8000 XLS-46: Dynamic Non Fungible Tokens (dNFTs) by xVet · Pull Request #4838 · XRPLF/rippled · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

XLS-46: Dynamic Non Fungible Tokens (dNFTs) #4838

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
Closed
1 change: 1 addition & 0 deletions Builds/CMake/RippledCore.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ target_sources (rippled PRIVATE
src/ripple/app/tx/impl/NFTokenCancelOffer.cpp
src/ripple/app/tx/impl/NFTokenCreateOffer.cpp
src/ripple/app/tx/impl/NFTokenMint.cpp
src/ripple/app/tx/impl/NFTokenModify.cpp
src/ripple/app/tx/impl/OfferStream.cpp
src/ripple/app/tx/impl/PayChan.cpp
src/ripple/app/tx/impl/Payment.cpp
Expand Down
10 changes: 8 additions & 2 deletions src/ripple/app/tx/impl/NFTokenMint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,14 @@ NFTokenMint::preflight(PreflightContext const& ctx)
// tfTrustLine flag as a way to prevent the attack. But until the
// amendment passes we still need to keep the old behavior available.
std::uint32_t const NFTokenMintMask =
ctx.rules.enabled(fixRemoveNFTokenAutoTrustLine) ? tfNFTokenMintMask
: tfNFTokenMintOldMask;
ctx.rules.enabled(fixRemoveNFTokenAutoTrustLine)
// if featureDynamicNFT enabled then new flag allowing mutable URI
// available
? ctx.rules.enabled(featureDynamicNFT) ? tfNFTokenMintMaskWithMutable
: tfNFTokenMintMask
: ctx.rules.enabled(featureDynamicNFT) ? tfNFTokenMintOldMaskWithMutable
: tfNFTokenMintOldMask;

if (ctx.tx.getFlags() & NFTokenMintMask)
return temINVALID_FLAG;

Expand Down
109 changes: 109 additions & 0 deletions src/ripple/app/tx/impl/NFTokenModify.cpp
< 8000 td class="blob-code blob-code-addition js-file-line"> ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2024 Ripple Labs Inc.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================

#include <ripple/app/tx/impl/NFTokenModify.h>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new transaction type needs to be added to ripple/protocol/TxFormats.h and ripple/protocol/impl/TxFormats.cpp and ripple/app/tx/impl/applySteps.cpp - otherwise rippled doesn't know it exists

#include <ripple/app/tx/impl/details/NFTokenUtils.h>
#include <ripple/ledger/View.h>
#include <ripple/protocol/Feature.h>
#include <ripple/protocol/Rate.h>
#include <ripple/protocol/TxFlags.h>
#include <ripple/protocol/st.h>

namespace ripple {

NotTEC
NFTokenModify::preflight(PreflightContext const& ctx)
{
if (!ctx.rules.enabled(featureNonFungibleTokensV1_1) ||
!ctx.rules.enabled(featureDynamicNFT))
return temDISABLED;

if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
return ret;

if (auto owner = ctx.tx[~sfOwner]; owner == ctx.tx[sfAccount])
return temMALFORMED;

if (auto uri = ctx.tx[~sfURI])
{
if (uri->length() == 0 || uri->length() > maxTokenURILength)
return temMALFORMED;
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to check

    if (txFlags & tfNFTokenModifyMask)
        return temINVALID_FLAG;

return preflight2(ctx);
}

TER
NFTokenModify::preclaim(PreclaimContext const& ctx)
{
auto const account = ctx.tx[sfAccount];
auto const owner =
ctx.tx[ctx.tx.isFieldPresent(sfOwner) ? sfOwner : sfAccount];

if (!nft::findToken(ctx.view, owner, ctx.tx[sfNFTokenID]))
return tecNO_ENTRY;

// Check if the NFT is mutable
if (!(nft::getFlags(ctx.tx[sfNFTokenID]) & nft::flagMutable))
return tecNO_PERMISSION;

// Verify permissions for the issuer
if (auto const issuer = nft::getIssuer(ctx.tx[sfNFTokenID]);
issuer != account)
{
if (auto const sle = ctx.view.read(keylet::account(issuer)); sle)
{
if (auto const minter = (*sle)[~sfNFTokenMinter]; minter != account)
return tecNO_PERMISSION;
}
}

return tesSUCCESS;
}

TER
NFTokenModify::doApply()
{
auto const nftokenID = ctx_.tx[sfNFTokenID];
auto const owner =
ctx_.tx[ctx_.tx.isFieldPresent(sfOwner) ? sfOwner : sfAccount];

// Find the token and its page
auto tokenAndPage = nft::findTokenAndPage(view(), owner, nftokenID);
if (!tokenAndPage)
return tecINTERNAL;

// Replace the URI if present in the transaction
if (auto const newURI = ctx_.tx[~sfURI])
tokenAndPage->token.setFieldVL(sfURI, *newURI);
else
tokenAndPage->token.makeFieldAbsent(sfURI);

// Apply the changes to the token
if (auto const ret = nft::updateToken(
view(),
owner,
std::move(tokenAndPage->token),
std::move(tokenAndPage->page));
!isTesSuccess(ret))
return ret;

return tesSUCCESS;
}
} // namespace ripple
48 changes: 48 additions & 0 deletions src/ripple/app/tx/impl/NFTokenModify.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2024 Ripple Labs Inc.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================

#ifndef RIPPLE_TX_NFTOKENMODIFY_H_INCLUDED
#define RIPPLE_TX_NFTOKENMODIFY_H_INCLUDED

#include <ripple/app/tx/impl/Transactor.h>

namespace ripple {

class NFTokenModify : public Transactor
{
public:
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};

explicit NFTokenModify(ApplyContext& ctx) : Transactor(ctx)
{
}

static NotTEC
preflight(PreflightContext const& ctx);

static TER
preclaim(PreclaimContext const& ctx);

TER
doApply() override;
};

} // namespace ripple

#endif
3 changes: 3 additions & 0 deletions src/ripple/app/tx/impl/applySteps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <ripple/app/tx/impl/NFTokenCancelOffer.h>
#include <ripple/app/tx/impl/NFTokenCreateOffer.h>
#include <ripple/app/tx/impl/NFTokenMint.h>
#include <ripple/app/tx/impl/NFTokenModify.h>
#include <ripple/app/tx/impl/PayChan.h>
#include <ripple/app/tx/impl/Payment.h>
#include <ripple/app/tx/impl/SetAccount.h>
Expand Down Expand Up @@ -125,6 +126,8 @@ with_txn_type(TxType txnType, F&& f)
return f.template operator()<NFTokenCancelOffer>();
case ttNFTOKEN_ACCEPT_OFFER:
return f.template operator()<NFTokenAcceptOffer>();
case ttNFTOKEN_MODIFY:
return f.template operator()<NFTokenModify>();
case ttCLAWBACK:
return f.template operator()<Clawback>();
case ttAMM_CREATE:
Expand Down
21 changes: 21 additions & 0 deletions src/ripple/app/tx/impl/details/NFTokenUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,27 @@ compareTokens(uint256 const& a, uint256 const& b)
return a < b;
}

TER
updateToken(
ApplyView& view,
AccountID const& owner,
STObject&& nft,
std::shared_ptr<SLE>&& page)
{
// Remove the old token from the owner's directory
if (auto const ret = nft::removeToken(
view, owner, nft.getFieldH256(sfNFTokenID), std::move(page));
!isTesSuccess(ret))
return ret;

// Insert the updated token into the owner's directory
if (auto const ret = nft::insertToken(view, owner, std::move(nft));
!isTesSuccess(ret))
return ret;

return tesSUCCESS;
}

/** Insert the token in the owner's token directory. */
TER
insertToken(ApplyView& view, AccountID owner, STObject&& nft)
Expand Down
7 changes: 7 additions & 0 deletions src/ripple/app/tx/impl/details/NFTokenUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ deleteTokenOffer(ApplyView& view, std::shared_ptr<SLE> const& offer);
bool
compareTokens(uint256 const& a, uint256 const& b);

TER
updateToken(
ApplyView& view,
AccountID const& owner,
STObject&& nft,
std::shared_ptr<SLE>&& page);

} // namespace nft

} // namespace ripple
Expand Down
3 changes: 2 additions & 1 deletion src/ripple/protocol/Feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ namespace detail {
// Feature.cpp. Because it's only used to reserve storage, and determine how
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
// the actual number of amendments. A LogicError on startup will verify this.
static constexpr std::size_t numFeatures = 67;
static constexpr std::size_t numFeatures = 68;

/** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated
Expand Down Expand Up @@ -354,6 +354,7 @@ extern uint256 const featureDID;
extern uint256 const fixFillOrKill;
extern uint256 const fixNFTokenReserve;
extern uint256 const fixInnerObjTemplate;
extern uint256 const featureDynamicNFT;

} // namespace ripple

Expand Down
7 changes: 7 additions & 0 deletions src/ripple/protocol/TxFlags.h
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should also add
constexpr std::uint32_t const tfNFTokenModifyMask = ~tfUniversal;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary - all the other transactions that don't have any flags just use the tfUniversalMask variable instead of creating a new one.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, unless new flags are looking to be added in the future 🤷

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but a new variable can be added then.

Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ constexpr std::uint32_t const tfBurnable = 0x00000001;
constexpr std::uint32_t const tfOnlyXRP = 0x00000002;
constexpr std::uint32_t const tfTrustLine = 0x00000004;
constexpr std::uint32_t const tfTransferable = 0x00000008;
constexpr std::uint32_t const tfMutable = 0x00000010;

// Prior to fixRemoveNFTokenAutoTrustLine, transfer of an NFToken between
// accounts allowed a TrustLine to be added to the issuer of that token
Expand All @@ -149,6 +150,12 @@ constexpr std::uint32_t const tfNFTokenMintOldMask =
constexpr std::uint32_t const tfNFTokenMintMask =
~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable);

// if featureDynamicNFT enabled then new flag allowing mutable URI available.
constexpr std::uint32_t const tfNFTokenMintOldMaskWithMutable =
~(tfUniversal | tfBurnable | tfOnlyXRP | tfTrustLine | tfTransferable | tfMutable);
constexpr std::uint32_t const tfNFTokenMintMaskWithMutable =
~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable | tfMutable);

// NFTokenCreateOffer flags:
constexpr std::uint32_t const tfSellNFToken = 0x00000001;
constexpr std::uint32_t const tfNFTokenCreateOfferMask =
Expand Down
3 changes: 3 additions & 0 deletions src/ripple/protocol/TxFormats.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ enum TxType : std::uint16_t
/** This transaction type deletes a DID */
ttDID_DELETE = 50,

/** This transaction type modify a NFToken */
ttNFTOKEN_MODIFY = 51,


/** This system-generated transaction type is used to update the status of the various amendments.

Expand Down
1 change: 1 addition & 0 deletions src/ripple/protocol/impl/Feature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ REGISTER_FEATURE(DID, Supported::yes, VoteBehavior::De
REGISTER_FIX(fixFillOrKill, Supported::yes, VoteBehavior::DefaultNo);
REGISTER_FIX (fixNFTokenReserve, Supported::yes, VoteBehavior::DefaultNo);
REGISTER_FIX(fixInnerObjTemplate, Supported::yes, VoteBehavior::DefaultNo);
REGISTER_FEATURE(DynamicNFT, Supported::yes, VoteBehavior::DefaultNo);

// The following amendments are obsolete, but must remain supported
// because they could potentially get enabled.
Expand Down
9 changes: 9 additions & 0 deletions src/ripple/protocol/impl/TxFormats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,15 @@ TxFormats::TxFormats()
},
commonFields);

add(jss::NFTokenModify,
ttNFTOKEN_MODIFY,
{
{sfNFTokenID, soeREQUIRED},
{sfOwner, soeOPTIONAL},
{sfURI, soeOPTIONAL},
},
commonFields);

add(jss::Clawback,
ttCLAWBACK,
{
Expand Down
1 change: 1 addition & 0 deletions src/ripple/protocol/jss.h
B9C8
Original file line numberDiff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ JSS(NFTokenOffer); // ledger type.
JSS(NFTokenAcceptOffer); // transaction type.
JSS(NFTokenCancelOffer); // transaction type.
JSS(NFTokenCreateOffer); // transaction type.
JSS(NFTokenModify); // transaction type.
JSS(NFTokenPage); // ledger type.
JSS(LPTokenOut); // in: AMM Liquidity Provider deposit tokens
JSS(LPTokenIn); // in: AMM Liquidity Provider withdraw tokens
Expand Down
1 change: 1 addition & 0 deletions src/ripple/protocol/nft.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ constexpr std::uint16_t const flagBurnable = 0x0001;
constexpr std::uint16_t const flagOnlyXRP = 0x0002;
constexpr std::uint16_t const flagCreateTrustLines = 0x0004;
constexpr std::uint16_t const flagTransferable = 0x0008;
constexpr std::uint16_t const flagMutable = 0x0010;

inline std::uint16_t
getFlags(uint256 const& id)
Expand Down
Loading
0