Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.Sign up
ERC-998 Composable Non-Fungible Token Standard #998
The latest code is in the EIP and reference implementation
A standard extension for any non-fungible token to own another non-fungible ERC-721 or fungible ERC-20 tokens. Transferring the token composition means transferring the entire hierarchy of items. For example, a cryptokitty may own a scratching post and a feeding dish; the dish may contain some amount of fungible “chow” tokens. If I sell the cryptokitty, I sell all of the belongings of the cryptokitty.
ERC998ERC721 top-down composable tokens that receive, hold and transfer ERC721 tokens
For more details on the reference implementation, visit the EIP.
I’ve presented a new standard for composable non-fungible tokens, ERC-998, that allows for the ownership of ERC-998, ERC-721 and ERC-20 tokens. This allows standard assets to be composed into complex compositions and traded using a single transfer. The additional functionality that can be added to a non-fungible token based on the presence of specific child tokens is open for exploration. I believe that standard interfaces for non-fungible and fungible assets to be composed and act upon one another is an exciting new area for the Ethereum community to explore and I look forward to seeing the work.
LATEST: EIP with reference implementation code
Not too different from the proposed mapping:
However not dealing with the same contract with parents and children being simply related key to key as is the case with #994.
Could it be
This was an edit, but then grew so I'll post again:
I guess for fungible you want it to be an integer.
Alternatively the whole thing on it's head so that one child has one parent as is the case with #994.
edit: Although that then breaks when you're trying to figure out where a fungible is held.
I see your point about the child tokenId being overwritten, that's a pain.
I had several approaches to this and I knew this wasn't perfect. You are right that a child contract will only be able to have one ERC-721 child. Darn.
A strict requirement of this proposal will be NOT requiring any changes to children that are already ERC-721 or ERC-20, meaning they won't have to upgrade to be a child of a composite.
Another approach was to keep the mapping:
And upgrade to a pseudo unique address for ERC-721 children:
Note: this is actually how the EVM generates smart contract addresses, using the hash of address + nonce as a bytes20 address type.
In this way we have a pseudo unique address for every child token.
We will have to adopt your bookkeeping method 0 means no child and 1 means child exists.
I really wanted to reduce the need for a deep mapping as in your proposed solution, although my unique address generation pushes a bit more computation and gas fees onto the miners and users.
This would have to be calculated to transfer a child token as well, like so:
Thoughts on this @mryellow?
Interesting, so it's
I was thinking a lot of the issues go away when dealing with non-fungible or fungibles independently. It's always this bit where you have to start thinking about using "tokenId" index
Perhaps the neatest solution is to not attempt to deal with them in the same variable, but storing differently once you know what type you're dealing with. Not sure how best to represent anything like that semantically though. Could add a boolean for
I think you avoid it when dealing with fungibles. So in the fungible functions, simply use the fungible contract address. There's no need for extra computation in the fungibles functions.
Could be possible to go with a completely new mapping for non-fungibles and deal with them seperately.
And still use the pseudo address construction for dealing with NFTs to ensure a unique address per NFT.
Another thought on this concept, ERC: Ethereum Claims Registry #780 features some prior work which might be informative:
However would this add anything or is the
Would anyone ever want to use the
My feeling on this, and why I refer to is at "pseudo address creation" is because it is analogous to how smart contract addresses are generated given the nonce of the smart contract.
So here we are creating an address for every NFT based on the contract address and tokenId of the NFT. This is exactly the same as if every NFT were deployed as a new contract from the main contract.
This is a great start, thanks. Like the idea of pseudo-addresses for child tokens. Have a bunch of thoughts. Here're three major points.
As you said, I think this is a preferred solution. I don't think it's a good idea to have one mapping for two different standards. It adds complexity (and fragility), adds unexpected behaviors, makes it harder for the wallets to process two different types. Wallets actually don't know the type beforehand - how would they know what token is that without guessing that through presence of the methods, etc? To me that's the biggest problem that I don't see how to resolve without splitting. Token type needs to be defined very explicitly.
So fungiblePossessions and nonfungiblePossessions may be more appropriate, with comments explicitly saying what standards to they support (ERC20+ERC677 and ERC721 respectively).
Also, more like a suggestion. "children" naming sounds a bit off for ERC20. It's more like stuff that belongs to this token. Maybe possessions would be better, or something like that. Nit.
Hello everybody and thanks @mattlockyer for creating this ERC. I was thinking about something like this for over a month, happy to see it brought to attention of a broader community.
My initial idea was very similar to this, that you embed such functionality as an extension to ERC721, and your ERC998 contract would be an owner of some ERC721 tokens (from the perspective of owned token) while keeping information that the true owner is a token this contract itself keeps track of.
I see some problems with such approach. The most important one being that if you have a chain of tokens from different ERC998 contracts, as a user you will have hard time understanding what contract you need to call to transfer a CryptoKitty that is owned by a DogERC998 token that is owned by PersonERC998 token that you own. I might be wrong here, but my intuition tells me you would have to call PersonERC998 and pass it 2 arrays of all contracts and tokens that are owners (parent, grandparent, ...) of the token to be able to retrieve that poor little Kitty.
Currently I'm thinking this is a perfect example where global / master registry could be used. I started drafting it (code is here) and would like to ask all of you if you also think this might be a good idea. I also agree with all the points @vernon99 mentioned and already partially incorporated them into the codebase.
Thank you everyone for the comments. I have been grinding through an implementation with tests so we have a basis from which to work on finding the most optimal solutions together.
@vernon99 I have address the first 2 concerns for nonfungible "possessions". I like this name.
This code is working now, it's here if you want to run it yourself.
I have put ERC-20 on hold for a bit, seems relatively trivial once ERC-721 is working. @vernon99 thanks again for the comments on where to look for that implementation.
@mg6maciej thanks for dropping in here. I think the global registry is a fantastic solution to a lot of the needs of developers out there.
I do foresee some issues with functionality, specific implementations that restrict the composability of assets for example. For all basic compositions though, I think it's quite a good approach!
Yes, there are things that need to be taken care of in 998. I can think of these cases:
Another thing worth discussing is what kind of events these transfers will fire.
I think this is a great start.
@mg6maciej What are the thoughts on NFTP as a title for both the non-fungible token possessions and FTP for fungible token possessions?
I'm not that interested in choosing names for anything for now. I think it's too early. I'd be more than happy to change names in my implementation at some point.
I've noticed a potential issue with different implementations of ERC721 tho. There are a couple of ways to interact with them.
If you just use
@mg6maciej I'm going to be adding the callbacks and events soon to the implementation
I know you're but syncing on the composables instances + registry will be crucial, let's touch base about this next week.
If anyone has any feedback on how to interop a global composable NFT registry with individual instances of Composable 998 (721 extended) please feel free to chime in!
Also there is a Discord for general #buidl chatter around NFTs here: https://discord.gg/3TtqP2C
referenced this issue
Jun 15, 2018
Hi everyone! Myself, @flockonus and a few other folks from the CryptoKitties team had the opportunity to meet @mattlockyer a couple days ago to discuss designs for composable NFTs. We primarily discussed a different design than what is currently in this ERC, which I’ll summarize here to get feedback on from all of you fine NFT enthusiasts!
Current Design Issues
Ownership state is split between child/parent
When a token is owned by a composable “parent” NFT, the complete ownership state is split between the child contract and the parent contract. The child contract (which may not know about ERC998) state says that the token is owned by the parent contract address. The parent contract specifies which NFT within the contract actually owns the child token. Similarly, sometimes methods related to ownership are executed from the child contract and other times they are executed from the parent contract.
Basically, the current design requires implementors to maintain a lot of state! Parent contracts would need to track who owns their tokens, which child tokens are owned by the parent contract’s tokens, and reimplement/wrap
Ownership terminology overloading
Ownership in Ethereum is currently strongly defined as a mapping from Ethereum addresses to tokens of some kind. Current contracts rely on this relationship for ownership operations (you
Bottom-up Design Proposal
The current proposal describes ERC721 tokens with logic added so they can own child tokens. The bottom-up design inverts this, instead proposing an extension to ERC721 and ERC20/223 that enables them to be linked/attached to any ERC721 token, in addition to being owned by an Ethereum address (as is the case now).
Similarly to the current proposal, the ownership hierarchy for a particular NFT can be thought of as a tree, with an Ethereum address at the root, NFTs in the middle, and either NFTs or fungible tokens at the leaves.
In addition to the benefits in the next section, the rationale behind this proposal comes from our experience with CryptoKitties. After releasing CryptoKitties, many developers built apps, tools, and tokens that extend the CryptoKitties ecosystem. It doesn’t make much sense for a CryptoKitty to own EOS tokens, but it does make sense (and is super cool!) for a CryptoKitty to own a provably unique cat-hat token (see KittyHats). In general, we see value in NFTs being extended by contextual tokens with semantic meaning, not NFTs being able to own arbitrary tokens. We think the bottom-up approach best fits this ecosystem-extension view of composable tokens.
Wonder if there are issues similar to "approval" where some "attachment" might be orphaned by a chance in "ownership" at the child level.
Does a cat continue to be attached to a hat after the hat's ownership has changed?
Who can detach the hat?
I'm rather interested by the possibilities when it comes to arbitrary standard tokens rather than specifically crafted tokens setup to be children. Semantics can be re-imagined in new contexts.
i.e. Turn the power on for your city in a dApp game by adding
This "composable" approach may be entirely unsuited for such tasks in the end, the proper approach is probably a lot more custodian and based around "deposits", but worth mentioning a use-case for the parent-child ownership style even if I'm not seeing the cleanest way to lay it out.
Perhaps the best approach is to separate everything. ERC721's go on being themselves, ERC20's do their thing. Then another contract can associate them, perhaps by taking custody and wrapping into a new combined entity.
I have been looking into the bottom-up approach. Some comments:
Using the bottom-up approach it is possible for new composable-aware ERC721 parent contracts to have onchain enumeration for any token that is transferred to it. This is done by using the
I really like the idea of doing enumeration off-chain because I don't like the expense and complexity of the bookkeeping on-chain.
I like the idea of using events to track child tokens of parents. A cache of this info (child tokens) could be included in the JSON file returned by the tokenURI for each parent.
There is another issue which is buy/trade/sales verification of state. When selling a parent token the state of the parent token (all the children) can be checked using on-chain enumeration to verify it is all that is expected by the buyer. This verification can be done in the same transaction that the transfer is done. Without this verification it is possible for someone to remove children right before a transfer call and the buyer does not get what he/she paid for.
So my question is this: How to securely do state verification of a parent ERC721 token when selling it if there is no on-chain enumeration?
Perhaps the state verification can be done onchain by passing in an array of child contracts and child token Ids to check for after the transfer function is called. I think that would work.
Related work, haven't dug into it but have seen this mentioned in relation to "composables".
They create an ERC20 which has a pre-defined set of addresses and quantities associated with it.
@mryellow I believe that's the intention, the hat would keep on belonging to the same cat. Who can detach the item is the current owner of the cat.
@mudgen I think so too! If the item in case that is for purchase, has attached items that are important for the buyer then it would make sense that the purchase order would pass an array of address+ids to verify the items are indeed attached to the NFT.
It would work with signed transactions (similar to 0x style) orders as well, if the seller at the time of the sales creation also bundle the promise of the items in the order.
@mudgen I think your assumptions are wrong here. If I understand this bottom-up concept correctly, child token is never directly transferred to its parent, i.e.
@jordanschalm @flockonus Are you going to join our next composable call on NFTy Magicians discord? I would like to discuss this concept with you in depth and believe we should schedule a call sooner than planned. Also @jordanschalm I asked you some questions there, but if you want I can move it to GitHub.
referenced this issue
Jul 15, 2018
I recently did a lot of work on a reference implementation of ERC998 which can be seen here: https://github.com/mattlockyer/composables-998
I also wrote a draft EIP for ERC998 here: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-998.md But I have not done a pull request yet for this EIP to get it added because I would like more feedback first.
Some feed back on the EIP and the reference implementation would be very helpful.
Also, here is a blog post where I gave an overview of top-down and bottom-up approaches: https://hackernoon.com/top-down-and-bottom-up-composables-whats-the-difference-and-which-one-should-you-use-db939f6acf1d
An EIP998 draft was recently added: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-998.md
@mudgen Following The discussion on the channel, and commenting on the issue as requested
Currently there is this structure in the reference contract implementation:
So I believe the implied idea of ++
If my assumption is correct I'd suggest we instead have this other struct, that would also cost 2 words (same as now):
So we don't have to overload meaning into
Some thoughts on functions of
Simplify token transfer functions
transferFrom() -- as inherited from 721
transferChildToken(uint256 _tokenId, address _parentContract, address _parentTokenId)
I understand ERC721 it requires the
Was a team leader on the Honu the CryptoKitty Charity Auction project with CryptoKitties and Bill Tai of Actai Global and Sir Richard Branson's team at Ocean Elders.
Putting together a presentation for NFT.NYC and exploring how 998 can become an added building block to create a future for this.
Looking for projects, ideas, visionaries who can help me (with attribution of course) draw a picture of a possible future with new tools and protocols.