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