Gamifying Crypto Assets with the ERC998 Composables Token Standard

Assets can be complex. Take a house, for example; you're not just selling the ownership of the land it sits on, but also the physical attributes of the building - the foundation, the wood, the interior walls, the roof, the stairs. Sometimes, if you're selling a fully furnished house, that asset will also include expensive furniture pieces such as couches, dining tables, bed frames and more. When it comes to crypto, attributing an ERC721 token to any non-fungible asset doesn't give you the space to interact with the asset in all the ways you possibly can. You'd be compressing all the pieces of the item into a single representation, and that representation often isn't accurate, nor helpful to you if you want to later pull them apart to sell them individually.

Crypto Composables, or the ERC998 standard, is a solution to this problem. It can be applied to many non-trivial real-life industry problems: property ownership, supply chain (for example, attributing a given field of harvested coffee beans to an overarching ERC998 token, under which you'd have bags of differently roasted beans as ERC721 tokens and the beans themselves as "bean tokens" in ERC20 standard, etc.), gaming, and more.

Basic architecture

Think of all the token standards as one big family: ERC998 is the "parent" token contract, and ERC721 and ERC20 the "child" token contracts, depending on which standard you choose (or both, if you wish). ERC998 is mapped to these child contracts in such a way that they are now "adopted" by the parent ERC998 contract and "belong" to the overarching composable.

ERC998's tokenId is mapped to each child's contract address. For ERC721 child tokens, its contract address is mapped to the token's own tokenId, whereas, for ERC20 child tokens, the contract address is mapped to the balance of ERC20 tokens. In this way, you re only allowed to transfer child tokens if you also own the parent ERC998 token.

Top-Down vs Bottom-Up

No, you're not suddenly reading an article on subatomic physics, we're still in cryptoland. There's two different ways you can structure a composable: the top-down approach, or the bottom-up approach.

You can visualize the top-down approach as the ERC998 token being a basket open upwards; you can take objects in and out of it, exchange it with others, and do whatever you want with its contents - as long as you're the owner of the basket. When I mention the parent-child relationship, that usually refers to the top-down composable approach. You can transfer any ERC721 or ERC20 token contract into the composable. It's also easier to retrieve all the information on child tokens with top-down composable tokens.

However, ordinary and existing ERC721 tokens (non-composable ones) cannot receive ownership of a top-down composable token, as the parent-child mapping can't be established. This is like trying to force a woven basket into a sealed cube. Of course, you can always place a basket into a bigger basket - meaning, you can place top-down ERC998 into other top-down ERC998 tokens. You can't place them inside non-composable ERC721 tokens.

Furthermore, you must make all interactions with non-composable child tokens in top-down ERC998 tokens that require owner authentication through the proxy of the parent contract and not directly to the child contract. This is because you're technically not the owner of the child tokens; the parent token is. Because of this, issues can happen if you haven't made the setup of creating a parent method for all interactions with non-composable child tokens in your top-down ERC998 basket.

The bottom-up approach is where things go topsy-turvy; instead of the parent being the ERC998 contract, it's the children who are. Think of bottom-up composables as a dog left home alone for a long time; it latches onto the first visitor that comes home, asking for pets. Similarly, ERC998 bottom-up composables can attach themselves to other ordinary non-composable ERC721 tokens.

For example, if you have a new CryptoKitty ERC721, you can attach bottom-up ERC998 composables like clothes or toys to the Kitty, as well as ERC20 composable food tokens. Going back to the analogy of non-composable ERC721 tokens as sealed cubes, bottom-up ERC998 composables would be like objects strung up on sticky pads that can attach themselves to the sides of the cube.

In the case of bottom-up composables, it's a lot harder to retrieve information on all the child tokens, but conversely, you can call methods that require owner authentication directly from the "child" ERC998 contracts. The biggest disadvantage of bottom-up composables is that you can't have just any ERC721 be a part of the composable; it can strictly only be a composable ERC721 because the "parent" contract is just a regular non-composable.

The Implementation

In terms of implementation, there are four kinds of composable tokens:

First, there's a couple of key elements of composable contracts that you should know before going in:

Authentication is important when you need to limit who or which contracts can execute specific actions. In top-down and bottom-up composables that use ERC721 tokens, the rootOwner is the address that "owns" the entire system of composables. For example, for a top-down token, the rootOwner is the one who holds the largest ERC998 basket that contains all the other children inside it. For a bottom-up token, the rootOwner is the one who holds the cube to which the bottom-up ERC998 composables are attached.
Authentication is pretty simple in an application; you compare the rootOwner to the msg.sender, whom is the user making the current call to the contract (and thus the owner of the contract at the time of deployment), as well as what's returned by getApproved(tokenId) and isApprovedForAll(rootOwner, msg.sender).

Traversal is another important concept that plays an important role when the composable system gets more complex. If you have lots of nested ERC998 composables of different types, one parenting the other, it can be hard to keep track of who the original rootOwner was. The functions rootOwnerOf(uint256 _tokenId) and rootOwnerOfChild(address _childContract, uint256 _childTokenId) can retrieve the rootOwner in both top-down and bottom-up composables.

For bottom-up composables, if the rootOwnerOf call for the parent token (the ERC721 cube) passes, then what's returned is the true rootOwner of the composable tree. If it fails, then you have to call rootOwnerOfChild instead to find its parent, which gives you the true rootOwner if it passes. If that still fails, then the address of whoever owns that token is the rootOwner.

Transfers follow the same simple format from composable to composable: from whom, to whom, and what's transferred.

For example getChild(address _from, uint256 _tokenId, address _childContract, uint256 _childTokenId) transfers an ERC721 token with address _childContract and ID uint256 _childTokenId from the address _from parameters, to the token with ID uint256 _tokenId. Therefore, you can think of it as getChild(from, to, what).

The same format applies for the function safeTransferChild(uint256 _fromTokenId, address _to, address _childContract, uint256 _childTokenId), except this can’t transfer tokens that are “owned” by other tokens. It can only transfer tokens that are directly owned by an actual address. (In other words, it can't transfer child composable tokens). The same exception applies to transferFrom functions.

OK, so now we've got all the pieces in place. Let's dig into the actual implementation!

ERC998ERC721 Top-Down Implementation

For transferring tokens

For ERC721 contracts that have a safeTransferFrom function, you can use that function to transfer the token to a top-down composable. The bytes data argument is where you put the token ID of the top-down composable token that you're transferring the ERC721 to.

For ERC721 contracts that don't have this function, instead call the approve function to approve the top-down composable as an owner, and then in the composable contract, call getChild (which I explained previously).

onERC721Received is a function that's defined in the ERC721 standard, and it's always called after a safeTransferFrom function is called. This is how top-down composable contracts are notified that you've transferred an ERC721 token to it.

Another interesting method to note is transferChildToParent. It authenticates the caller and then transfers a bottom-up composable ERC998 token from a top-down composable token to another parent ERC721, basically shifting it from a basket and then hooking it onto a cube.

For rootOwnerOf and magic values

The first 4 bytes returned by rootOwnerOf is a "magic value", which is essentially something that gives contracts a way to show each other what interfaces they support. In this case, it's the magic value 0xcd740db5, which denotes an ERC998 interface. The last 20 bytes of the returned value is the actual rootOwner address. The magic value ensures that even if you call rootOwnerOf on a contract that doesn't have that function, you'll still receive a valid returned value. The same goes for rootOwnerOfChild and ownerOfChild functions.

If you don't know whether a contract has any of these functions, you have to compare the first 4 bytes returned to the ERC998 magic value 0xcd740db5.

ERC998ERC20 Top-Down Implementation

For transferring tokens

Use the transfer(address _to, uint256 _value, bytes _data) function on the ERC223 contract, where the bytes _data argument contains the integer value of the top-down composable receiver's token ID.
If the ERC20 contract doesn't support the ERC223 standard, then similar to ERC998ERC20, call the approve function in the ERC20 contract to approve the top-down composable as an owner, then call getERC20(address _from, uint256 _tokenId, address _erc20Contract, uint256 _value) on the top-down composable contract so the tokens may be transferred.

ERC998ERC721 Bottom-Up Implementation

These contracts store the address of their parent contract and their parent tokenId.

On tokenOwnerOf

You use this function to get the address and tokenId of the token's parent if it exists. If the boolean isParent (which is one of the outputs of the tokenOwnerOf function) returns true, then the tokenOwner is the parent ERC721's address. If it returns false, then the address returned is a user address.

Similar to the previously detailed implementations, the tokenOwner returns an ERC998 magic value in the first four bytes, whereas the last 20 bytes contain the token owner address.

ERC998ERC20 Bottom-Up Implementation

Like ERC998ERC721 bottom-up contracts, ERC998ERC20 bottom-ups store their parent contract's address and tokenId. The main differences with the ERC223 standard are that ERC998ERC20 bottom-ups allow you to call for the parent token's balance, as well as transfer the bottom-ups between parent tokens. You track ownership by mapping the parent address, to the parent tokenId, and to the balance - all this in a nested mapping. This is in addition to the standard ERC223 address-to-balance mapping.

The simple function balanceOfToken allows you to check the parent ERC721 token's balance of ERC998ERC20 bottom-up composable tokens, in contrast to the usual ERC223 functionality that would return a user address' balance instead.

On transferring tokens

The transferToParent function allows you to move ownership of bottom-up tokens from an actual user to a parent ERC721 token.

There's a couple of important things to take note of here:

The new ERC721 parent contract has to be compliant with ERC165 and therefore use the supportsInterface interface

transferToParent has to make sure the new parent contract exists, and does this by calling ownerOf on the parent token's contract to see whether it throws an error or not

After transferring, the function has to emit the TransferToParent event

Of course, if the account transferring the tokens doesn't have sufficient balance, an error is thrown

Now… So What?

Why should we actually care about crypto composables? We know what they do, but what is their potential for the future, and how are people and projects using them today?

Crypto composables brings us one step closer to a future where we can actually use cryptocurrency reliably and flexibly for a greater variety of financial applications across the world, thus addressing the complete set of needs of the population that it seeks adoption from. From the one-dimensional digital asset backed by an innovative foundational protocol built in 2008, we’re moving to a full-fledged digital economy that still has that same foundational protocol our community fell in love with in the first place.

There’s some super cool projects that are already leveraging crypto composables to do incredible things, and here’s a couple of them as mentioned in this article:

Mokens.io → Is the build-your-own crypto collectible! You can make “limited edition” collections of your own collectible mokens, each with their own unique name, and sell them, trade them, or give them as you like. Mokens.io has become ERC998 compliant, which means your cryptokitty can actually own a moken! How cool is that?

Caesar’s Triumph → Is an epic empire-building game where each piece of land is a unique ERC721 non-fungible token. You can thus build a huge empire made up of ERC998 bottom-up child token “cities”, and even further down, “villages”. This allows you to trade an entire city with all its components, rather than having to manually transfer each one, which can take ages if you’ve advanced far enough into the game.

Mintable.app → Similar to mokens.io, this project allows you to create your own ERC721 NFTs, browse others’, and organize them in a streamlined manner. It’s essentially an ERC721 manager for when in-game assets or other crypto collectibles start to become a little confusing to make sense of yourself. This includes, of course, management of ERC998 NFTs, and further down the line, a visualization of the ownership tree.

To wrap up, ERC998 crypto composables are a new token standard that now allows you to do even more with your non-fungible tokens, and if moved into real-world verticals, can make our interactions with assets so much easier. They might seem complicated on the surface, but they’re not too hard to implement either, so do try it out and tinker with some of the smart contracts in this article!

Article Author

1 Comment

Related Articles

ERC-721 Non-Fungible Token Standard

Simple Summary A standard interface for non-fungible tokens, also known as deeds. Abstract The following standard allows for the implementation of a standard API for NFTs within smart contracts. This standard provides basic functionality to track and transfer NFTs. We considered use cases of NFTs being owned and transacted by individuals as well as consignment to third party brokers/wallets/auctioneers (operators). NFTs can represent ownership over digital or physical assets. We considered a div

ERC-20 Token Standard

Simple Summary A standard interface for tokens. Abstract The following standard allows for the implementation of a standard API for tokens within smart contracts. This standard provides basic functionality to transfer tokens, as well as allow tokens to be approved so they can be spent by another on-chain third party. Motivation A standard interface allows any tokens on Ethereum to be re-used by other applications: from wallets to decentralized exchanges. Specification Token Methods NOTES: - The