0020 XLS-20d Non-Fungible Token Support (native) #46
Replies: 74 comments 145 replies
-
Digesting this, but from my initial read, looks pretty awesome! |
Beta Was this translation helpful? Give feedback.
-
Should we allocate a draft number? Looks like |
Beta Was this translation helpful? Give feedback.
-
I suspect we need to clarify rules for the
In general the details on the |
Beta Was this translation helpful? Give feedback.
-
Regarding the question of the identifier of an Use the |
Beta Was this translation helpful? Give feedback.
-
Interesting NFT spec:
One general comment - as we scale we should consider allowing for off-chain message signing for use on-chain. This means we will be able to do offchain orderbooks and onchcian execution to reduce offercreate noises. |
Beta Was this translation helpful? Give feedback.
-
It feels like this standard is very close to enabling an on-ledger software licensing model. @WietseWind have you considered what issuing a XUMM Pro license via NFT would look like? I don't think that you could pull off a subscription based licensing model with this standard, but the ability to profit off of every secondary market transaction seems very appealing. |
Beta Was this translation helpful? Give feedback.
-
This is really interesting! I like the idea of the native support of NFTs on the XRPL. |
Beta Was this translation helpful? Give feedback.
-
Really wrestling with this part. I don't have any experience with the IPFS, so that's probably slowing me down. I can envision a NFT's that are "minimally invasive" that the ledger should be able to accommodate directly on chain. I don't know what that limit is (128 characters?) but I can easily see something like ownership of virtual land being nothing more than a hash and some coordinates. Seems a shame to necessitate a pointer off-ledger for something so simple. |
Beta Was this translation helpful? Give feedback.
-
The paper sounds plausible in itself, but I think the part with the external references still needs to be clarified. Offchain data storage in particular has some pitfalls in the context of data management, such as trustworthiness, rights management, data integrity and data security. A simple link is usually not enough. You should therefore pay particular attention to the secure connection to external data services. IPFS sounds promising at first, especially for NFTs (Hash of Content eq. Address), but I am currently not clear about how IPFS itself regulates data access restrictions. I think it is unfavorable if all data content is publicly available one way or another. But in the end this is also part of the NFT's rights policy and order of responsiblity. |
Beta Was this translation helpful? Give feedback.
-
Excited to see the possibilities of NFTs on XRPL. I am working on CO2 Bonds/Conservation NFTs and would love to learn if something like this https://github.com/BooneTB/CO2StakingBonsai/blob/main/CarbonBOND |
Beta Was this translation helpful? Give feedback.
-
I've got an Social Media prototype using ethereum hybrid 721's.... Every asset uploaded is a "721" contract but can also hold a token balance. I call my tokens SAMY. Every view on the asset reduces the token balance by one, paid to the "viewer" Every comment/like, adds a token to the balance, paid by the "commenter/liker". A simple basic decentralized way to measure engagement and reward users. I stripped the ETH protocol today and I'm going to try to add the XRP protocol features for NFT. I did have one question. Smart Contracts on ethereum can hold value, I view this feature in XRPL as just the wallet that holds the value. Sure, the functionality of the code doesn't reside inside the wallet on XRPL, but by using multi sign, I can basically create the same idea and did this using a swift class if anyone is interested. Is there a better way to achieve this? I know you just released hooks but to be honest I've been head down in my ethereum private blockchains. I like XRP more tho. Would love to discuss. |
Beta Was this translation helpful? Give feedback.
-
Would it be possible for a |
Beta Was this translation helpful? Give feedback.
-
When minting an NFT it looks like there are 2 routes that can be taken from a 3rd parties perspective.
Example: Website A wants to offer the ability for users to create NFTs. Website A must either:
Is this correct? What are the downsides for setting User B, User C, User D, as issuers when they mint their own NFTs and not setting Website A as the issuer? |
Beta Was this translation helpful? Give feedback.
-
Great proposal! I think this is a solid step towards supporting NFTs on XRPL. I have a question about These objects are updated automatically with If so, what possible use cases could there be for having the ability to change this object outside of a mint or burn transaction? |
Beta Was this translation helpful? Give feedback.
-
I've been thinking a little more about this proposal and would like to suggest a change that should make NFT objects even more lightweight. Currently, an NFT contains both a 20-byte issuer and a 32-byte hash, for a total of 55 bytes. The 32-byte hash is meant to distinguish this NFT from any other, but in reality it only adds trouble. For example, an issuer could "double-issue" a token, and there's no way for the ledger to detect this, much less prevent it. Maybe that's fine, of course; maybe issuers shouldn't shoot themselves in the foot, but the spec is meant to allow for "non-fungible" tokens and yet it allows for the creation of binary-identical objects. What does it mean when have two "non-fungible" tokens that are identical and cannot be distinguished? What if we were to add an additional field: a "serial number" of sorts. But what to set it to? Well, the transaction's sequence number seems reasonable. It's never reused, so it works. It means that even if the issuer reuses the hash, the two resulting NFTs are distinct. This causes trouble with the mint account, but we can solve this by adding a new optional field to the account root: a 64-bit number But if we're going to do that, why even have a 256-bit identifier? Why not just treat the pair And this also enables something else that's really neat: we can create semi-fungible tokens. We can simply add an optional 32-bit field to an NFT, let's call it So, now we can use Let's say the issuer wants to issue an NFT to represent a limited edition album. They can assign that album a unique 32-bit number, and issue any number of tokens which are all "linked":
|
Beta Was this translation helpful? Give feedback.
-
There is no way given this spec. I have a PR in review that will add this
ability to clio - it will let you query by tokenid and see the owner, as
well as the decrypted uri and other fields.
If you’re unfamiliar With clio, it’s a reporting/performance layer on top
of rippled.
We are planning to have this feature ready soon and available for query.
…On Mon, Apr 11, 2022 at 20:52 Mahiros ***@***.***> wrote:
Hello, I want to get owner account info from NFTokenID, how can I get
account info?
I can get NFTs list from the account using account_nfts.
—
Reply to this email directly, view it on GitHub
<#46 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABXUFDK7W2WTK3JKL7PUBLLVETCL3ANCNFSM45N47IJA>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
Hi guys - Just to keep systems/docs updated, I'd like to suggest a few edits...
|
Beta Was this translation helpful? Give feedback.
-
Feature Request This feature request describes absent yet essential functionality on the XRPL, with regards to fetching Account Objects for a particular address. It is currently possible to request certain types of Account Objects by providing the type of such objects in the parameters of an “account_objects” request, as indicated here. For example, adding { type: “escrow” } to an “account_objects” request will exclusively return Account Objects of the escrow type. Such functionality, however, does not exist with regards to the new NFTokenOffer objects that have been introduced through the XLS-20 amendment. Indeed, the only possible means by which to retrieve all NFTokenOffers related to an account is to query for all of the Account Objects associated with an account, and filter against their type field. As a consequence, there exists no efficient way to retrieve only NFTokenOffer objects related to one account. Ultimately, this calls for a revision that enables the provision of a relevant type such as { type: “nftoken_offer” } or similar. |
Beta Was this translation helpful? Give feedback.
-
@scottschurr, I think he is referring to offers on an NFT. |
Beta Was this translation helpful? Give feedback.
-
Unfortunately that is not possible given the directory structure of NFTs.
That structure was chosen for performance, and to reduce reserve
requirements for end-users. This is just an example of dev tradeoffs, but
Clio is able to fill in the gap.
…On Wed, Apr 20, 2022 at 4:19 PM Julian Gums ***@***.***> wrote:
Clio seems like a great tool but arguably looking up who a given NFT
belongs to seems to be something that is so common that it would be great
if it was natively supported.
—
Reply to this email directly, view it on GitHub
<#46 (reply in thread)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABXUFDOSR5MBJD6BHDANFSLVGBRERANCNFSM45N47IJA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
Owner test with regards to accepting buy offers. The following describes a simple flow to demonstrate the somewhat counterintuitive role of the Owner field with regards to the creation of NFToken Buy Offers on the XRPL. This counterintuitive behaviour can be attributed to the premise that the requirement of an Owner field in the NFTokenCreateOffer transaction ensures that such an offer may only be accepted by the address specified in the owner field. The flow described below, however, reveals that this is not the case: Account 1 creates offer for 100 XRP with owner Account 3 Account 2 creates offer for 100XRP with owner Account 3 Account 3 accepts Account 2’s offer Account 2 accepts Account 1’s offer Following from the above described premise, Account 2 should not have been able to accept Account 1’s offer on the principle that Account 1’s offer was made with the Owner field specified as the address of Account 3. The conclusion, thus, is that the Owner field is significant only when a buy offer is being created. Assigning the Owner field with an address that is not the current owner of the NFT prevents that offer from being successfully made, but does not appear to have any further behaviours or interactions. That is to say, the Owner field does not prevent buy offers from being accepted by a ‘new’ owner whose address is different from the ‘original’ owner address which was used to create that buy offer. |
Beta Was this translation helpful? Give feedback.
-
@scottschurr When transferring an NFT would all the past orders for that token id owned by XYZ be "destroyed" or is it up to the user client or rpc indexing to handle this? |
Beta Was this translation helpful? Give feedback.
-
Hi guys, I have written up a new proposal to expand on the XLS-20d proposal for NFTs. The change would help owners manage the NFT's they have in there wallets and also mitigate some potential bad user experience and negative feedback on how NFT's work in XRPL. It would be good if you take a look, comment and hopefully up-vote my proposal. |
Beta Was this translation helpful? Give feedback.
-
Suggested edits to align the standard with the implementation, prior to moving XLS-20d from draft to final: 1.2.1.1.1.4 Example
Example TokenPage JSON
The NFTokenMint transaction
Example NFTokenMint transaction
The NFTokenBurn transaction
1.3. Account Root modifications
1.3.3 BurnedNFTokens
1.4.1.1. NFTokenOfferID Format
1.5.4.1. Fields
|
Beta Was this translation helpful? Give feedback.
-
I minted NFTs on behalf of other account. I used Account A and minted for Account B. |
Beta Was this translation helpful? Give feedback.
-
Hello |
Beta Was this translation helpful? Give feedback.
-
I've come across an issue. It is very easy to create buy offers from unfunded accounts. Here is one I have done for 250M XRP. Obviously I don't have that, even in devnet. https://xls20.bithomp.com/explorer/18B9E787507DD6EA61874BD1E8EA6C61E41825B343542F3FCE97C1666CD899F0 These buys orders generate a tech unfunded error on the sell side. |
Beta Was this translation helpful? Give feedback.
-
I'm not sure how the NFTokenPage concept works on an atomic level but I noticed that they never get completely filled with NFTs. Initially, I thought they always fill up to 32 but I'm seeing token pages with 17-29 NFTs in them when I mint. If I mint the same things twice, I get the same amount of pages so it does not seem random but there seems to be a deterministic algorithm for it. But how? How can I work out if I am going to mint x amount of NFTs, how much reserve I will need? Or does this depend on the exact NFTokenIDs as it seems like this is some kind of indexing issue and an NFTokenID can either fit into a page or it can't, based on how high/low it is and a new one needs to be created? Anyone that can explain? |
Beta Was this translation helpful? Give feedback.
-
I know that this is already active/enabled on mainnet, but just for the sake of having this documentation correct, I propose following changes to original post:
That is actually not true. So actually the transfer fee is wrong. Also, in the same section, you are showing how tokenId is calculated. With flags as first for characters etc.
000B => Flags: 11, not 12. We cannot have flags with value of 12. |
Beta Was this translation helpful? Give feedback.
-
Note for future readers: This spec has been implemented and adopted, and is being updated and approved here: #95 |
Beta Was this translation helpful? Give feedback.
-
Latest version: XLS-20 Non-Fungible Tokens
A previous version of the spec follows:
1. Non-Fungible Token Support
1.1. Abstract
The XRP Ledger offers support for tokens (a.k.a. IOUs or issued assets). Such assets are, primarily, fungible. They can be easily traded between users for XRP or other issued assets on the XRP Ledger's decentralized exchange. This makes them ideal for payments.
Such objects can also be used to implement non-fungible tokens (NFTokens), as seen in an example implementation by the XRPL Labs team.
Non-fungible tokens serve to encode ownership of physical, non-physical or purely digital goods, such as works of art and in-game items.
This proposal introduces extensions to the XRP Ledger that would support a native non-fungible token type, along with operations to enumerate, purchase, sell and hold such tokens.
While other proposals (some of which are extremely interesting) have been made, the authors believe that this proposal represents a strong commitment to supporting NFTs on the XRP Ledger, and adds a rich set of flexible primitives that can be used by token issuers.
The non-fungible tokens proposed are:
1.1.1. Advantages and Disadvantages
Advantages
Disadvantages
1.2. Creating and Transferring Tokens on XRPL
1.2.1. On-Ledger Data Structures
We propose two new objects and one new ledger structure:
NFToken
is a new object that describes a single NFT.NFTokenOffer
is a new object that describes an offer to buy or sell a singleNFToken
.NFTokenPage
is a ledger structure that contains a set ofNFToken
objects owned by the same account.1.2.1.1. The
NFToken
objectThe
NFToken
object represents a single NFT and holds data associated with the NFT itself. NFTs are created using theNFTokenMint
transaction and can, optionally, be destroyed by theNFTokenBurn
transaction.1.2.1.1.1. Fields
An
NFToken
object can have the following required and optional fields. Notice that, unlike other objects no field is needed to identify the object type or current owner of the object, because NFTs are grouped into pages that implicitly define the object type and identify the owner.NFTokenID
string
UINT256
This composite field uniquely identifiers a token; it contains a set of 16 bits that identify flags or settings specific to the NFT, 16 bits that encode the transfer fee associated with this token, if
any, the 160-bit account identifier of the issuer, a 32-bit issuer-specified taxon, and an
(automatically generated) monotonically increasing 32-bit sequence number.
The 16-bit flags and transfer fee fields, and the 32-bit taxon and sequence number fields are stored in big-endian format.
1.2.1.1.1.1
Flags
A set of flags indicating properties or other options associated with this
NFToken
object. The type specific flags proposed at this are:These flags are immutable: they can only be set during the
NFTokenMint
transaction and cannot be changed later.📝 The
lsfTrustLine
field is useful when the token can be offered for sale for assets other than XRP and the issuer charges aTransferFee
. If this flag is set, then a trust line will be automatically created, when needed, to allow the issuer to receive the appropriate transfer fee. If this flag is not set then an attempt to transfer for token for an asset that the issuer does not have a trustline for will fail.1.2.1.1.1.2
TransferFee
The value specifies the fee, in tenths of a basis point, charged by the issuer for secondary sales of the token, if such sales are allowed at all. Valid values for this field are between 0 and 50,000 inclusive and a value of 1 is equivalent to 1/10 of a basis point or 0.001%, allowing transfer rates between 0% and 50%. A
TransferFee
of 50,000 corresponds to 50%.1.2.1.1.1.3 Taxon Scrambling
An issuer may issue several NFTs with the same taxon; to ensure that NFTs are spread across multiple pages we lightly mix the taxon up by using the sequence (which is not under the issuer's direct control) as the seed for a simple linear congruential generator.
From the Hull-Dobell theorem we know that
f(x)=(m*x+c) mod n
will yield a permutation of[0, n)
whenn
is a power of 2 ifm
is congruent to1 mod 4
andc
is odd.This proposal fixes
m = 384160001
andc = 2459
. Changing these numbers after this proposal is implemented and deployed would be a breaking change requiring, at a minimum, an amendment and a way to distinguish token IDs that were generated with the old code.1.2.1.1.1.4 Example
For example, the
NFTokenID
000B013A95F14B0E44F78A264E41713C64B5F89242540EE2BC8B858E00000D65
would uniquely identify the token withTaxon
146,999,694 andSequence
3,429, issued byrNCFjv8Ek5oDrNiMJ3pw6eLLFtMjZLJnf2
. TheTransferFee
is 3.14% and theFlags
associated with the token are:lsfBurnable
,lsfOnlyXRP
andlsfTransferable
:ℹ️ Notice that the scrambled version of the taxon is
0xBC8B858E
: the scrambled version of the taxon specified by the issuer. But the actual value of the taxon is the unscrambled value.URI
string
BLOB
A URI that points to the data and/or metadata associated with the NFT. This field need not be an HTTP or HTTPS URL; it could be an IPFS URI, a magnet link, immediate data encoded as an RFC2379 "data" URL, or even an opaque issuer-specific encoding. The URI is NOT checked for validity, but the field is limited to a maximum length of 256 bytes.
📝 In the interest of reducing the size of NFT objects and their impact on the ledger as a whole as well as maximizing flexibility, this implementation recommends (but does not require) that this field be avoided. Not only does this field increase the amount of data that must be stored on ledger, but it is also immutable, which means that, if specified, it commits the issuer to hosting the data and/or metadata associated with the NFT at the specified location. See the Retrieving NFToken Data and Metadata section below for details on alternatives.
1.2.1.1.2.1. Example NFToken JSON
Retrieving NFToken Data and Metadata
In the interest of (a) minimizing the footprint of an NFT but without sacrificing utility or functionality; and (b) imposing as few restrictions as possible, this specification does not allow an NFT to hold arbitrary data fields. Instead, such data, whether structured or unstructured, is maintained separately and referenced by the NFT. This proposal recommends using one of the following two approaches to provide external references to obtain
NFToken
data and/or metadata.URI
field: We propose an optionalURI
field in theNFToken
object. Implementations MAY choose to use this field to provide an external reference to:Hash
.NFToken
object.The
URI
field is especially useful for referring to non-traditional Peer-to-Peer (P2P) URLs. For example, aNFTokenMinter
wishing to storeNFToken
data and/or metadata using the Inter Planetary File System (IPFS) MAY useURI
field to refer to data on IPFS in different ways, each of which is suited to different use-cases. For more context on types of IPFS links that can be used to store NFT data, see here.Domain
field: Alternative to the above approach, issuers ofNFToken
objects may set theDomain
field of their issuing account to the correct domain and offer an API for clients that want to lookup the data and/or metadata associated with a particular NFT. This proposal recommends the use of DNSTXT
records as a customization point, allowing the issuer to specify the URL to be used by providing a properly-formatted TXT record.Note that using this mechanism requires the
NFTokenMinter
to acquire a domain name and set the domain name for their minting account, but does not require theNFTokenMinter
to necessarily operate a serveror other service to provide the ability to query this data; instead, a
NFTokenMinter
can easily "redirect" queries to a data provider (e.g., to a marketplace, registry or other service).Implementations should attempt to check for the presence of
URI
field first to retrieve the associated data and/or metadata. In caseURI
field does not exist, implementations should check for the presence ofDomain
field. Nothing happens, if neither of the fields exist. Implementations should be prepared to handle HTTP redirections (e.g., using HTTP responses 301, 302, 307 and 308) from the URI.TXT Record Format:
The string
{:NFTokenID:}
should be replaced with the requested tokens'NFTokenID
, as a 64 byte hex string when attempting to query information.Implementations should check for the presence of
TXT
records and use those query strings if present. If no string is present, implementations should attempt to use a default URL. Assuming the domain was example.com, the default URL this proposal recommends would be:https://example.com/.well-known/xrpl-nft/{:nft_id:}
The
NFTokenPage
ledger entryThis object represents a collection of
NFToken
objects owned by the same account. It is important to note that theNFToken
objects themselves reside within this page, instead of in a dedicated object entry in theSHAMap
. An account can have multipleNFTokenPage
ledger objects, which form a doubly-linked list (DLL).In the interest of minimizing the size of a page and optimizing storage, the
Owner
field is not present since it is encoded as part of the object's ledger identifier (more details in theNFTokenPageID
discussion).Fields
An
NFTokenPage
object may have the following required and optional fields:LedgerEntryType
string
UINT16
Identifies the type of ledger object. This proposal recommends the value
0x0050
as the reserved ledger entry type.PreviousPageMin
string
UINT256
The locator of the previous page, if any. Details about this field and how it should be used are outlined below, after the construction of the
NFTokenPageID
is explained.NextPageMin
string
UINT256
The locator of the next page, if any. Details about this field and how it should be used are outlined below, after the construction of the
NFTokenPageID
is explained.PreviousTxnID
string
HASH256
Identifies the transaction ID of the transaction that most recently modified this
NFTokenPage
object.PreviousTxnLgrSeq
number
UINT32
The sequence of the ledger that contains the transaction that most recently modified this
NFTokenPage
object.NFTokens
object
TOKEN
The collection of
NFToken
objects contained in thisNFTokenPage
object. This specification places an upper bound of 32NFToken
objects per page. Objects should be stored in sorted order, from low to high with the low order 96 bits of theNFTokenID
used as the sorting parameter.TokenPage ID Format
Unlike other object identifiers on the XRP Ledger, which are derived by hashing a collection of data using
SHA512-Half
,NFTokenPage
identifiers are constructed so as to specfically allow for the adoption of a more efficient paging structure, ideally suited for NFTs.The identifier of an
NFTokenPage
is derived by concatenating the 160-bitAccountID
of the owner of the page, followed by a 96 bit value that indicates whether a particularNFTokenID
may be contained in this page.More specifically, and assuming that the function
low96(x)
returns the low 96 bits of a 256-bit value, an NFT withNFTokenID
A
can be included in a page withNFTokenPageID
B
if and only iflow96(A) >= low96(B)
.For example, applying the
low96
function to the NFT described before, which had an ID of000B013A95F14B0044F78A264E41713C64B5F89242540EE208C3098E00000D65
the functionlow96
would return42540EE208C3098E00000D65
.This curious construct exploits the structure of the SHAMap to allow for efficient lookups of individual
NFToken
objects without requiring iteration of the doubly-linked list ofNFTokenPages
.Example TokenPage JSON
How do
NFTokenPage
objects work?The page within which an
NFToken
entry is stored will be formed as described above. This is needed to find the correct starting point in the doubly-linked list ofNFTokenPage
objects if that list is large. This is because it is inefficient to have to traverse the list from the beginning if an account holds thousands ofNFToken
objects in hundreds ofNFTokenPage
objects.Searching an
NFToken
objectTo search for a specific
NFToken
, the first step is to locate theNFTokenPage
, if any, that should contain thatNFToken
. For that do the following:Compute the
NFTokenPageID
using the account of the owner and theNFTokenID
of the token, as described above. Then search for the ledger entry whose identifier is less than or equal to that value. If that entry does not exist or is not anNFTokenPage
, theNFToken
is not held by the given account.Adding an
NFToken
objectAn
NFToken
object can be added by using the same approach to find theNFTokenPage
it should be in and adding it to that page. If after addition the page overflows, find thenext
andprevious
pages (if any) and balance those three pages, inserting a new page as/if needed.Removing an
NFToken
objectAn
NFToken
can be removed by using the same approach. If the number ofNFTokens
in the page goes below a certain threshhold, an attempt will be made to consolidate the page with aprevious
or subsequent page and recover the reserve.Reserve for
NFTokenPage
objectEach
NFTokenPage
costs an incremental reserve to the owner account. This specification allows up to 32NFToken
entries per page, which means that for accounts that hold multiple NFTs the effective reserve cost per NFT can be as low as R/32 where R is the incremental reserve.The reserve in practice
The value of the incremental reserve is, as of this writing, 2 XRP. The table below shows what the effective reserve per token is, if a given page contains 1, 8, 16, 32 and 64 NFTs:
Transactions
This proposal introduces several new transactions to allow for the minting, burning and trading of NFTs. All transactions introduced by this proposal incorporate the common transaction fields
that are shared by all transactions. Common fields are not document in this proposal unless needed because this proposal introduces new possible values for such fields.
Transactions for minting and burning NFTs on XRPL
We define two transactions:
NFTokenMint
andNFTokenBurn
for minting and burning NFTs respectively on XRPL.The
NFTokenMint
transactionThe
NFTokenMint
transaction creates anNFToken
object and adds it to the relevantNFTokenPage
object of theNFTokenMinter
. A required parameter to this transaction is theToken
field specifying the actual token. This transaction is the only opportunity theNFTokenMinter
has to specify any token fields that are defined as immutable (e.g., theTokenFlags
).If the transaction is successful, the newly minted NFToken will be owned by the account (the
NFTokenMinter
account) which executed the transaction. If needed, a newNFTokenPage
is created for this account and a reserve is charged as described earlier.Transaction-specific Fields
TransactionType
string
UINT16
Indicates the new transaction type
NFTokenMint
. The integer value is25
.Account
string
ACCOUNT ID
Indicates the account which is minting the token. The account MUST either:
Issuer
field in theNFToken
object; orNFTokenMinter
field in theAccountRoot
of theIssuer
field in theNFToken
object.Issuer
string
ACCOUNT ID
Indicates the account that should be the issuer of this token. This value is optional and should only be specified if the account executing the transaction is not the
Issuer
of theNFToken
object. If it is present, theNFTokenMinter
field in theAccountRoot
of theIssuer
field must match theAccount
, otherwise the transaction will fail.NFTokenTaxon
number
UINT32
Indicates the taxon associated with this token. The taxon is generally a value chosen by the
NFTokenMinter
of the token and a given taxon may be used for multiple tokens. Taxons have a valid range range from 0x0 to 0xFFFFFFFF.Flags
number
UINT32
Specifies the flags for this transaction. In addition to the universal transaction flags that are applicable to all transactions (e.g.,
tfFullyCanonicalSig
), the following transaction-specific flags are defined and used to set the appropriate fields in the NFT:TransferFee
number
UINT16
The value specifies the fee to charged by the issuer for secondary sales of the Token, if such sales are allowed. Valid values for this field are between 0 and 50,000 inclusive, allowing transfer rates of between 0.000% and 50.000% in increments of 0.001.
The field MUST NOT be present if the
tfTransferable
flag is not set. If it is, the transaction should fail and a fee should be claimed.URI
string
BLOB
A URI that points to the data and/or metadata associated with the NFT. This field need not be an HTTP or HTTPS URL; it could be an IPFS URI, a magnet link, immediate data encoded as an RFC2379 "data" URL, or even an opaque issuer-specific encoding. The URI is NOT checked for validity, but the field is limited to a maximum length of 256 bytes.
Embedding additional information
If
NFTokenMinters
need to specify additional information during minting (for example, details identifying a property by referencing a particular plat, a vehicle by specifying a VIN, or other object-specific descriptions) they should use thememo
functionality that is already available on the XRP Ledger as a common field. Memos are a part of the signed transaction and are available from historical archives, but are not stored in the ledger.Example
NFTokenMint
transactionThis transaction assumes that the issuer,
rNCFjv8Ek5oDrNiMJ3pw6eLLFtMjZLJnf2
, has set theNFTokenMinter
field in itsAccountRoot
torvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B
, thereby authorizing that account to mint tokens on its behalf.Execution
In executing, this transaction will examine the
MintedNFTokens
field in the account root of theIssuer
and use it to construct theNFTokenID
for the token being minted. If the field does not exist, the field will be assumed to have the value 0; the value of the field will then be incremented by exactly 1.The
NFTokenBurn
transactionThe
NFTokenBurn
transaction is used to remove anNFToken
object from theNFTokenPage
in which it is being held, effectively removing the token from the ledger ("burning" it).If this operation succeeds, the corresponding
NFToken
is removed. If this operation empties theNFTokenPage
holding theNFToken
or results in the consolidation, thus removing anNFTokenPage
, the owner’s reserve requirement is reduced by one.Transaction-specific Fields
TransactionType
string
UINT16
Indicates the new transaction type
NFTokenBurn
. The integer value is26
.Account
string
ACCOUNT ID
Indicates the
AccountID
that submitted this transaction. The account MUST be either the presentowner
of the token or, if thelsfBurnable
flag is set in theNFToken
, either theissuer
account or an account authorized by the issuer, i.e.,NFTokenMinter
.NFTokenID
string
UINT256
Identifies the
NFToken
object to be removed by the transaction.Example
NFTokenBurn
JSON1.3. Account Root modifications
This proposal introduces 3 additional fields in an
AccountRoot
:NFTokenMinter
field;MintedNFTokens
field; and theBurnedNFTokens
field.1.3.1
NFTokenMinter
It is likely that issuers may want to issue NFTs from their well-known account while, at the same time wanting to delegate the issuance of such NFTs to a mint or other third party. To enable this use case, this specification introduces a new, optional, field in the
AccountRoot
object.NFTokenMinter
string
AccountID
The
NFTokenMinter
field, if set, specifies an alternate account which is allowed to execute theNFTokenMint
andNFTokenBurn
operations on behalf of the account.The
AccountSet
transaction should be augmented to allow the field to be set or cleared.Note: Previous versions of this spec used the term
MintAccount
for this field.1.3.2
MintedNFTokens
To ensure the uniqueness of
NFToken
objects, this proposal introduces theMintedNFTokens
field. This field is used during theNFTokenMint
transaction and used to form theNFTokenID
of the new object. If this field is not present the value 0 is assumed.1.3.3
BurnedNFTokens
To provide a convenient way to determine how many
NFToken
objects issued by an account are still active (i.e., not burned), this proposal introduces theBurnedNFTokens
field. If this field is not present the value 0 is assumed. The field is incremented whenever a token issued by this account is burned. So this field will be present and non-zero for any account that has issued at least one token and one or more of those tokens have been burned.📝 An account for which the difference between the number of minted and burned tokens, as stored in the
MintedNFTokens
andBurnedNFTokens
fields respectively, is non-zero cannot be deleted.1.4. Transferability of Tokens (NFTs)
Tokens which have the
lsfTransferable
flag set can be transferred among users. This is achieved by way of offers.1.4.1. The
NFTokenOffer
ledger entryThe
NFTokenOffer
ledger entry represents an offer to buy, sell or transfer anNFToken
object. AnNFTokenOffer
object is created as a result ofNFTokenCreateOffer
transaction by the owner of theNFToken
.1.4.1.1.
NFTokenOfferID
FormatThe unique ID, a.k.a
NFTokenOfferID
of theNFTokenOffer
object is the result ofSHA512-Half
of the following values concatenated in order:NFTokenOffer
space key; this proposal recommends using the value0x0074
;AccountID
of the account placing the offer; andSequence
(orTicket
) of theNFTokenCreateOffer
transaction that will create theNFTokenOffer
.Fields
Owner
string
AccountID
Indicates the
Owner
of the account that is creating and owns the offer. Only the currentOwner
of anNFToken
can create an offer to sell anNFToken
, but any account can create an offer to buy anNFToken
.LedgerEntryType
string
UINT16
Indicates the type of ledger object. This proposal recommends using the value
0x0074
.Flags
number
UINT32
A set of flags associated with this object, used to specify various options or settings. This proposal only defines one flag at this time, used to determine if this is a
Buy
or
Sell
offer:PreviousTxnID
string
Hash256
Indicates the identifying hash of the transaction that most recently modified this object.
PreviousTxnLgrSeq
number
UINT32
Indicates the index of the ledger that contains the transaction that most recently modified this object.
NFTokenID
string
UINT256
Specifies the
NFTokenID
of theNFToken
object being referenced by this offer.Amount
object
orstring
AMOUNT
Indicates the amount expected or offered for the
NFToken
. If the token has thelsfOnlyXRP
flag set, the amount MUST be specified in XRP.Sell offers that specify assets other than XRP must specify a non-zero amount. Sell offers which specify XRP can be 'free' (i.e., the
Amount
field may be equal to"0"
).Expiration
number
UINT32
Indicates the time after which the offer is no longer active. The value is the number of seconds since the Ripple Epoch.
Destination
string
Account ID
Only allowed if the
lsfSellToken
flag is set. Indicates theAccountID
that this sell offer is intended for (either a buyer or a broker). If present, only that account can accept the sell offer.OwnerNode
string
UINT64
Internal bookkeeping, indicating the page inside the owner directory where this token is being tracked. This field allows of the efficient deletion of offers.
NFTokenOfferNode
string
UINT64
Internal bookkeeping, indicating the page inside the token buy or sell offer directory, as appropriate, where this token is being tracked. This field allows of the efficient deletion of offers.
1.5. How does
NFTokenOffer
work?Unlike regular offers on XRPL, which are stored sorted by quality in an order book and are automatically matched by an on-ledger mechanism, an
NFTokenOffer
is not stored in an order book and will never be automatically matched or executed.A buyer must explicitly choose to accept an
NFTokenOffer
that offers to buy anNFToken
. Similarly, a seller must explicitly choose to accept a specificNFTokenOffer
that offers to buy anNFToken
object that they own.1.5.1. Locating
NFTokenOffer
objectsEach token has two directories, one containing offers to buy the token and the other containing offers to sell the token. This makes it easy to find
NFTokenOffer
for a particular token. It is expected that off-ledger systems will be used to retrieve, present, communicate and effectuate the creation, enumeration, acceptance or cancellation of offers. For example, a marketplace may offer intuitive web- or app-based interfaces for users.1.5.2.
NFTokenOffer
ReserveEach
NFTokenOffer
object costs the account placing the offer one incremental reserve. As of this writing the incremental reserve is 2 XRP. The reserve can be recovered by cancelling the offer. The reserve is also recovered if the offer is accepted, which removes the offer from the XRP Ledger.1.5.3.
NFTokenOffer
TransactionsThere are three defined transactions:
NFTokenCreateOffer
NFTokenCancelOffer
NFTokenOfferAccept
All three transactions have the generic set of transaction fields, some of which may be ommitted from this proposal for the sake of clarity.
1.5.4.
NFTokenCreateOffer
transactionThe
NFTokenCreateOffer
transaction creates either a newSell
offer for anNFToken
owned by the account executing the transaction or a newBuy
offer forNFToken
owned by another account.Each offer costs one incremental reserve.
1.5.4.1. Fields
TransactionType
string
UINT16
Indicates the new transaction type
NFTokenCreateOffer
. The integer identifier is27
.Account
string
AccountID
Indicates the
AccountID
of the account that initiated the transaction.Owner
string
AccountID
Indicates the
AccountID
of the account that owns the correspondingNFToken
.Account
(since an offer to buy a token one already holds is meaningless).Account
(since an offer to sell a token one doesn't already hold is meaningless).Flags
number
UINT32
A set of flags that specifies options or controls the behavior of the transaction. This proposal only defines one flag at this time:
Note that the
Flags
field includes both transaction-specific and generic flags. This proposal only specifies the transaction-specific flags; all currently valid generics flags (e.g.,tfFullyCanonicalSig
) are applicable, but not listed here.The transactor SHOULD NOT allow unknown flags to be set.
NFTokenID
string
Hash256
Identifies the
NFTokenID
of theNFToken
object that the offer references.Amount
Currency Amount
AMOUNT
Indicates the amount expected or offered for the
Token
.The amount must be non-zero, except where this is an offer is an offer to sell and the asset is XRP; then it is legal to specify an amount of zero, which means that the current owner of the token is giving it away, gratis, either to anyone at all, or to the account identified by the
Destination
field.Expiration
number
UINT32
Indicates the time after which the offer will no longer be valid. The value is the number of seconds since the Ripple Epoch.
Destination
string
AccountID
Only valid if the
tfSellToken
flag is set. If present, indicates that this offer may only be accepted by the specified account (either a broker or a buyer). Attempts by other accounts to accept this offer MUST fail.If succesful,
NFTokenCreateOffer
transaction results in the creation ofNFTokenOffer
object.1.5.5.
NFTokenCancelOffer
transactionThe
NFTokenCancelOffer
transaction can be used to cancel existing token offers created usingNFTokenCreateOffer
.1.5.5.1 Permissions
An existing offer, represented by an
NFTokenOffer
object, can be cancelled by:NFTokenOffer
;Destination
field of theNFTokenOffer
, if one is present; orNFTokenOffer
specifies an expiration time and the close time of the parent ledger in which theNFTokenCancelOffer
is included is greater than the expiration time.This transaction removes the listed
NFTokenOffer
object from the ledger, if present, and adjusts the reserve requirements accordingly. It is not an error if theNFTokenOffer
cannot be found, and the transaction should complete successfully if that is the case.Fields
TransactionType
string
UINT16
Indicates the new transaction type
NFTokenCancelOffer
. The integer identifier is28
.NFTokenOffers
array
VECTOR256
An array of ledger entry IDs, each identifying an
NFTokenOffer
object, which should be cancelled by this transaction.It is an error if an entry in this list points to an object that is not an
NFTokenOffer
object. It is not an error if an entry in this list points to an object that does not exist.1.5.6.
NFTokenOfferAccept
transactionThe
NFTokenOfferAccept
transaction is used to accept offers tobuy
orsell
anNFToken
. It can either:direct
mode.NFToken
and the other offering to sell the sameNFToken
, to be accepted in an atomic fashion. This is calledbrokered
mode.1.5.6.1. Brokered vs. Direct Mode
The mode in which the transaction operates depends on the presence of the
NFTokenSellOffer
andNFTokenBuyOffer
fields of the transaction:NFTokenSellOffer
NFTokenBuyOffer
If neither of those fields is specified, the transaction is malformed and shall produce a
tem
class error.The semantics of
brokered
mode are slightly different than one indirect
mode: The account executing the transaction functions as a broker, bringing the two offers together and causing them to be matched but does not acquire ownership of the involved NFT, which will, if the transaction is successful, be transferred directly from the seller to the buyer.1.5.6.2. Execution Details
1.5.6.2.1. Direct Mode
In
direct
mode,NFTokenOfferAccept
transaction MUST fail if:NFTokenOffer
against whichNFTokenOfferAccept
transaction is placed is an offer tobuy
the
NFToken
and the account executing theNFTokenOfferAccept
is not, at the time of execution, the current owner of the correspondingNFToken
.NFTokenOffer
against whichNFTokenOfferAccept
transaction is placed is an offer tosell
the
NFToken
and was placed by an account which is not, at the time of execution, the current owner of theNFToken
.NFTokenOffer
against whichNFTokenOfferAccept
transaction is placed is an offer tosell
the
NFToken
and was placed by an account which is not, at the time of execution, theAccount
in the recipient field of theNFTokenOffer
, if there exist one.NFTokenOffer
against whichNFTokenOfferAccept
transaction is placed specifies anexpiration
time and the close time field of the parent of the ledger in which the transactionwould be included has already passed.
NFTokenOffer
against whichNFTokenOfferAccept
transaction is placed to buy or sell theNFToken
is owned by the account executing the
NFTokenOfferAccept
.If the transaction is executed successfully then:
NFTtoken
will change ownership, meaning that the token will be removed from theNFTokenPage
of the existingowner
and be added to theNFTokenPage
of the newowner
.NFTokenOffer
. If the correspondingNFToken
offer specifies aTransferRate
, then theissuer
receives the specified percentage, with the balance going to the seller of theNFToken
.1.5.6.2.2. Brokered Mode
In
brokered
mode,NFTokenOfferAccept
transaction MUST fail if:buy
NFTokenOffer
against whichNFTokenOfferAccept
transaction is placed is owned by the account executing the transaction.sell
NFTokenOffer
against whichNFTokenOfferAccept
transaction is placed is owned by the account executing the transaction.NFToken
is not, at the time of execution the current owner of the correspondingNFToken
.buy
orsell
) specifies anexpiration
time and the close time field of the parent of the ledger in which the transaction would be included has already passed.1.5.6.3. Fields
TransactionType
string
UINT16
Indicates the new transaction type
NFTokenOfferAccept
. The sequence number of a previousNFTokenCreateOffer
transaction. The integer identifier is29
.NFTokenSellOffer
string
UINT256
Identifies the
NFTokenOffer
that offers to sell theNFToken
.📝 In direct mode this field is optional, but either
NFTokenSellOffer
orNFTokenBuyOffer
must be specified. In brokered mode, bothNFTokenSellOffer
andNFTokenBuyOffer
MUST be specified.NFTokenBuyOffer
string
UINT256
Identifies the
NFTokenOffer
that offers to buy theNFToken
.📝 In direct mode this field is optional, but either
NFTokenSellOffer
orNFTokenBuyOffer
must be specified. In brokered mode, bothNFTokenSellOffer
andNFTokenBuyOffer
MUST be specified.NFTokenBrokerFee
object
orstring
AMOUNT
This field is only valid in brokered mode and specifies the amount that the broker will keep as part of their fee for bringing the two offers together; the remaining amount will be sent to the seller of the
NFToken
being bought. If specified, the fee must be such that, prior to accounting for the transfer fee charged by the issuer, the amount that the seller would receive is at least as much as the amount indicated in the sell offer.This functionality is intended to allow the
owner
of anNFToken
to offer their token for sale to a third party broker, who may then attempt to sell theNFToken
on for a larger amount, without the broker having to own theNFToken
or custody funds.📝 If both offers are for the same asset, it is possible that the order in which funds are transferred might cause a transaction that would succeed to fail due to an apparent lack of funds. To ensure deterministic transaction execution and maximimize the chances of successful execution, this proposal requires that the account attempting to buy the
NFToken
is debited first and that funds due to the broker are credited before crediting the seller or issuer.:note: In brokered mode, The offers referenced by
NFTokenBuyOffer
andNFTokenSellOffer
must both specify the sameNFTokenID
; that is, both must be for the sameNFToken
.Beta Was this translation helpful? Give feedback.
All reactions