-
Notifications
You must be signed in to change notification settings - Fork 14
NFT Standard #62
Comments
We are grateful to the TonWhales developers for collaborating on the current draft of the standard 🤝 |
This comment was marked as off-topic.
This comment was marked as off-topic.
What is the reason to expect |
I have a few points:
Thank you. |
Artificial example is https://emelyanenkok.github.io/nft-standard-draft/ where each nft stores it's own image onchain and nft-collection stores common png-header as well as uri prefix. It is worth noting, by the way, that TVM execution is highly local (almost no context is used). That means that it is possible to download code/storage of collection contract and then run |
Our thoughts on these 2 questions are actually coupled: |
Thank you, @EmelyanenkoK, for your clarification. I got the idea. Following this approach, it's is essential for service contracts (e.g., an auction) to know where the token came from. Please correct me if I'm missing something. |
Hey🤗 Would you consider allowing the contract to also mint fungible tokens? (I'm referring to the collection contract design by the way) |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as spam.
This comment was marked as spam.
|
This comment was marked as off-topic.
This comment was marked as off-topic.
Will it be useful to store the history of NFT changes, so editing will not change the content of current the NFT, but will provide a new one with new data? |
Will there be any cases where content of the NFT will not be acceptable by the community ? For example any porn content, some kind of nazi propaganda or drugs adware ? |
Навряд ли надо блокировать само содержимое NFT, скорее будет блокироваться его распространение на площадках, которые смогут блокировать адрес этого NFT. Google Translate to English: |
What about bulk transfer? |
Его собственность, которую как минимум нужно соответственно промаркировать ... Как минимум 18+ ... (adult content) |
Маркировать NFT могут как раз площадки, на которых они будут размещаться. Никто не может обязать меня ставить маркировку на своем NFT. Например Ютуб и соцсети сами фильтруют такой контент. Google Translate to English: |
Предлагаю добавить в NFT возможность просмотра контента, ограниченного доступа и доступа по подписке списку указанных адресов, которые владелец NFT сможет менять (аренда NFT по установленной цене). Google Translate to English: |
А как насчёт вируса ? На сколько я понял payload - всего лишь набор байтов никаким форматом не ограниченный. |
@konak @DocInn Please use English.
Each NFT is separate contract and thus should be transferred by distinct message. At the same time wallet or contracts may send multiple messages per transactions so it is possible to send request to change owners of many NFT.
What is the usecase of notification owner about unsuccessful attempt to move his NFT? @LaDoger |
Распишу ещё желательные возможности NFT в сети TON.
Google Translate to English:
|
One more thing. |
@KarabutinAlex |
Standard update:
|
Pretty cool stuff, guys! I have some thoughts on smart contracts in TON and NFT contracts in specific: I think we need some kind of mechanic's to distinguish some contracts from others. I see three possible solutions for this stuff: 1 - each contract that wats to follow introspection mechanics implements some well-known GET method which returns either TL-B schema of it's interface or hash of that schema or some other data which uniquely defines interfaces of contract. 2 - instead of well-known GET method we can put information about contract interface at the beginning of smart contract data cell. 3 - We can use some indirect signs to distinguish contracts. For example we can locally run contract and test it against list of GET and internal methods that contract should implement. Since 1-2 don't actually guarantee anything - we can use some sort of combination of 1/2 + 3. |
I don't know much about smart contracts, but how do I know what the auction contract will do with my nfts? |
Transfers in ERC-721 may be initiated by:
Current standart allows only transfers initiated by the owner. |
Standard update:
|
Standard update:
|
Looks like we need function Also |
|
Potential nft-sale contract deadlock:
In that case nft_owner_address of the nft-sale contract will be null, so it will be waiting for message from the NFT, but the NFT will not be able to send message to the nft-sale contract because it's already changed its owner to nft-sale |
forward_payload - optional custom data that should be sent to the new owner. Word "optional" creates problem for understanding by some developers. they forget controlling bit for Either |
Description of |
Summary
A standard interface for non-fungible tokens.
Motivation
A standard interface will greatly simplify interaction and display of different entities representing right of ownership.
NFT standard describes:
Specification
The NFT collection and each NFT item are separate smart contracts.
Example: if you release a collection that contains 10 000 items, then you will deploy 10 001 smart contracts.
NFT item smart contract
Must implement:
Internal message handlers
1.
transfer
Request
TL-B schema of inbound message:
transfer#5fcc3d14 query_id:uint64 new_owner:MsgAddress response_destination:MsgAddress custom_payload:(Maybe ^Cell) forward_amount:(VarUInteger 16) forward_payload:(Either Cell ^Cell) = InternalMsgBody;
query_id
- arbitrary request number.new_owner
- address of the new owner of the NFT item.response_destination
- address where to send a response with confirmation of a successful transfer and the rest of the incoming message coins.custom_payload
- optional custom data.forward_amount
- the amount of nanotons to be sent to the new owner.forward_payload
- optional custom data that should be sent to the new owner.Should be rejected if:
message is not from current owner.
there is no enough coins (with respect to NFT own storage fee guidelines) to process operation and send
forward_amount
.After processing the request, the contract must send at least
in_msg_value - forward_amount - max_tx_gas_price
to theresponse_destination
address.If the contract cannot guarantee this, it must immediately stop executing the request and throw error.
max_tx_gas_price
is the price in Toncoins of maximum transaction gas limit of NFT habitat workchain. For the basechain it can be obtained fromConfigParam 21
fromgas_limit
field.Otherwise should do:
change current owner of NFT to
new_owner
address.if
forward_amount > 0
send message tonew_owner
address withforward_amount
nanotons attached and with the following layout:TL-B schema:
ownership_assigned#05138d91 query_id:uint64 prev_owner:MsgAddress forward_payload:(Either Cell ^Cell) = InternalMsgBody;
query_id
should be equal with request'squery_id
.forward_payload
should be equal with request'sforward_payload
.prev_owner
is address of the previous owner of this NFT item.If
forward_amount
is equal to zero, notification message should not be sent.Send all excesses of incoming message coins to
response_destination
with the following layout:TL-B schema:
excesses#d53276db query_id:uint64 = InternalMsgBody;
query_id
should be equal with request'squery_id
.2
get_static_data
Request
TL-B schema of inbound message:
get_static_data#2fcb26a2 query_id:uint64 = InternalMsgBody;
query_id
- arbitrary request number.should do:
Send back message with the following layout and send-mode
64
(return msg amount except gas fees):TL-B schema:
report_static_data#8b771735 query_id:uint64 index:uint256 collection:MsgAddress = InternalMsgBody;
query_id
should be equal with request'squery_id
.index
- numerical index of this NFT in the collection, usually serial number of deployment.collection
- address of the smart contract of the collection to which this NFT belongs.Get-methods
get_nft_data()
returns(int init?, int index, slice collection_address, slice owner_address, cell individual_content)
init?
- if not zero, then this NFT is fully initialized and ready for interaction.index
- numerical index of this NFT in the collection. For collection-less NFT - arbitrary but constant value.collection_address
- (MsgAddress) address of the smart contract of the collection to which this NFT belongs. For collection-less NFT this parameter should be addr_none;owner_address
- (MsgAddress) address of the current owner of this NFT.individual_content
- if NFT has collection - individual NFT content in any format;if NFT has no collection - NFT content in format that complies with standard TIP-64.
NFT Collection smart contract
It is assumed that the smart contract of the collection deploys smart contracts of NFT items of this collection.
Must implement:
Get-methods
get_collection_data()
returns(int next_item_index, cell collection_content, slice owner_address)
next_item_index
- the count of currently deployed NFT items in collection. Generally, collection should issue NFT with sequential indexes (see Rationale(2) ).-1
value ofnext_item_index
is used to indicate non-sequential collections, such collections should provide their own way for index generation / item enumeration.collection_content
- collection content in a format that complies with standard TIP-64.owner_address
- collection owner address, zero address if no owner.get_nft_address_by_index(int index)
returnsslice address
Gets the serial number of the NFT item of this collection and returns the address (MsgAddress) of this NFT item smart contract.
get_nft_content(int index, cell individual_content)
returnscell full_content
Gets the serial number of the NFT item of this collection and the individual content of this NFT item and returns the full content of the NFT item in format that complies with standard TIP-64.
As an example, if an NFT item stores a metadata URI in its content, then a collection smart contract can store a domain (e.g. "https://site.org/"), and an NFT item smart contract in its content will store only the individual part of the link (e.g "kind-cobra").
In this example the
get_nft_content
method concatenates them and return "https://site.org/kind-cobra".Implementation example
https://github.com/ton-blockchain/token-contract/tree/main/nft
Rationale
"One NFT - one smart contract" simplifies fees calculation and allows to give gas-consumption guarantees.
NFT collection with sequential NFT index provide easy way of association and search of linked NFTs.
Division of NFT content into individual and common (collection) part allows to deduplicate storage as well as cheap mass update.
Why not a single smart contract with a token_id -> owner_address dictionary?
Unpredictable gas consumption
In TON, gas consumption for dictionary operations depends on exact set of keys.
Also, TON is an asynchronous blockchain. This means that if you send a message to a smart contract, then you do not know how many messages from other users will reach the smart contract before your message.
Thus, you do not know what the size of the dictionary will be at the moment when your message reaches the smart contract.
This is OK with a simple wallet -> NFT smart contract interaction, but not acceptable with smart contract chains, e.g. wallet -> NFT smart contract -> auction -> NFT smart contract.
If we cannot predict gas consumption, then a situation may occur like that the owner has changed on the NFT smart contract, but there were no enough Toncoins for the auction operation.
Using smart contracts without dictionaries gives deterministic gas consumption.
Does not scale (becomes a bottleneck)
Scaling in TON is based on the concept of sharding, i.e. automatic partitioning of the network into shardchains under load.
The single big smart contract of the popular NFT contradicts this concept. In this case, many transactions will refer to one single smart contract.
The TON architecture provides for sharded smart contracts(see whitepaper), but at the moment they are not implemented.
Why are there no "Approvals"?
TON is an asynchronous blockchain, so some synchronous blockchain approaches are not suitable.
You cannot send the message "is there an approval?" because the response may become irrelevant while the response message is getting to you.
If a synchronous blockchain can check
alowance
and if everything is OK dotransferFrom
in one transaction, then in an asynchronous blockchain you will always need to send atransferFrom
message at random, and in case of an error, catch the response message and perform rollback actions.This is a complex and inappropriate approach.
Fortunately, all cases that arose during the discussion can be implemented by a regular transfer with notification of the new owner. In some cases, this will require an additional smart contract.
The case when you want to place NFT on several marketplaces at the same time is solved by creating auction smart contracts that first accept payment, and then NFT is sent to one of auction smart contracts.
Why are there no obligatory royalties to the author from all sales?
In the process of developing this idea, we came to the conclusion that it is possible to guarantee royalties to the author from absolutely any sale on the blockchain only in 1 case:
All transfers must be carried out through an open long-term auction, and other types of transfers are prohibited.
If you want to transfer NFT to yourself to another wallet, then you need to start an auction and win it.
Another variation of this scheme is to make all transfers chargeable.
By prohibiting the free transfer of tokens, we make tokens inconvenient in many cases - the user simply updated the wallet, the user wants to donate NFT, the user wants to send NFT to some smart contract.
Given the poor usability and that NFTs are a general concept and not all of them are created for sale - this approach was rejected.
Standard extensions
The functionality of the basic NFT standard can be extended:
NFTRoyalty (Release Candidate)
NFTBounceable (Draft)
NFTEditable (Draft)
NFTUpgradable (Draft)
TL-B schema
Tags were calculated via tlbc as follows (request_flag is equal to
0x7fffffff
and response flag is equal to0x80000000
):crc32('transfer query_id:uint64 new_owner:MsgAddress response_destination:MsgAddress custom_payload:Maybe ^Cell forward_amount:VarUInteger 16 forward_payload:Either Cell ^Cell = InternalMsgBody') = 0x5fcc3d14 & 0x7fffffff = 0x5fcc3d14
crc32('ownership_assigned query_id:uint64 prev_owner:MsgAddress forward_payload:Either Cell ^Cell = InternalMsgBody') = 0x85138d91 & 0x7fffffff = 0x05138d91
crc32('excesses query_id:uint64 = InternalMsgBody') = 0x553276db | 0x80000000 = 0xd53276db
crc32('get_static_data query_id:uint64 = InternalMsgBody') = 0x2fcb26a2 & 0x7fffffff = 0x2fcb26a2
crc32('report_static_data query_id:uint64 index:uint256 collection:MsgAddress = InternalMsgBody') = 0xb771735 | 0x80000000 = 0x8b771735
Changelog
01 Feb 2022
02 Feb 2022
04 Feb 2022
08 Feb 2022
11 Feb 2022
30 Jul 2022
The text was updated successfully, but these errors were encountered: