mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-04 19:25:51 +00:00
Compare commits
1 Commits
dangell/re
...
Bronek/add
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c365da1208 |
@@ -187,6 +187,7 @@ enum LedgerSpecificFlags {
|
||||
lsfMPTCanTrade = 0x00000010,
|
||||
lsfMPTCanTransfer = 0x00000020,
|
||||
lsfMPTCanClawback = 0x00000040,
|
||||
lsfMPTMutableMeta = 0x00000080,
|
||||
|
||||
// ltMPTOKEN
|
||||
lsfMPTAuthorized = 0x00000002,
|
||||
|
||||
@@ -148,8 +148,9 @@ constexpr std::uint32_t const tfMPTCanEscrow = lsfMPTCanEscrow;
|
||||
constexpr std::uint32_t const tfMPTCanTrade = lsfMPTCanTrade;
|
||||
constexpr std::uint32_t const tfMPTCanTransfer = lsfMPTCanTransfer;
|
||||
constexpr std::uint32_t const tfMPTCanClawback = lsfMPTCanClawback;
|
||||
constexpr std::uint32_t const tfMPTMutableMeta = lsfMPTMutableMeta;
|
||||
constexpr std::uint32_t const tfMPTokenIssuanceCreateMask =
|
||||
~(tfUniversal | tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | tfMPTCanTrade | tfMPTCanTransfer | tfMPTCanClawback);
|
||||
~(tfUniversal | tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | tfMPTCanTrade | tfMPTCanTransfer | tfMPTCanClawback | tfMPTMutableMeta);
|
||||
|
||||
// MPTokenAuthorize flags:
|
||||
constexpr std::uint32_t const tfMPTUnauthorize = 0x00000001;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
// If you add an amendment here, then do not forget to increment `numFeatures`
|
||||
// in include/xrpl/protocol/Feature.h.
|
||||
|
||||
XRPL_FEATURE(MPTMutableMeta, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (AMMClawbackRounding, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(TokenEscrow, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (EnforceNFTokenTrustlineV2, Supported::yes, VoteBehavior::DefaultNo)
|
||||
|
||||
@@ -420,6 +420,7 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_DESTROY, 55, MPTokenIssuanceDestroy, Delegation::
|
||||
TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet, Delegation::delegatable, ({
|
||||
{sfMPTokenIssuanceID, soeREQUIRED},
|
||||
{sfHolder, soeOPTIONAL},
|
||||
{sfMPTokenMetadata, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction type authorizes a MPToken instance */
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <test/jtx/xchain_bridge.h>
|
||||
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
namespace ripple {
|
||||
@@ -86,6 +87,14 @@ class MPToken_test : public beast::unit_test::suite
|
||||
.metadata = "",
|
||||
.err = temMALFORMED});
|
||||
|
||||
// oversized metadata returns error
|
||||
mptAlice.create(
|
||||
{.maxAmt = 100,
|
||||
.assetScale = 0,
|
||||
.transferFee = 0,
|
||||
.metadata = std::string(2050, 'B'),
|
||||
.err = temMALFORMED});
|
||||
|
||||
// MaximumAmout of 0 returns error
|
||||
mptAlice.create(
|
||||
{.maxAmt = 0,
|
||||
@@ -108,6 +117,29 @@ class MPToken_test : public beast::unit_test::suite
|
||||
.metadata = "test",
|
||||
.err = temMALFORMED});
|
||||
}
|
||||
|
||||
// test preflight tfMPTMutableMeta when feature is disabled
|
||||
{
|
||||
Env env{*this, features - featureMPTMutableMeta};
|
||||
MPTTester mptAlice(env, alice);
|
||||
|
||||
mptAlice.create(
|
||||
{.maxAmt = 100,
|
||||
.assetScale = 0,
|
||||
.transferFee = 0,
|
||||
.flags = tfMPTMutableMeta,
|
||||
.err = temDISABLED}
|
||||
);
|
||||
|
||||
mptAlice.create(
|
||||
{.maxAmt = 100,
|
||||
.assetScale = 0,
|
||||
.transferFee = 0,
|
||||
.metadata = "abc",
|
||||
.flags = tfMPTMutableMeta,
|
||||
.err = temDISABLED}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -512,6 +544,14 @@ class MPToken_test : public beast::unit_test::suite
|
||||
.holder = alice,
|
||||
.flags = tfMPTLock,
|
||||
.err = temMALFORMED});
|
||||
|
||||
// Oversized metadata
|
||||
mptAlice.set(
|
||||
{.account = alice,
|
||||
.holder = alice,
|
||||
.metadata = std::string(2050, 'B'),
|
||||
.flags = tfMPTLock,
|
||||
.err = temMALFORMED});
|
||||
}
|
||||
|
||||
// Validate fields in MPTokenIssuanceSet (preclaim)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <test/jtx.h>
|
||||
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
namespace ripple {
|
||||
@@ -231,6 +232,8 @@ MPTTester::set(MPTSet const& arg)
|
||||
Throw<std::runtime_error>("MPT has not been created");
|
||||
jv[sfMPTokenIssuanceID] = to_string(*id_);
|
||||
}
|
||||
if (arg.metadata)
|
||||
jv[sfMPTokenMetadata] = strHex(*arg.metadata);
|
||||
if (arg.holder)
|
||||
jv[sfHolder] = arg.holder->human();
|
||||
if (arg.delegate)
|
||||
|
||||
@@ -135,6 +135,7 @@ struct MPTSet
|
||||
std::optional<Account> account = std::nullopt;
|
||||
std::optional<Account> holder = std::nullopt;
|
||||
std::optional<MPTID> id = std::nullopt;
|
||||
std::optional<std::string> metadata = std::nullopt;
|
||||
std::optional<std::uint32_t> ownerCount = std::nullopt;
|
||||
std::optional<std::uint32_t> holderCount = std::nullopt;
|
||||
std::optional<std::uint32_t> flags = std::nullopt;
|
||||
|
||||
@@ -30,6 +30,8 @@ MPTokenIssuanceCreate::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
if (!ctx.rules.enabled(featureMPTokensV1))
|
||||
return temDISABLED;
|
||||
if (ctx.tx.isFlag(tfMPTMutableMeta) && !ctx.rules.enabled(featureMPTMutableMeta))
|
||||
return temDISABLED;
|
||||
|
||||
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
#include <xrpld/app/tx/detail/MPTokenIssuanceSet.h>
|
||||
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
|
||||
namespace ripple {
|
||||
@@ -30,6 +33,8 @@ MPTokenIssuanceSet::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
if (!ctx.rules.enabled(featureMPTokensV1))
|
||||
return temDISABLED;
|
||||
if (ctx.tx.isFieldPresent(sfMPTokenMetadata) && !ctx.rules.enabled(featureMPTMutableMeta))
|
||||
return temDISABLED;
|
||||
|
||||
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
|
||||
return ret;
|
||||
@@ -43,6 +48,13 @@ MPTokenIssuanceSet::preflight(PreflightContext const& ctx)
|
||||
else if ((txFlags & tfMPTLock) && (txFlags & tfMPTUnlock))
|
||||
return temINVALID_FLAG;
|
||||
|
||||
if (auto const metadata = ctx.tx[~sfMPTokenMetadata])
|
||||
{
|
||||
// Note: metadata->length() == 0 is valid here, will erase metatdata
|
||||
if (metadata->length() > maxMPTokenMetadataLength)
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
auto const accountID = ctx.tx[sfAccount];
|
||||
auto const holderID = ctx.tx[~sfHolder];
|
||||
if (holderID && accountID == holderID)
|
||||
@@ -97,6 +109,11 @@ MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx)
|
||||
if (!sleMptIssuance)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
|
||||
if (ctx.tx.isFieldPresent(sfMPTokenMetadata) && !sleMptIssuance->isFlag(lsfMPTMutableMeta))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// TODO check below is invalid if we are trying to update metadata
|
||||
|
||||
// if the mpt has disabled locking
|
||||
if (!((*sleMptIssuance)[sfFlags] & lsfMPTCanLock))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
Reference in New Issue
Block a user