mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-22 23:00:55 +00:00
feat: Make DynamicMPT opt-in-immutable
This commit is contained in:
committed by
Ayaz Salikhov
parent
bf65e5fa7b
commit
033dca2f0e
@@ -43,6 +43,7 @@
|
||||
#include <xrpl/protocol/IOUAmount.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/MPTAmount.h>
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
@@ -59,6 +60,7 @@
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/tx/transactors/token/MPTokenIssuanceSet.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
@@ -602,9 +604,9 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
|
||||
mptAlice.authorize({.account = bob, .holderCount = 1});
|
||||
|
||||
// test invalid flag - only valid flags are tfMPTLock (1) and Unlock
|
||||
// (2)
|
||||
mptAlice.set({.account = alice, .flags = 0x00000008, .err = temINVALID_FLAG});
|
||||
// test invalid flag - an unrecognized flag bit is always
|
||||
// rejected, regardless of which amendments are enabled
|
||||
mptAlice.set({.account = alice, .flags = 0x00001000, .err = temINVALID_FLAG});
|
||||
|
||||
if (!features[featureSingleAssetVault] && !features[featureDynamicMPT] &&
|
||||
!features[featureConfidentialTransfer])
|
||||
@@ -3393,26 +3395,26 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
using namespace test::jtx;
|
||||
Account const alice("alice");
|
||||
|
||||
// Can not provide MutableFlags when DynamicMPT amendment is not enabled
|
||||
// Can not provide ImmutableFlags when DynamicMPT amendment is not enabled
|
||||
{
|
||||
Env env{*this, features - featureDynamicMPT};
|
||||
MPTTester mptAlice(env, alice);
|
||||
mptAlice.create({.ownerCount = 0, .mutableFlags = 2, .err = temDISABLED});
|
||||
mptAlice.create({.ownerCount = 0, .mutableFlags = 0, .err = temDISABLED});
|
||||
mptAlice.create({.ownerCount = 0, .immutableFlags = 2, .err = temDISABLED});
|
||||
mptAlice.create({.ownerCount = 0, .immutableFlags = 0, .err = temDISABLED});
|
||||
}
|
||||
|
||||
// MutableFlags contains invalid values
|
||||
// ImmutableFlags contains invalid values
|
||||
{
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice);
|
||||
|
||||
// Value 1 is reserved for MPT lock.
|
||||
mptAlice.create({.ownerCount = 0, .mutableFlags = 1, .err = temINVALID_FLAG});
|
||||
mptAlice.create({.ownerCount = 0, .mutableFlags = 17, .err = temINVALID_FLAG});
|
||||
mptAlice.create({.ownerCount = 0, .mutableFlags = 65535, .err = temINVALID_FLAG});
|
||||
mptAlice.create({.ownerCount = 0, .immutableFlags = 1, .err = temINVALID_FLAG});
|
||||
mptAlice.create({.ownerCount = 0, .immutableFlags = 17, .err = temINVALID_FLAG});
|
||||
mptAlice.create({.ownerCount = 0, .immutableFlags = 65535, .err = temINVALID_FLAG});
|
||||
|
||||
// MutableFlags can not be 0
|
||||
mptAlice.create({.ownerCount = 0, .mutableFlags = 0, .err = temINVALID_FLAG});
|
||||
// ImmutableFlags can not be 0
|
||||
mptAlice.create({.ownerCount = 0, .immutableFlags = 0, .err = temINVALID_FLAG});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3425,16 +3427,16 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
Account const alice("alice");
|
||||
Account const bob("bob");
|
||||
|
||||
// Can not provide MutableFlags, MPTokenMetadata or TransferFee when
|
||||
// Can not provide mutate related flags, MPTokenMetadata or TransferFee when
|
||||
// DynamicMPT amendment is not enabled
|
||||
{
|
||||
Env env{*this, features - featureDynamicMPT};
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
auto const mptID = makeMptID(env.seq(alice), alice);
|
||||
|
||||
// MutableFlags is not allowed when DynamicMPT is not enabled
|
||||
mptAlice.set({.account = alice, .id = mptID, .mutableFlags = 2, .err = temDISABLED});
|
||||
mptAlice.set({.account = alice, .id = mptID, .mutableFlags = 0, .err = temDISABLED});
|
||||
// Mutate related flags is not allowed when DynamicMPT is not enabled
|
||||
mptAlice.set(
|
||||
{.account = alice, .id = mptID, .flags = tfMPTSetCanLock, .err = temDISABLED});
|
||||
|
||||
// MPTokenMetadata is not allowed when DynamicMPT is not enabled
|
||||
mptAlice.set({.account = alice, .id = mptID, .metadata = "test", .err = temDISABLED});
|
||||
@@ -3445,19 +3447,19 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
mptAlice.set({.account = alice, .id = mptID, .transferFee = 0, .err = temDISABLED});
|
||||
}
|
||||
|
||||
// Can not provide holder when MutableFlags, MPTokenMetadata or
|
||||
// Can not provide holder when mutate related flags, MPTokenMetadata or
|
||||
// TransferFee is present
|
||||
{
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
auto const mptID = makeMptID(env.seq(alice), alice);
|
||||
|
||||
// Holder is not allowed when MutableFlags is present
|
||||
// Holder is not allowed when mutate related flags is present
|
||||
mptAlice.set(
|
||||
{.account = alice,
|
||||
.holder = bob,
|
||||
.id = mptID,
|
||||
.mutableFlags = 2,
|
||||
.flags = tfMPTSetCanLock,
|
||||
.err = temMALFORMED});
|
||||
|
||||
// Holder is not allowed when MPTokenMetadata is present
|
||||
@@ -3477,27 +3479,24 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
.err = temMALFORMED});
|
||||
}
|
||||
|
||||
// Can not set Flags when MutableFlags, MPTokenMetadata or
|
||||
// Can not lock when mutate related flags, MPTokenMetadata or
|
||||
// TransferFee is present
|
||||
{
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
mptAlice.create(
|
||||
{.ownerCount = 1,
|
||||
.mutableFlags = tmfMPTCanMutateMetadata | tmfMPTCanEnableCanLock |
|
||||
tmfMPTCanMutateTransferFee});
|
||||
mptAlice.create({.ownerCount = 1});
|
||||
|
||||
// Setting flags is not allowed when MutableFlags is present
|
||||
// Lock is not allowed when mutate related flags is present
|
||||
mptAlice.set(
|
||||
{.account = alice, .flags = tfMPTCanLock, .mutableFlags = 2, .err = temMALFORMED});
|
||||
{.account = alice, .flags = tfMPTLock | tfMPTSetCanLock, .err = temMALFORMED});
|
||||
|
||||
// Setting flags is not allowed when MPTokenMetadata is present
|
||||
// Lock is not allowed when MPTokenMetadata is present
|
||||
mptAlice.set(
|
||||
{.account = alice, .flags = tfMPTCanLock, .metadata = "test", .err = temMALFORMED});
|
||||
{.account = alice, .flags = tfMPTLock, .metadata = "test", .err = temMALFORMED});
|
||||
|
||||
// setting flags is not allowed when TransferFee is present
|
||||
// Lock is not allowed when TransferFee is present
|
||||
mptAlice.set(
|
||||
{.account = alice, .flags = tfMPTCanLock, .transferFee = 100, .err = temMALFORMED});
|
||||
{.account = alice, .flags = tfMPTLock, .transferFee = 100, .err = temMALFORMED});
|
||||
}
|
||||
|
||||
// Flags being 0 or tfFullyCanonicalSig is fine
|
||||
@@ -3509,48 +3508,39 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
{.transferFee = 10,
|
||||
.ownerCount = 1,
|
||||
.flags = tfMPTCanTransfer,
|
||||
.mutableFlags = tmfMPTCanMutateTransferFee | tmfMPTCanMutateMetadata});
|
||||
.immutableFlags = tifMPTTransferFee});
|
||||
|
||||
mptAlice.set({.account = alice, .flags = 0, .transferFee = 100, .metadata = "test"});
|
||||
mptAlice.set(
|
||||
{.account = alice,
|
||||
.flags = tfFullyCanonicalSig,
|
||||
.transferFee = 200,
|
||||
.metadata = "test2"});
|
||||
mptAlice.set({.account = alice, .flags = 0, .metadata = "test"});
|
||||
mptAlice.set({.account = alice, .flags = tfFullyCanonicalSig, .metadata = "test2"});
|
||||
}
|
||||
|
||||
// Invalid MutableFlags
|
||||
// Invalid flags
|
||||
{
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
auto const mptID = makeMptID(env.seq(alice), alice);
|
||||
|
||||
for (auto const flags : {10000, 0, 5000})
|
||||
for (auto const flags : {0x0200u, 0x0800u, 0x2000u, 0x0201u})
|
||||
{
|
||||
mptAlice.set(
|
||||
{.account = alice, .id = mptID, .mutableFlags = flags, .err = temINVALID_FLAG});
|
||||
{.account = alice, .id = mptID, .flags = flags, .err = temINVALID_FLAG});
|
||||
}
|
||||
}
|
||||
|
||||
// Can not mutate flag which is not mutable
|
||||
// Can not set flag which is immutable
|
||||
{
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
|
||||
mptAlice.create({.ownerCount = 1});
|
||||
mptAlice.create(
|
||||
{.ownerCount = 1,
|
||||
.immutableFlags = tifMPTCanLock | tifMPTCanTrade | tifMPTCanTransfer |
|
||||
tifMPTCanClawback | tifMPTCanEscrow | tifMPTRequireAuth |
|
||||
tifMPTCanHoldConfidentialBalance});
|
||||
|
||||
auto const mutableFlags = {
|
||||
tmfMPTSetCanLock,
|
||||
tmfMPTSetRequireAuth,
|
||||
tmfMPTSetCanEscrow,
|
||||
tmfMPTSetCanTrade,
|
||||
tmfMPTSetCanTransfer,
|
||||
tmfMPTSetCanClawback};
|
||||
|
||||
for (auto const& mutableFlag : mutableFlags)
|
||||
for (auto const& f : MPTokenIssuanceSet::flagMapping)
|
||||
{
|
||||
mptAlice.set(
|
||||
{.account = alice, .mutableFlags = mutableFlag, .err = tecNO_PERMISSION});
|
||||
mptAlice.set({.account = alice, .flags = f.setFlag, .err = tecNO_PERMISSION});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3559,18 +3549,18 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
|
||||
mptAlice.create({.ownerCount = 1, .mutableFlags = tmfMPTCanMutateMetadata});
|
||||
mptAlice.create({.ownerCount = 1});
|
||||
|
||||
std::string const metadata(kMaxMpTokenMetadataLength + 1, 'a');
|
||||
mptAlice.set({.account = alice, .metadata = metadata, .err = temMALFORMED});
|
||||
}
|
||||
|
||||
// Can not mutate metadata when it is not mutable
|
||||
// Can not set metadata when it is immutable
|
||||
{
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
|
||||
mptAlice.create({.ownerCount = 1});
|
||||
mptAlice.create({.ownerCount = 1, .immutableFlags = tifMPTMetadata});
|
||||
mptAlice.set({.account = alice, .metadata = "test", .err = tecNO_PERMISSION});
|
||||
}
|
||||
|
||||
@@ -3580,7 +3570,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
auto const mptID = makeMptID(env.seq(alice), alice);
|
||||
|
||||
mptAlice.create({.ownerCount = 1, .mutableFlags = tmfMPTCanMutateTransferFee});
|
||||
mptAlice.create({.ownerCount = 1});
|
||||
|
||||
mptAlice.set(
|
||||
{.account = alice,
|
||||
@@ -3594,83 +3584,70 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
|
||||
mptAlice.create(
|
||||
{.ownerCount = 1,
|
||||
.mutableFlags = tmfMPTCanMutateTransferFee | tmfMPTCanEnableCanTransfer});
|
||||
mptAlice.create({.ownerCount = 1});
|
||||
|
||||
// MPTCanTransfer is not set, return tecNO_PERMISSION
|
||||
mptAlice.set({.account = alice, .transferFee = 100, .err = tecNO_PERMISSION});
|
||||
|
||||
// Can not set transfer fee even when trying to set MPTCanTransfer
|
||||
// at the same time. MPTCanTransfer must be set first, then transfer
|
||||
// fee can be set in a separate transaction.
|
||||
mptAlice.set(
|
||||
{.account = alice,
|
||||
.mutableFlags = tmfMPTSetCanTransfer,
|
||||
.transferFee = 100,
|
||||
.err = tecNO_PERMISSION});
|
||||
// Setting a non-zero transfer fee is fine if MPTCanTransfer is
|
||||
// being enabled in the same transaction
|
||||
mptAlice.set({.account = alice, .flags = tfMPTSetCanTransfer, .transferFee = 100});
|
||||
BEAST_EXPECT(mptAlice.checkFlags(lsfMPTCanTransfer));
|
||||
BEAST_EXPECT(mptAlice.checkTransferFee(100));
|
||||
}
|
||||
|
||||
// Can not mutate transfer fee when it is not mutable
|
||||
// Can not set transfer fee when it is immutable
|
||||
{
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
|
||||
mptAlice.create({.transferFee = 10, .ownerCount = 1, .flags = tfMPTCanTransfer});
|
||||
mptAlice.create(
|
||||
{.transferFee = 10,
|
||||
.ownerCount = 1,
|
||||
.flags = tfMPTCanTransfer,
|
||||
.immutableFlags = tifMPTTransferFee});
|
||||
|
||||
mptAlice.set({.account = alice, .transferFee = 100, .err = tecNO_PERMISSION});
|
||||
|
||||
mptAlice.set({.account = alice, .transferFee = 0, .err = tecNO_PERMISSION});
|
||||
}
|
||||
|
||||
// Set some flags mutable. Can not mutate the others
|
||||
// Set some flags immutable. Others can still be set.
|
||||
{
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
|
||||
mptAlice.create(
|
||||
{.ownerCount = 1,
|
||||
.mutableFlags = tmfMPTCanEnableCanTrade | tmfMPTCanEnableCanTransfer |
|
||||
tmfMPTCanMutateMetadata});
|
||||
.immutableFlags = tifMPTCanTrade | tifMPTCanTransfer | tifMPTMetadata});
|
||||
|
||||
// Can not mutate transfer fee
|
||||
mptAlice.set({.account = alice, .transferFee = 100, .err = tecNO_PERMISSION});
|
||||
auto const canEnableFlags = {
|
||||
tfMPTSetCanLock, tfMPTSetRequireAuth, tfMPTSetCanEscrow, tfMPTSetCanClawback};
|
||||
|
||||
auto const invalidFlags = {
|
||||
tmfMPTSetCanLock, tmfMPTSetRequireAuth, tmfMPTSetCanEscrow, tmfMPTSetCanClawback};
|
||||
// Can not enable immutable flags
|
||||
mptAlice.set({.account = alice, .flags = tfMPTSetCanTrade, .err = tecNO_PERMISSION});
|
||||
mptAlice.set({.account = alice, .flags = tfMPTSetCanTransfer, .err = tecNO_PERMISSION});
|
||||
|
||||
// Can not mutate flags which are not mutable
|
||||
for (auto const& mutableFlag : invalidFlags)
|
||||
// Can enable flags which are not immutable
|
||||
for (auto const& mutableFlag : canEnableFlags)
|
||||
{
|
||||
mptAlice.set(
|
||||
{.account = alice, .mutableFlags = mutableFlag, .err = tecNO_PERMISSION});
|
||||
mptAlice.set({.account = alice, .flags = mutableFlag});
|
||||
}
|
||||
|
||||
// Can mutate MPTCanTrade
|
||||
mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanTrade});
|
||||
|
||||
// Can mutate MPTCanTransfer
|
||||
mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanTransfer});
|
||||
|
||||
// Can mutate metadata
|
||||
mptAlice.set({.account = alice, .metadata = "test"});
|
||||
mptAlice.set({.account = alice, .metadata = ""});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testMutateMPT(FeatureBitset features)
|
||||
testSetMPT(FeatureBitset features)
|
||||
{
|
||||
testcase("Mutate MPT");
|
||||
testcase("Set MPT");
|
||||
using namespace test::jtx;
|
||||
|
||||
Account const alice("alice");
|
||||
|
||||
// Mutate metadata
|
||||
// Set metadata
|
||||
{
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice);
|
||||
mptAlice.create(
|
||||
{.metadata = "test", .ownerCount = 1, .mutableFlags = tmfMPTCanMutateMetadata});
|
||||
mptAlice.create({.metadata = "test", .ownerCount = 1});
|
||||
|
||||
std::vector<std::string> const metadatas = {
|
||||
"mutate metadata",
|
||||
@@ -3691,7 +3668,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
BEAST_EXPECT(!mptAlice.isMetadataPresent());
|
||||
}
|
||||
|
||||
// Mutate transfer fee
|
||||
// Set transfer fee
|
||||
{
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice);
|
||||
@@ -3699,8 +3676,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
{.transferFee = 100,
|
||||
.metadata = "test",
|
||||
.ownerCount = 1,
|
||||
.flags = tfMPTCanTransfer,
|
||||
.mutableFlags = tmfMPTCanMutateTransferFee});
|
||||
.flags = tfMPTCanTransfer});
|
||||
|
||||
for (std::uint16_t const fee :
|
||||
std::initializer_list<std::uint16_t>{1, 10, 100, 200, 500, 1000, kMaxTransferFee})
|
||||
@@ -3718,33 +3694,29 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
BEAST_EXPECT(mptAlice.checkTransferFee(10));
|
||||
}
|
||||
|
||||
// Test mutable flag enablement
|
||||
// Test setting flags
|
||||
{
|
||||
auto testFlagSet = [&](std::uint32_t createFlags, std::uint32_t setFlags) {
|
||||
auto testFlagSet = [&](std::uint32_t setFlags) {
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice);
|
||||
|
||||
// Create the MPT object with the specified initial flags
|
||||
mptAlice.create({.metadata = "test", .ownerCount = 1, .mutableFlags = createFlags});
|
||||
// Create issuance and the flags can be enabled once by default.
|
||||
mptAlice.create({.metadata = "test", .ownerCount = 1});
|
||||
|
||||
// Setting the same mutable capability more than once is harmless.
|
||||
mptAlice.set({.account = alice, .mutableFlags = setFlags});
|
||||
mptAlice.set({.account = alice, .mutableFlags = setFlags});
|
||||
// Setting the same immutable flag more than once is harmless.
|
||||
mptAlice.set({.account = alice, .flags = setFlags});
|
||||
mptAlice.set({.account = alice, .flags = setFlags});
|
||||
};
|
||||
|
||||
testFlagSet(tmfMPTCanEnableCanLock, tmfMPTSetCanLock);
|
||||
testFlagSet(tmfMPTCanEnableRequireAuth, tmfMPTSetRequireAuth);
|
||||
testFlagSet(tmfMPTCanEnableCanEscrow, tmfMPTSetCanEscrow);
|
||||
testFlagSet(tmfMPTCanEnableCanTrade, tmfMPTSetCanTrade);
|
||||
testFlagSet(tmfMPTCanEnableCanTransfer, tmfMPTSetCanTransfer);
|
||||
testFlagSet(tmfMPTCanEnableCanClawback, tmfMPTSetCanClawback);
|
||||
for (auto const& f : MPTokenIssuanceSet::flagMapping)
|
||||
testFlagSet(f.setFlag);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testMutateCanLock(FeatureBitset features)
|
||||
testSetCanLock(FeatureBitset features)
|
||||
{
|
||||
testcase("Mutate MPTCanLock");
|
||||
testcase("Set MPTCanLock");
|
||||
using namespace test::jtx;
|
||||
|
||||
Account const alice("alice");
|
||||
@@ -3754,78 +3726,41 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
{
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
mptAlice.create(
|
||||
{.ownerCount = 1,
|
||||
.holderCount = 0,
|
||||
.flags = tfMPTCanLock | tfMPTCanTransfer,
|
||||
.mutableFlags = tmfMPTCanEnableCanLock | tmfMPTCanEnableCanTrade |
|
||||
tmfMPTCanMutateTransferFee});
|
||||
mptAlice.create({.ownerCount = 1, .holderCount = 0});
|
||||
mptAlice.authorize({.account = bob, .holderCount = 1});
|
||||
|
||||
// Lock bob's mptoken
|
||||
mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock});
|
||||
// Lock bob's mptoken fails because alice has not enabled MPTCanLock
|
||||
mptAlice.set(
|
||||
{.account = alice, .holder = bob, .flags = tfMPTLock, .err = tecNO_PERMISSION});
|
||||
|
||||
// Can mutate the mutable flags and fields
|
||||
mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanLock});
|
||||
mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanTrade});
|
||||
mptAlice.set({.account = alice, .transferFee = 200});
|
||||
// set CanLock
|
||||
mptAlice.set({.account = alice, .flags = tfMPTSetCanLock});
|
||||
|
||||
// Now can lock
|
||||
mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock});
|
||||
}
|
||||
|
||||
// Global lock
|
||||
{
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
mptAlice.create(
|
||||
{.ownerCount = 1,
|
||||
.holderCount = 0,
|
||||
.flags = tfMPTCanLock,
|
||||
.mutableFlags = tmfMPTCanEnableCanLock | tmfMPTCanEnableCanClawback |
|
||||
tmfMPTCanMutateMetadata});
|
||||
mptAlice.create({.ownerCount = 1, .holderCount = 0});
|
||||
mptAlice.authorize({.account = bob, .holderCount = 1});
|
||||
|
||||
// Lock issuance
|
||||
mptAlice.set({.account = alice, .flags = tfMPTLock});
|
||||
|
||||
// Can mutate the mutable flags and fields
|
||||
mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanLock});
|
||||
mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanClawback});
|
||||
mptAlice.set({.account = alice, .metadata = "mutate"});
|
||||
}
|
||||
|
||||
// Test lock and unlock after enabling MPTCanLock
|
||||
{
|
||||
Env env{*this, features};
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
mptAlice.create(
|
||||
{.ownerCount = 1,
|
||||
.holderCount = 0,
|
||||
.mutableFlags = tmfMPTCanEnableCanLock | tmfMPTCanEnableCanClawback |
|
||||
tmfMPTCanMutateMetadata});
|
||||
mptAlice.authorize({.account = bob, .holderCount = 1});
|
||||
|
||||
// Can not lock or unlock before MPTCanLock is enabled
|
||||
// Lock issuance fails because alice has not enabled MPTCanLock
|
||||
mptAlice.set({.account = alice, .flags = tfMPTLock, .err = tecNO_PERMISSION});
|
||||
mptAlice.set({.account = alice, .flags = tfMPTUnlock, .err = tecNO_PERMISSION});
|
||||
mptAlice.set(
|
||||
{.account = alice, .holder = bob, .flags = tfMPTLock, .err = tecNO_PERMISSION});
|
||||
mptAlice.set(
|
||||
{.account = alice, .holder = bob, .flags = tfMPTUnlock, .err = tecNO_PERMISSION});
|
||||
|
||||
// Set MPTCanLock
|
||||
mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanLock});
|
||||
|
||||
// Can lock and unlock
|
||||
// Set CanLock
|
||||
mptAlice.set({.account = alice, .flags = tfMPTSetCanLock});
|
||||
// Now can lock
|
||||
mptAlice.set({.account = alice, .flags = tfMPTLock});
|
||||
mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock});
|
||||
mptAlice.set({.account = alice, .flags = tfMPTUnlock});
|
||||
mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testMutateRequireAuth(FeatureBitset features)
|
||||
testSetRequireAuth(FeatureBitset features)
|
||||
{
|
||||
testcase("Mutate MPTRequireAuth");
|
||||
testcase("Set MPTRequireAuth");
|
||||
using namespace test::jtx;
|
||||
|
||||
// test enabling RequireAuth flag on the issuance and its effect on payment
|
||||
@@ -3835,16 +3770,13 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
Account const bob("bob");
|
||||
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
mptAlice.create(
|
||||
{.ownerCount = 1,
|
||||
.flags = tfMPTCanTransfer,
|
||||
.mutableFlags = tmfMPTCanEnableRequireAuth});
|
||||
mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer});
|
||||
|
||||
mptAlice.authorize({.account = bob});
|
||||
mptAlice.pay(alice, bob, 1000);
|
||||
|
||||
// Set RequireAuth because it is mutable.
|
||||
mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetRequireAuth});
|
||||
// Set RequireAuth
|
||||
mptAlice.set({.account = alice, .flags = tfMPTSetRequireAuth});
|
||||
|
||||
// This should fail because bob is not authorized yet.
|
||||
mptAlice.pay(alice, bob, 1000, tecNO_AUTH);
|
||||
@@ -3855,9 +3787,9 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
}
|
||||
|
||||
void
|
||||
testMutateCanEscrow(FeatureBitset features)
|
||||
testSetCanEscrow(FeatureBitset features)
|
||||
{
|
||||
testcase("Mutate MPTCanEscrow");
|
||||
testcase("Set MPTCanEscrow");
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
|
||||
@@ -3868,11 +3800,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
auto const carol = Account("carol");
|
||||
|
||||
MPTTester mptAlice(env, alice, {.holders = {carol, bob}});
|
||||
mptAlice.create(
|
||||
{.ownerCount = 1,
|
||||
.holderCount = 0,
|
||||
.flags = tfMPTCanTransfer,
|
||||
.mutableFlags = tmfMPTCanEnableCanEscrow});
|
||||
mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer});
|
||||
mptAlice.authorize({.account = carol});
|
||||
mptAlice.authorize({.account = bob});
|
||||
|
||||
@@ -3888,8 +3816,8 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
Fee(baseFee * 150),
|
||||
Ter(tecNO_PERMISSION));
|
||||
|
||||
// MPTCanEscrow is enabled now
|
||||
mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanEscrow});
|
||||
// Set MPTCanEscrow
|
||||
mptAlice.set({.account = alice, .flags = tfMPTSetCanEscrow});
|
||||
env(escrow::create(carol, bob, mpt(3)),
|
||||
escrow::kCondition(escrow::kCb1),
|
||||
escrow::kFinishTime(env.now() + 1s),
|
||||
@@ -3897,9 +3825,9 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
}
|
||||
|
||||
void
|
||||
testMutateCanTransfer(FeatureBitset features)
|
||||
testSetCanTransfer(FeatureBitset features)
|
||||
{
|
||||
testcase("Mutate MPTCanTransfer");
|
||||
testcase("Set MPTCanTransfer");
|
||||
|
||||
using namespace test::jtx;
|
||||
Account const alice("alice");
|
||||
@@ -3910,9 +3838,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
Env env{*this, features};
|
||||
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
|
||||
mptAlice.create(
|
||||
{.ownerCount = 1,
|
||||
.mutableFlags = tmfMPTCanEnableCanTransfer | tmfMPTCanMutateTransferFee});
|
||||
mptAlice.create({.ownerCount = 1});
|
||||
|
||||
mptAlice.authorize({.account = bob});
|
||||
mptAlice.authorize({.account = carol});
|
||||
@@ -3926,20 +3852,10 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
// Can not set non-zero transfer fee when MPTCanTransfer is not set
|
||||
mptAlice.set({.account = alice, .transferFee = 100, .err = tecNO_PERMISSION});
|
||||
|
||||
// Can not set non-zero transfer fee even when trying to set
|
||||
// MPTCanTransfer at the same time
|
||||
mptAlice.set(
|
||||
{.account = alice,
|
||||
.mutableFlags = tmfMPTSetCanTransfer,
|
||||
.transferFee = 100,
|
||||
.err = tecNO_PERMISSION});
|
||||
|
||||
// Alice sets MPTCanTransfer
|
||||
mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanTransfer});
|
||||
|
||||
// Can set transfer fee now
|
||||
// Set MPTCanTransfer
|
||||
BEAST_EXPECT(!mptAlice.isTransferFeePresent());
|
||||
mptAlice.set({.account = alice, .transferFee = 100});
|
||||
mptAlice.set({.account = alice, .flags = tfMPTSetCanTransfer, .transferFee = 100});
|
||||
BEAST_EXPECT(mptAlice.checkFlags(lsfMPTCanTransfer));
|
||||
BEAST_EXPECT(mptAlice.isTransferFeePresent());
|
||||
|
||||
// Bob can pay carol
|
||||
@@ -3958,16 +3874,13 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
}
|
||||
}
|
||||
|
||||
// Can set transfer fee to zero when tmfMPTCanMutateTransferFee is set.
|
||||
// Can set transfer fee to zero when transfer fee is mutable (i.e.
|
||||
// tifMPTTransferFee is not set).
|
||||
{
|
||||
Env env{*this, features};
|
||||
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
|
||||
mptAlice.create(
|
||||
{.transferFee = 100,
|
||||
.ownerCount = 1,
|
||||
.flags = tfMPTCanTransfer,
|
||||
.mutableFlags = tmfMPTCanMutateTransferFee});
|
||||
mptAlice.create({.transferFee = 100, .ownerCount = 1, .flags = tfMPTCanTransfer});
|
||||
|
||||
BEAST_EXPECT(mptAlice.checkTransferFee(100));
|
||||
|
||||
@@ -3978,9 +3891,9 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
}
|
||||
|
||||
void
|
||||
testMutateCanClawback(FeatureBitset features)
|
||||
testSetCanClawback(FeatureBitset features)
|
||||
{
|
||||
testcase("Mutate MPTCanClawback");
|
||||
testcase("Set MPTCanClawback");
|
||||
|
||||
using namespace test::jtx;
|
||||
Env env(*this, features);
|
||||
@@ -3989,8 +3902,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
|
||||
mptAlice.create(
|
||||
{.ownerCount = 1, .holderCount = 0, .mutableFlags = tmfMPTCanEnableCanClawback});
|
||||
mptAlice.create({.ownerCount = 1, .holderCount = 0});
|
||||
|
||||
// Bob creates an MPToken
|
||||
mptAlice.authorize({.account = bob});
|
||||
@@ -4001,13 +3913,117 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
// MPTCanClawback is not enabled
|
||||
mptAlice.claw(alice, bob, 1, tecNO_PERMISSION);
|
||||
|
||||
// Enable MPTCanClawback
|
||||
mptAlice.set({.account = alice, .mutableFlags = tmfMPTSetCanClawback});
|
||||
// Set MPTCanClawback
|
||||
mptAlice.set({.account = alice, .flags = tfMPTSetCanClawback});
|
||||
|
||||
// Can clawback now
|
||||
mptAlice.claw(alice, bob, 1);
|
||||
}
|
||||
|
||||
void
|
||||
testSetImmutableFlags(FeatureBitset features)
|
||||
{
|
||||
testcase("Set MPT ImmutableFlags via MPTokenIssuanceSet");
|
||||
|
||||
using namespace test::jtx;
|
||||
Account const alice{"alice"};
|
||||
Account const bob{"bob"};
|
||||
|
||||
// ImmutableFlags requires featureDynamicMPT.
|
||||
{
|
||||
Env env(*this, features - featureDynamicMPT);
|
||||
MPTTester mptAlice(env, alice);
|
||||
mptAlice.create({.ownerCount = 1});
|
||||
|
||||
mptAlice.set(
|
||||
{.account = alice, .immutableFlags = tifMPTCanClawback, .err = temDISABLED});
|
||||
}
|
||||
|
||||
// ImmutableFlags containing tifMPTCanHoldConfidentialBalance requires
|
||||
// featureConfidentialTransfer.
|
||||
{
|
||||
Env env(*this, features - featureConfidentialTransfer);
|
||||
MPTTester mptAlice(env, alice);
|
||||
mptAlice.create({.ownerCount = 1});
|
||||
|
||||
mptAlice.set(
|
||||
{.account = alice,
|
||||
.immutableFlags = tifMPTCanHoldConfidentialBalance,
|
||||
.err = temDISABLED});
|
||||
}
|
||||
|
||||
// ImmutableFlags of 0, or containing unknown bits, is rejected.
|
||||
{
|
||||
Env env(*this, features);
|
||||
MPTTester mptAlice(env, alice);
|
||||
mptAlice.create({.ownerCount = 1});
|
||||
|
||||
mptAlice.set({.account = alice, .immutableFlags = 0, .err = temINVALID_FLAG});
|
||||
mptAlice.set({.account = alice, .immutableFlags = 1, .err = temINVALID_FLAG});
|
||||
}
|
||||
|
||||
// Holder is not allowed alongside ImmutableFlags, and ImmutableFlags
|
||||
// can not be combined with Lock/Unlock in the same transaction.
|
||||
{
|
||||
Env env(*this, features);
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
mptAlice.create({.ownerCount = 1});
|
||||
|
||||
mptAlice.set(
|
||||
{.account = alice,
|
||||
.holder = bob,
|
||||
.immutableFlags = tifMPTCanClawback,
|
||||
.err = temMALFORMED});
|
||||
|
||||
mptAlice.set(
|
||||
{.account = alice,
|
||||
.flags = tfMPTLock,
|
||||
.immutableFlags = tifMPTCanClawback,
|
||||
.err = temMALFORMED});
|
||||
}
|
||||
|
||||
// Can sets ImmutableFlags and the capability flags in the same transaction
|
||||
{
|
||||
Env env(*this, features);
|
||||
MPTTester mptAlice(env, alice);
|
||||
mptAlice.create({.ownerCount = 1});
|
||||
|
||||
mptAlice.set(
|
||||
{.account = alice,
|
||||
.flags = tfMPTSetCanClawback,
|
||||
.immutableFlags = tifMPTCanClawback});
|
||||
|
||||
mptAlice.set(
|
||||
{.account = alice,
|
||||
.flags = tfMPTSetCanTransfer | tfMPTSetRequireAuth,
|
||||
.immutableFlags = tifMPTCanTrade});
|
||||
}
|
||||
|
||||
// Setting ImmutableFlags persists to the ledger, permanently blocks
|
||||
// enabling the corresponding capability, and merges (rather than
|
||||
// overwrites) across multiple transactions.
|
||||
{
|
||||
Env env(*this, features);
|
||||
MPTTester mptAlice(env, alice);
|
||||
mptAlice.create({.ownerCount = 1});
|
||||
|
||||
mptAlice.set({.account = alice, .immutableFlags = tifMPTCanClawback});
|
||||
BEAST_EXPECT(mptAlice.checkImmutableFlags(tifMPTCanClawback));
|
||||
|
||||
// The CanClawback can no longer be enabled.
|
||||
mptAlice.set({.account = alice, .flags = tfMPTSetCanClawback, .err = tecNO_PERMISSION});
|
||||
|
||||
// A distinct bit merges with the first rather than overwriting it.
|
||||
// Both CanClawback and CanTrade are now immutable.
|
||||
mptAlice.set({.account = alice, .immutableFlags = tifMPTCanTrade});
|
||||
BEAST_EXPECT(mptAlice.checkImmutableFlags(tifMPTCanClawback | tifMPTCanTrade));
|
||||
|
||||
// Setting the same bit again is a harmless no-op.
|
||||
mptAlice.set({.account = alice, .immutableFlags = tifMPTCanClawback});
|
||||
BEAST_EXPECT(mptAlice.checkImmutableFlags(tifMPTCanClawback | tifMPTCanTrade));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testMultiSendMaximumAmount(FeatureBitset features)
|
||||
{
|
||||
@@ -4398,14 +4414,14 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
.holders = {alice, carol},
|
||||
.pay = 100,
|
||||
.flags = tfMPTCanTransfer,
|
||||
.mutableFlags = tmfMPTCanEnableCanTrade});
|
||||
.immutableFlags = tifMPTCanTrade});
|
||||
MPTTester const eth(
|
||||
{.env = env,
|
||||
.issuer = gw,
|
||||
.holders = {alice, carol},
|
||||
.pay = 100,
|
||||
.flags = tfMPTCanTrade,
|
||||
.mutableFlags = tmfMPTCanEnableCanTrade});
|
||||
.immutableFlags = tifMPTCanTrade});
|
||||
|
||||
// Can't create
|
||||
env(offer(gw, eth(10), btc(10)), Ter(tecNO_PERMISSION));
|
||||
@@ -4641,30 +4657,25 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
.issuer = gw,
|
||||
.holders = {alice, carol, bob},
|
||||
.pay = 1'000,
|
||||
.flags = tfMPTCanLock | kMptDexFlags,
|
||||
.mutableFlags = tmfMPTCanEnableRequireAuth | tmfMPTCanEnableCanTrade |
|
||||
tmfMPTCanEnableCanTransfer});
|
||||
.flags = tfMPTCanLock | kMptDexFlags});
|
||||
MPTTester eth(
|
||||
{.env = env,
|
||||
.issuer = gw,
|
||||
.holders = {alice, carol, bob},
|
||||
.pay = 1'000,
|
||||
.flags = tfMPTCanLock | kMptDexFlags,
|
||||
.mutableFlags = tmfMPTCanEnableCanTransfer});
|
||||
.flags = tfMPTCanLock | kMptDexFlags});
|
||||
MPTTester const usd(
|
||||
{.env = env,
|
||||
.issuer = gw,
|
||||
.holders = {alice, carol, bob},
|
||||
.pay = 1'000,
|
||||
.flags = kMptDexFlags | tfMPTCanLock,
|
||||
.mutableFlags = tmfMPTCanEnableCanTransfer});
|
||||
.flags = kMptDexFlags | tfMPTCanLock});
|
||||
MPTTester const cad(
|
||||
{.env = env,
|
||||
.issuer = gw,
|
||||
.holders = {alice, carol, bob},
|
||||
.pay = 1'000,
|
||||
.flags = kMptDexFlags | tfMPTCanLock,
|
||||
.mutableFlags = tmfMPTCanEnableCanTransfer});
|
||||
.flags = kMptDexFlags | tfMPTCanLock});
|
||||
|
||||
env(offer(bob, eth(1'000), btc(1'000)), Txflags(tfPassive));
|
||||
env.close();
|
||||
@@ -4694,7 +4705,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
env(pay(gw, ed, eth(100)));
|
||||
env(pay(gw, ed, btc(100)));
|
||||
env.close();
|
||||
btc.set({.mutableFlags = tmfMPTSetRequireAuth});
|
||||
btc.set({.flags = tfMPTSetRequireAuth});
|
||||
// authorize bob to enable the offers trading
|
||||
btc.authorize({.account = gw, .holder = bob});
|
||||
env.close();
|
||||
@@ -4932,8 +4943,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
.issuer = gw,
|
||||
.holders = {alice, carol, bob},
|
||||
.pay = 1'000,
|
||||
.flags = tfMPTCanTransfer,
|
||||
.mutableFlags = tmfMPTCanEnableCanTrade});
|
||||
.flags = tfMPTCanTransfer});
|
||||
MPTTester const eth(
|
||||
{.env = env,
|
||||
.issuer = gw,
|
||||
@@ -4952,7 +4962,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
env.close();
|
||||
|
||||
// Enable MPTCanTrade so BTC can be crossed through offers.
|
||||
btc.set({.mutableFlags = tmfMPTSetCanTrade});
|
||||
btc.set({.flags = tfMPTSetCanTrade});
|
||||
env(offer(bob, XRP(1), btc(1)));
|
||||
env(offer(bob, btc(1), eth(1)));
|
||||
env(offer(bob, eth(1), usd(1)));
|
||||
@@ -6753,11 +6763,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
env.close();
|
||||
|
||||
MPTTester mpt(
|
||||
{.env = env,
|
||||
.issuer = gw,
|
||||
.holders = {alice, carol},
|
||||
.flags = tfMPTCanTrade,
|
||||
.mutableFlags = tmfMPTCanEnableCanTransfer});
|
||||
{.env = env, .issuer = gw, .holders = {alice, carol}, .flags = tfMPTCanTrade});
|
||||
|
||||
// src is issuer
|
||||
uint256 checkId{keylet::check(gw, env.seq(gw)).key};
|
||||
@@ -6793,7 +6799,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
env.close();
|
||||
|
||||
// can create now
|
||||
mpt.set({.account = gw, .mutableFlags = tmfMPTSetCanTransfer});
|
||||
mpt.set({.account = gw, .flags = tfMPTSetCanTransfer});
|
||||
checkId = keylet::check(alice, env.seq(alice)).key;
|
||||
env(check::create(alice, carol, mpt(100)));
|
||||
env.close();
|
||||
@@ -7223,37 +7229,26 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
auto const txfee = Fee(drops(increment));
|
||||
auto const badMPT = MPT(gw, 1'000);
|
||||
|
||||
auto const makeMPT = [&](std::uint32_t const flags,
|
||||
Holders holders = {},
|
||||
std::uint64_t const pay = 0,
|
||||
std::optional<std::uint32_t> const mutableFlags =
|
||||
std::nullopt) {
|
||||
return MPTTester(
|
||||
{.env = env,
|
||||
.issuer = gw,
|
||||
.holders = holders,
|
||||
.pay = pay ? std::optional<std::uint64_t>{pay} : std::nullopt,
|
||||
.flags = flags,
|
||||
.mutableFlags = mutableFlags});
|
||||
};
|
||||
auto const makeMPT =
|
||||
[&](std::uint32_t const flags, Holders holders = {}, std::uint64_t const pay = 0) {
|
||||
return MPTTester(
|
||||
{.env = env,
|
||||
.issuer = gw,
|
||||
.holders = holders,
|
||||
.pay = pay ? std::optional<std::uint64_t>{pay} : std::nullopt,
|
||||
.flags = flags});
|
||||
};
|
||||
|
||||
auto const makeDexMPT = [&](Holders holders = {}, std::uint64_t const pay = 0) {
|
||||
return makeMPT(
|
||||
tfMPTCanLock | kMptDexFlags,
|
||||
holders,
|
||||
pay,
|
||||
tmfMPTCanEnableRequireAuth | tmfMPTCanEnableCanTransfer |
|
||||
tmfMPTCanEnableCanTrade);
|
||||
return makeMPT(tfMPTCanLock | kMptDexFlags, holders, pay);
|
||||
};
|
||||
|
||||
auto const makeNoTransferMPT = [&](Holders holders = {}, std::uint64_t const pay = 0) {
|
||||
return makeMPT(
|
||||
tfMPTCanLock | tfMPTCanTrade, holders, pay, tmfMPTCanEnableCanTransfer);
|
||||
return makeMPT(tfMPTCanLock | tfMPTCanTrade, holders, pay);
|
||||
};
|
||||
|
||||
auto const makeNoTradeMPT = [&](Holders holders = {}, std::uint64_t const pay = 0) {
|
||||
return makeMPT(
|
||||
tfMPTCanLock | tfMPTCanTransfer, holders, pay, tmfMPTCanEnableCanTrade);
|
||||
return makeMPT(tfMPTCanLock | tfMPTCanTransfer, holders, pay);
|
||||
};
|
||||
|
||||
// AMMCreate
|
||||
@@ -7299,7 +7294,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
// MPTRequireAuth is set
|
||||
// alice is not authorized
|
||||
usd.set({.flags = tfMPTUnlock});
|
||||
usd.set({.mutableFlags = tmfMPTSetRequireAuth});
|
||||
usd.set({.flags = tfMPTSetRequireAuth});
|
||||
createFail(usd, alice, tecNO_AUTH);
|
||||
// issuer can create
|
||||
createDeleteAMM(usd, gw);
|
||||
@@ -7316,7 +7311,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
createFail(usd2, alice, tecNO_AUTH);
|
||||
// issuer can create
|
||||
createDeleteAMM(usd2, gw);
|
||||
usd2.set({.mutableFlags = tmfMPTSetCanTransfer});
|
||||
usd2.set({.flags = tfMPTSetCanTransfer});
|
||||
// alice can create
|
||||
createDeleteAMM(usd2, alice);
|
||||
}
|
||||
@@ -7328,7 +7323,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
// alice and issuer can't create
|
||||
createFail(usd3, alice, tecNO_PERMISSION);
|
||||
createFail(usd3, gw, tecNO_PERMISSION);
|
||||
usd3.set({.mutableFlags = tmfMPTSetCanTrade});
|
||||
usd3.set({.flags = tfMPTSetCanTrade});
|
||||
// alice can create
|
||||
createDeleteAMM(usd3, alice);
|
||||
}
|
||||
@@ -7383,7 +7378,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
|
||||
// MPTRequireAuth is set
|
||||
// carol is not authorized by the issuer
|
||||
usd.set({.mutableFlags = tmfMPTSetRequireAuth});
|
||||
usd.set({.flags = tfMPTSetRequireAuth});
|
||||
env.close();
|
||||
amm.deposit(
|
||||
{.account = carol,
|
||||
@@ -7429,7 +7424,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
.err = Ter(tecNO_AUTH)});
|
||||
// issuer can deposit
|
||||
amm2.deposit({.account = gw, .tokens = 1'000});
|
||||
usd2.set({.mutableFlags = tmfMPTSetCanTransfer});
|
||||
usd2.set({.flags = tfMPTSetCanTransfer});
|
||||
// carol can deposit
|
||||
amm2.deposit({.account = carol, .tokens = 1'000});
|
||||
}
|
||||
@@ -7499,7 +7494,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
usd.set({.flags = tfMPTUnlock});
|
||||
|
||||
// MPTRequireAuth is set
|
||||
usd.set({.mutableFlags = tmfMPTSetRequireAuth});
|
||||
usd.set({.flags = tfMPTSetRequireAuth});
|
||||
usd.authorize({.account = gw, .holder = carol, .flags = tfMPTUnauthorize});
|
||||
// carol can't withdraw
|
||||
amm.withdraw(
|
||||
@@ -7543,7 +7538,7 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
usd2.authorize({.account = bob, .flags = tfMPTUnauthorize});
|
||||
// Can redeem
|
||||
env(pay(carol, gw, usd2(1)));
|
||||
usd2.set({.mutableFlags = tmfMPTSetCanTransfer});
|
||||
usd2.set({.flags = tfMPTSetCanTransfer});
|
||||
// carol can withdraw
|
||||
amm2.withdraw({.account = carol, .asset1Out = usd2(1), .asset2Out = eur(1)});
|
||||
}
|
||||
@@ -7739,13 +7734,14 @@ public:
|
||||
// Dynamic MPT
|
||||
testInvalidCreateDynamic(all);
|
||||
testInvalidSetDynamic(all);
|
||||
testMutateMPT(all);
|
||||
testMutateCanLock(all);
|
||||
testMutateRequireAuth(all);
|
||||
testMutateCanEscrow(all);
|
||||
testMutateCanTransfer(all);
|
||||
testMutateCanTransfer(all - featureMPTokensV2);
|
||||
testMutateCanClawback(all);
|
||||
testSetMPT(all);
|
||||
testSetCanLock(all);
|
||||
testSetRequireAuth(all);
|
||||
testSetCanEscrow(all);
|
||||
testSetCanTransfer(all);
|
||||
testSetCanTransfer(all - featureMPTokensV2);
|
||||
testSetCanClawback(all);
|
||||
testSetImmutableFlags(all);
|
||||
|
||||
// Test offer crossing
|
||||
testOfferCrossing(all);
|
||||
|
||||
Reference in New Issue
Block a user