-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
EIP 821: Distinguishable Assets Registry (Contract for NFTs) #821
Comments
As far as I understand it from the implementation, assetByIndex will constantly change (slightly) as users trade their assets around (since the last item in their asset array is moved around). Is there any real need for the assetByIndex function then since that ordering is not very useful? An indexOfAsset(assetId) function seems more necessary as the main way UI is going to display your assets is to use something like the following:
Edit:
|
I don't think create() (and possibly update()) should necessarily be part of a standard ERC821 token. They seem optional, and for many assets, their creation probably won't be a publicly accessible function and updating might not be relevant for that contract. Edit: |
Thanks @ImAllInNow!
|
Regarding
The rule of the owner being the one authorized to make the changes is policy. You're right, it should not be part of the standard (same as before, I'll keep the mechanism as internal so the implementor can decide on the policy) |
Last note on I'll add a note that UIs should list the items in sorted order, or keep their own information based on the transfer logs or user preferences. |
@eordano You're right about update. I was getting it confused with updating the assetId rather than the data associated with the assetId. |
For those coming straight to ERC821 @eordano has written a distinguishable asset manifesto: https://blog.decentraland.org/the-non-fungibles-revolution-of-2018-304270525b05 |
My original thinking for (unique) assets was given existing ERC20 support in wallets was to create assets that are ERC20 compatible, rather than get wallets to support (unique) assets but if we can get enough support for a unique assets standard for wallets to implement, then all the better. |
Cost ERC821 meta data CUD Send |
Thanks for the comments, @abcoathup! Please note that I've updated the body of the proposal to include as much detail as I thought necessary
|
@eordano rather than Suggest reaching out to wallets and dApp browsers (e.g. the likes of MetaMask, Toshi, Status.im and Cipher Browser) for input on logo specifications. |
Is there a need for both Should all functions that accept an |
Discussion comes from #721 throwing on My take on this is that both are valid use cases... that you might want to save some gas by just calling The other functions that accept an assetId are not relevantly modified by this behavior, except maybe on the case of |
I'll expand later, but for the time being:
|
Lots of good thinking has gone into this. Decentraland brings a perspective to NFTs that we don't have at CryptoKitties. Thanks for bringing this to the community, @eordano! I'm confused as to why you think this needs to be an whole new standard, tho. I don't know about anyone else, but I don't consider ERC-721 as finalized, and I'm not sure it's appropriate to have a whole new standard that is largely the same. I appreciate that I've been a bad steward of ERC-721 for the last few weeks, and I can see how you might be frustrated by the lack of forward progress, but I would rather we find a way to move forward with one standard, rather than two. I mean, it's kind of the point of standards! 😅 |
Hey Dieter, I thought this was a better way to express the wholeness of the changes I was proposing (as you see, they are quite a lot). The three things were I think we've got completely different approaches are:
|
I like this! I haven't had a chance to integrate it into the 721 draft, however.
Unfortunately, we do disagree on this. I think that preventing user errors is a porcelain problem, not a plumbing problem. It's not the job of the filesystem to decide if the file you've named
EIP-820 is obviously very new, and looks pretty smart. So far as I can tell, it doesn't dictate anything about how an interface is structured, though, so it should be possible to use it for any standard past or future (even good ol' ERC-20). |
I agree with @dete that moving towards one NFT standard is preferable to multiple standards especially when this concept is new and has not been specifically supported by wallets/exchanges yet (that I know of). Definitely some good improvements suggested in the interface as described here. I like the use of an authorized operator and the idea of storing an index mapping to allow for a users assets to be stored as an array for easy retrieval through MetaMask without timing out when there are large numbers of assets (I recently noticed I can't retrieve all CryptoKitties for a user anymore :( ). I think deciding to prevent user transfer errors can be left up to the contract itself. It is a slight extra cost to make this check so if a contract wants to add to the gas cost of transfers to protect their users, that's great, but I don't think it necessarily needs to be mandated in the standard. |
I think regardless whether the UI should prevent the user from doing this (I think it should), it's still valuable to have another contract be notified with only requiring 1 transaction (from a plumbing perspective). |
Have you considered implementing something for lienholders? Let's say you have a plot of LAND that you are using as collateral for a loan, e.g. a mortgage. What if there was a way to allow the lender contract to transfer ownership of a plot of LAND without the land owner being able to revoke this access? |
I expect lienholders (new word for me!) to be a strong usecase for NFTs, especially as we move to a tokenized future. Think loans collateralized by fine art (or, hell, cryptokitties). Same with, say, propy houses. It'd be possible to create that functionality with a "wrapper" contract (like an escrow), but that's not entirely ideal. Could either be an optional extension to this EIP (nice) or another EIP (long process). |
I suggest that every ERC821 asset registry must register the "IAssetRegistry" interface with ERC820, that way contracts can automatically discern if a given NFT registry conforms to this standard. |
What is the operatorData argument of I'm kind of assuming it's just a blob of information that people can use when they need to communicate something not defined by the spec, but I feel like it needs more clarification. |
I feel like there's still room for an Calling Having In light of the numerous security compromises we've already seen (the DAO hack, Parity Multisig Wallets Rounds 1 and 2) building a standard on the assumption that contracts will always work as intended seems short sighted. An |
@AusIV the I think you're right about allowing |
@hyperfekt I think the correct way to go about this is that the DAR should register the |
I do not like what happened with erc721.org. There are several problems and inaccuracies:
I plan to have an updated specification at #721 soon which nearly matches the ideas on erc721.org. In addition, it will be an actual standard. Please get a hold of me and let's work on this together and at the same time recognize the benefits of collaboration and of respecting the EIP process. |
Hey @fulldecent -- I made erc721.org for the ETH Denver hackathon. erc721.org is currently being served using GH Pages from this GH repo: https://github.com/0xProject/erc721-website. The site could definitely use some improvements, so feel free to submit a PR if there are changes you'd like to see! As @dekz mentioned in the discussion under EIP-721, many in the community are worried by the fragmentation of NFT standards. It's currently extremely confusing and frustrating for new developers to get started, and equally frustrating for contributors like 0x and OpenZeppelin to be able to support the community when many people -- most of whom aren't even building NFTs or NFT-related projects -- are dragging their heels on committing to a standard or are continuing to expand the scope of this standard into unrelated areas. As shown on the site, large number of community members from all sides of the NFT ecosystem had a chance to meet at ETH Denver and agree to a minimum viable spec necessary to support the current digital NFT use case that also adds sufficient functionally to receive support from other teams like 0x, OpenZeppelin, and Toshi. We will all implement this spec or support for this spec in the immediate future. @recmo and @abandeali1 are currently working on PRs for a formal ERC and @spalladino's team is updating the OpenZeppelin solidity contracts to support this standard. We'd love to have the community's support in spreading and canonicalizing the final version of this standard. |
This process seems opaque. I wasn’t able to attend a three-day notice
meeting. Then at the meeting internet was not available. Now before minutes
being made available, I see a new proposed standard is deemed “final”,
outside the process of EIP. And all this is being done by a single entity.
I respect initiative. I’m here to help. Include me.
That website is missing parts. Let me digest, fix it and make some comments
please. I invited Jacob for a phone call tomorrow. Let’s get it done. And
let’s get it done right.
|
The 0x team has demonstrated a pattern of trying to run roughshod over any semblance of process to establishing a standard here. It is ultimately self defeating. |
It is unfortunate that not everyone was able to attend the working group. It was never intended to be some sort of official process. That being said, it was certainly not opaque. Almost all of the NFT projects were represented and, IMO, it was a huge relief to be able to communicate directly with these projects IRL rather than through this thread, which has become noisy and lacks focus. It was an incredibly productive session. We walked through the issues one by one, discussed potential solutions (most of which are already buried within this thread), and ensured that every project felt comfortable with a proposed solution before moving on. What we have converged on at erc721.org is a general interface that satisfies everyone's use cases and needs. |
@willwarren89 There are many projects that are not accounted for in your summary representation (including private, commercial B2B use cases)—this is not to make a value judgement on the significant contributions made by the hastily organized working group over the weekend. My only caution here would be towards the lack of participation in the well-established, community EIP process by this select cohort. Deviating from that established process only furthers the risk of fragmentation. |
For context, the plan is to work within the EIP process as a join effort by the stewards of 721 and 821. Regarding private, commercial, etc requirements, the plan (as I understand it) is to produce a standard that is as general as possible and allow additional features (like fine-grain access control, pull-payments, etc) as layers as additional EIP standards. |
The artifact of this meeting, erc721.org includes the statements that make this appear as an official process. To be clear. I am interpreting this as a good-faith effort to get shit done, with no intentional motive of excluding the community at large. Anyway, right now I am working on turning that website into an actual usable standard at #841. It is already pretty close. At that time (coming tonight or tomorrow) I will circle back here. Also I will seek to credit any authors at the top of the spec if I have lifted your words. Then I will propose that everyone come together on this under the name 721. I see 0x has purchased domain names with 721, so I think we can get this done. |
To be clear, this is the first time a diverse representation of the community has sat down together and actually worked on a NFT proposal as a group together. Let's try and get these Github issues back on track and see if they can be as productive as the Working group was. |
This works for us (RareBits, https://rarebits.io) and has our support. As an ERC721 marketplace, we have interacted with a lot of these contracts that are live and are supportive of this effort to standardize the implementation. While this doesn't include everything that the community will want eventually, it at least it locks in a "v1" API that devs can build against safely. |
Is my understanding correct that the intended process by the 'working group' is to now discuss their interface from the very beginning instead of continuing the work / understanding already done / come to here? This would include everything agreed upon at the meeting, since there is no discussion available for these decisions.
The argument for later extension seems to be omnipresent - are we certain this is actually feasible, and the interface published on erc721.org does not lock in things that could prevent some of the features currently being discussed? /cc @fulldecent |
Hello everyone. As promised, I have made significant changes at pull request #841. Cross post from #841 (comment) Major change implemented:
This addresses complaints from ETHDenver (0xproject is still preparing to release the notes. Please hurry up!):
In all, please help to review specifically the |
I just want to say I appreciate the effort of setting up that last minute meeting and getting it through. I hope you enjoy my latest update. Let's review, let's talk. The major departure is Now is a critical time because I think we can come together on this. FYI, I'm in New York time zone. So you can see I'm dedicated to getting this done, and getting it done right. |
@hyperfekt I do not support "v1". a) It is not a standard, you can't implement it b) it is incomplete. We have taken "v1" and with considerable effort, discussion and consensus building (from people that have identified skin in the game) turned it into a standard at #841. This was not too bad because "v1" is very similar to what we already had. Also, we have documented CONSIDERABLE amounts of rationale for all decisions. Many people are on the record saying that #841 is feasible. Additionally we have a baseline standard (required) and two optional add-ons (metadata and enumeration). We have also enumerated and thoroughly discussed many use cases. Even if we do not support them (functions for paying real estate taxes?) we have considered how those functions would be compatible with the standard. In summary: the standard has room to support many imagined use cases and we have documented it. |
We at OpenSea (https://opensea.io, an NFT marketplace) endorse this v1 API. At the EthDenver meet, the emphasis wasn't on finalizing the standard, but instead on establishing a name and location to send to devs who want to work with non-fungible tokens. This is important because many, many tokens haven't been following any standard at all, in part due to all these balkanized github EIPs. @tomhschmidt 's site is a step in the right direction |
@fulldecent |
I do not agree with https://erc21.org and I'm asking to get Decentraland's logo out of there (it's irresponsible to champion a standard without transfer security), but I've got the upmost respect for the 0x team. |
imo transfer security can/should be part of a secondary EIP that doesn't enforce a specific use-case onto a general standard |
@shrugs doesn't that defeat the purpose of security? I'm baffled about the idea of allowing a protocol to exist that can lead to loss of funds "because reasons". |
@eordano shouldnt the eip allow interoperability without enforceing specific use cases? If your token that you deploy needs an extra layer of security you should force unsafe/unwanted transactions to fail. As discussed at ethdenver this will still adhere to the api. |
There exist perfectly valid reasons to allow ERC20s to be sent to arbitrary addresses. For example, perhaps they represent debt. Or are tokens representing a "claim" against an address to signify KYC or something. This is even more relevant for NFTs. Sure, it's not the primary usecase, but that's not the point of a general standard. Transfer security can and should be part of a secondary standard that defines a method to enforce that receivers respect an interface that supports your transfer. In the case of ERC20 transfer security should be part of something like 223 (except ideally it would not be just talked about for a year without progress). 223 will never be finalized at this rate, so perhaps it's worth providing a simple, scoped EIP that adds optional transfer security to EIP20. |
I see your point but I dismiss it, as the use cases seem to me to be out of scope for the meaning of But I've only come this far and I'll agree to disagree. Like I said in private, I'm concerned about negligently championing a standard that leads to the loss of millions in value. It's not good craftsmanship, it's not ethical, and it might come with legal liability, given there's precedent of 5 million usd lost and you're in the position to improve it, but decidedly choose to go the other way. |
Updated the main text
|
aside: I don't expect any legal argument around this to stand up in court. Ethereum is a tool, just like a hammer, and that precedent has been set. If you're actually worried about legal implications of not including transfer security, that has everything to do with your specific implementation of the NFT standard rather than the standard itself. Unnecessarily restricting user behavior because of your perceived benefits is a very slippery slope, philosophically. Adding an The proposed solution is to create a general NFT standard and then augment it with additional standards for transfer security, specific role-based delegate standards, pull-transfers, metadata, and more. If the community works together on this, we champion for them all at the same time and result in the situation where:
(edit) I also want to point out that, in 721, you are 👍 regarding:
Which is very much counter to enforcing transfer security on the base interaction standard. The point is that we can't know right away if unsafe transfers are a feature or a bug. I think I've indicated that it certainly has the ability to be a feature, perhaps in ways we haven't thought of yet. And if it does end up being a specific feature, we'd need to create a new standard on top of this restrictive one, fragmenting the implementation space yet again. |
Another thing that crossed my mind with regard to transfer security: Account abstraction is coming with the constantinople hard fork, after which I expect we can see many people starting to use contracts as their primary wallets. Wallet contracts are generally structured such that they can proxy arbitrary transactions once those transactions have been validated. In general, they can do anything a key based account can do, but with their own rules around what conditions must be met first. My reading of this spec suggests that a multisig wallet which didn't implement onAssetReceived wouldn't be able to receive deeds, even though it was built to be able to handle arbitrary transactions. That may not be that big of a deal now, since account abstraction isn't here yet and most people will create such contracts after this proposal is finalized, but once lots of people are already using contracts as their daily wallets, adding functions that they have to implement in order to interact with broad classes of other contracts seems like a non-starter, because it would force people to migrate to new wallet contracts to support interaction with new standards. |
Summary
A Distinguishable Assets Registry (DAR for short) is a contract that tracks ownership of, and information about a set of assets that are distinguishable from each other, and are commonly refferred to as "NFTs", for "Non Fungible Tokens".
See https://github.com/decentraland/erc821 for a reference implementation.
See the "Revisions" section for a history of this ERC.
Abstract
Tracking the ownership of physical or digital distinguishable items on a blockchain has a broad range of applications, from virtual collectibles to physical art pieces. This proposal aims at standardizing a way to reference distinguishable assets along with the foreseeable required operations and interfaces for effective management of those assets on a blockchain.
Introduction
The number of virtual collectibles tracked on the Ethereum blockchain is rapidly growing, creating a demand for a more robust standard for distinguishable digital assets. This proposal suggests improvements to the vocabulary used to refer to such assets, and attempts to provide a solid and future-proof reference implementation of the basic functionality needed. This EIP also proposes better naming conventions and vocabulary for the different components of the NFT economy: the assets, the NFTs (representations of those assets on the blockchain), the DARs (the contracts registering such assets), distinguishing ownership from holding addresses, and more.
See also: ERC #721, ERC #20, ERC #223, and ERC #777.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
Specification
A non-fungible token (NFT) is a distinguishable asset that has a unique representation as a register in a smart contract. This proposal specifies such contracts, referenced as Distinguishable Asset Registries, or DARs. NFTs MAY also be reffered to as "deeds".
DARs can be identified by the blockchain in which they were deployed, and the 160-bit address of the contract instance. NFTs are identified by an ID, a 256 bit number, which MAY correspond to some cryptographic hash of the non-fungible's natural key.
NFTs SHOULD be referenced by a URI that follows this schema:
The NFT's ID SHOULD have a hint that helps to decode it. For instance, if the encoding of the number is in hexadecimal, the NFT’s ID SHOULD start with
0x
. The DAR's address SHOULD follow the checksum by casing as proposed on #55.Some common names for Ethereum blockchains are:
ethereum
,livenet
, ormainnet
ropsten
,testnet
kovan
rinkeby
Some examples of NFT URIs follow:
Every NFT MUST have a
owner
address associated with it. NFTs associated with the null address are assumed non-existent or destroyed.An owner MAY assign one or multiple
operator
addresses. These addresses will be able to transfer any asset of the owner.DARs MUST trigger
Transfer
events every time a NFT'sowner
changes. This might happen under three circumstances:from
value of theTransfer
event MUST be the zero address.to
value of theTransfer
event MUST be the zero address.Transfer
events SHALL NOT simultaneously have a zero value in both thefrom
andto
fields (this means, the sameTransfer
event can't both create and destroy a token).Associated Metadata
Metadata associated with each asset is out of scope for this standard.
DAR global methods
totalSupply():uint256
Return the total amount of assets under this DAR. This method SHALL NOT throw.
supportsInterface(bytes8 interfaceId):bool
This method returns
true
if theinterfaceId
is a supported interface (165, corresponding to 0x01ffc9a7, or 821, corresponding to 0x959d7abb). This method SHALL NOT throw.NFT getter methods
exists(uint256 assetId):bool
This method returns a boolean value,
true
if the asset identified with the givenassetId
exists under this DAR. This method SHALL NOT throw.ownerOf(uint256 assetId):address
This method returns the
address
of the owner of the NFT. This method SHALL NOT throw. If theassetId
does not exist, the return value MUST be the null address.Owner-centric getter methods
balanceOf(address owner):uint256
This method returns the amount of NFTs held by the
owner
address under this DAR. This method MUST not throw.assetByIndex(address owner, uint256 index):uint256
This method returns the ID of the
index
th NFT held by theowner
address under this DAR, when all the IDs of the NFTs held by such address are stored as an array.This method MUST throw if
assetCount(owner) >= index
. This method MUST throw ifindex >= 2^128
.The DAR MAY change the order assigned to any NFT held by a particular address.
This method is expected to be used by other contracts to iterate through an
owner
's assets. Contracts implementing such iterations SHOULD be aware of race conditions that might occur, if this iteration happens over multiple transactions.assetsOf(address owner):uint256[]
This method returns an array of IDs of the NFTs held by
owner
. This method SHALL NOT throw.Operator getters
isAuthorizedBy(address operator, address owner):bool
This method returns
true
ifowner
has called the methodauthorize
with parameters(operator, true)
and has not calledauthorize(operator, false)
afterwards. This method returnsfalse
otherwise.This method MUST return
true
ifoperator == owner
.This method SHALL NOT throw.
isApprovedFor(address operator, uint256 assetId):bool
This method returns
true
ifowner
has called the methodapprove
with parameters(operator, assetId)
and has not called it with a different operator value afterwards. This method returnsfalse
otherwise.This method MUST return
true
ifoperator == owner
.This method SHALL NOT throw.
Transfers
transfer(address to, uint256 assetId, bytes userData, bytes operatorData)
Transfers holding of the NFT referenced by
assetId
fromownerOf(assetId)
to the addressto
.to
SHALL NOT be the zero address. Ifto
is the zero address, the call MUST throw.to
SHALL NOT beownerOf(assetId)
. If this condition is met, the call MUST throw.isAuthorizedBy(msg.sender, ownerOf(assetId))
MUST return true as a precondition.This means that the
msg.sender
MUST beownerOf(assetId)
or an authorized operator.If the NFT referenced by
assetId
does not exist, then the call MUST throw.If there was any single authorized operator (see the
approve()
method below), this authorization MUST be cleared.If the call doesn't throw, it triggers the event
Transfer
with the following parameters:ownerOf(assetId)
before the callto
argumentassetId
argumentmsg.sender
userData
argumentoperatorData
argumentIf
to
is a contract's address, this call MUST verify that the contract can receive the tokens. In order to do so, the method MUST do a #165 check for support to handle tokens to the target contract.The implementation for the receiver is as follows:
If the
supportsInterface
method call fails, the transfer must be reversed and this call MUST throw. Otherwise, the methodonAssetReceived
MUST be invoked with the corresponding information, after the asset has been transferred.transfer(address to, uint256 assetId, bytes userData)
Shorthand method that MUST be equivalent to calling
transfer(to, assetId, userData, EMPTY_BYTES)
.transfer(address to, uint256 assetId)
Shorthand method that MUST be equivalent to calling
transfer(to, assetId, EMPTY_BYTES, EMPTY_BYTES)
.transferFrom(address from, address to, uint256 assetId, bytes userData, bytes operatorData)
Transfers holding of the NFT referenced by
assetId
fromownerOf(assetId)
to the addressto
, ifffrom == ownerOf(assetId)
.After checking that the asset is owned by the
from
address, this method MUST behave exactly as callingtransfer(to, assetId, EMPTY_BYTES, EMPTY_BYTES)
.transferFrom(address from, address to, uint256 assetId, bytes userData)
Shorthand method that MUST be equivalent to calling
transferFrom(to, assetId, userData, EMPTY_BYTES)
.transferFrom(address from, address to, uint256 assetId)
Shorthand method that MUST be equivalent to calling
transferFrom(to, assetId, EMPTY_BYTES, EMPTY_BYTES)
.Authorization
authorize(address operator, bool authorized)
If
authorized
istrue
, allowsoperator
totransfer
any NFT held bymsg.sender
.This method MUST throw if
operator
is the zero address. This method MUST throw ifauthorized
is true andoperator
is already authorized by the sender. This method MUST throw ifauthorized
is false andoperator
is unauthorized.This method MUST throw if
msg.sender == operator
.This method MUST trigger an
AuthorizeOperator
event if it doesn't throw.approve(address operator, uint256 assetId)
Allow
operator
totransfer
an asset without delegating full access to all assets.Only the
owner
of an asset can call this method. Otherwise, the call MUST fail.Only one address can receive
approval
at the same time. Clearing approval for a transfer can be done by setting theoperator
value to the zero address.This method MUST trigger an
Approve
event if it doesn't throw.Events
Interfaces
Implementation
https://github.com/decentraland/erc821
Revisions
transferFrom
operator
from public facing interfacesholder
->owner
to use the most common nameapprove
to approve individual assets to be transferredmsg.sender
being the managerERC820
andIAssetHolder
interface checkIAssetOwner
forIAssetHolder
to reflect that another contract might hold tokens for onetransfer
textdecimals
for more ERC20 compatibilityonAssetReceived(...)
is implemented.isERC821
flag to detect support.holder
toowner
.transfer
:to
MUST NOT beholderOf(assetId)
safeAssetData
methodtransfer
: it MUST throw if the asset does not exist.Copyright
Copyright and related rights waived via CC0.
The text was updated successfully, but these errors were encountered: