summary: 0xmons is an experimental NFT project that combines generative pixel art with blockchain collectibles.
content: 0xmons (XMON) is an experimental NFT project that combines generative pixel art with blockchain collectibles. It is a combination of memes and Pokémon, but 30% more. It is an NFT platform for summoning neural net-generated pixel monsters. Overview 0xmons is an NFT platform for summoning neural net-generated pixel monsters. (XMON) is a cryptocurrency and operates on the Ethereum (ETH) platform. Each piece of artwork is generated by a Generative Adversarial Model (GAN). This makes each NFT completely unique, with the option to register the NFT data fully on-chain. Users can view all 0xmons they have created so far, starting with 0. Users who mint the 0xmons NFTs can then choose the encode the entirety of their collectible (name, image, lore) on-chain. These NFT Pixel art are created from the mad nightmares of a GAN. They are procedurally formed from animations. Their names are gotten from a Big Language Model. Their totally not-random bits collected from the Ethereum blockchain. Goals The goal of 0xmons NFTs is to bootstrap a new valuable NFT asset class without relying on OG trappings. The combination of scarcity, aesthetic, creation process and technology are the basic reasons why they're desirable. In addition to the flagship NFTs, they are also working to create other valuable pieces of a broader NFT ecosystem. The bundler allows NFTs to become general purpose asset baskets, while the multisender makes it cheap to send any token anywhere. They are currently working on more ways to expand the technology behind NFTs, bring utility to the (XMON) token, and create lots of cool stuff. How It Works 0xmons is not a generative project in the composable sense, its images come from a generative model. But the images are generated from a GAN which is at least a gigabyte in size, factoring in all the libraries and model parameters. There is no way to store the model parameters needed directly in contract storage, much less implement the thorny matrix multiplication libraries needed to make it all work. Furthermore, the images are not built up from smaller images, so we can’t even rely on precomputation in any form to give us a boost. The solution they used does not move the GAN on-chain. It also does not move the direct image into contract storage. Instead, they took some notes from a 2017 project about putting boobs on the blockchain. They were egregiously going to take advantage of cheap calldata. Also, directly storing the 0xmon images is not very feasible. The model can’t be stored on-chain because (it clearly greatly exceeds the 24kb limit) and why they can’t compose the images from smaller pieces (there is no composition used to create the images). The reason for all this is, of course, is gas costs. It currently costs 20,000 gas to store a uint256 (i.e. 256 bits = 32 bytes) directly into smart contract storage. Even with lossless GIF compression, the 0xmons images range anywhere from 10kb to 50kb in size. The costs of doing a full write, assuming a very dense packing is still around 6,000,000 gas, which is around half of the block gas limit. And that’s only on the most conservative side of things! Contract storage is expensive, but calldata storage is not. An update to the EVM in 2019 changed the gas costs of storing a byte to be only 16 gas. This means that if we upload the full 0xmons animations, we’re looking at costs of around 400,000 to 2,000,000 gas. This is much more manageable. However, this is also where the trade-offs come in. Contract storage is always accessible. Calldata is not. Calldata is only saved by full nodes, and while it’s needed for accurate recreation of the blockchain, it may not be saved on fast nodes and light clients. Calldata refers to the inputs passed into functions, so all we need to do to record our data is to make a function call. But then how do we access the data? We can do so through the transaction hash which uniquely identifies each transaction. From there, we can look at the parameters passed into the uploadMon function call through the input. In this transaction, the bytes passed in from the Data field encode the data for one 0xmon, and it can be accessed from any front-end chosen, as long as a connection to a node is available. With tools like Infura and Etherscan, such info is generally available. However, this data is also not available to other smart contracts. This is the other drawback to using calldata (aside from the availability of a connection to a full node). For the 0xmons project, it was decided that the trade-off was worth it to enable the most affordable encoding of the full animation. Then, once the input is stored, the transaction hash can be saved in a mapping on the contract so that it is easy to know which hash to lookup in the future. Unfortunately, there’s one more gotcha–transactions do not have access to their own hash. This means they can’t make both store the data (via the input) and update the on-chain mapping in one function call. So what actually happens is: First, we make an “empty” transaction to store the encoed data. Then, we make a call to the registry contract to store the transaction hash from the first transaction. How is 0xmons image encoded? Given that the images are all pixel art, an immediate thought might be to get extra clever with densely packing pixel information into the uint256, perhaps with reference to another mapping of values to hex colors. This was tried but it wasn’t as efficient. It turns out that the native GIF encoding, once optimized with gifsicle still does a better job. Encoding Your 0xmons Now, let’s go over what the actual process is like for doing your on-chain encoding. First, you can only encode 0xmons that you own. If you head over to the page of a 0xmon that you own, you’ll be greeted with a new menu on the bottom: There is a dropdown that lets you select between Static and Animated. This refers to the 0xmon image. In both cases, the name, epithets, and lore will also be encoded into the payload. Even though the 400,000-2,000,000 gas estimate is “more reasonable” to encode a 0xmon, there is also an added option to encode just the static image which should be around 10 times less expensive, i.e. around 40,000 to 200,000 gas to encode. If this a user's first time, and you want the front-end to handle everything, simply select if you wish to encode the static or animated image, and hit the Upload button. As the picture above describes, there will be three transactions you have to accept in order to make things work. The first encodes the image in the input field. The second approves the registry contract to spend XMON for the register fee, and the third actually adds the transaction hash to the contract’s mapping. If you only send the first transaction and want to come back to do the actual registration, simply save the transaction hash of the encoding transaction (i.e. the one that makes the uploadMon function call), and paste it into the input field. You can then register at your leisure. Astute readers may have noticed that it is still “feasible” to encode the entirety of the static 0xmon image directly into the contract’s storage. The gas costs for doing so are still incredibly high, anywhere from 1,000,000 to 4,000,000 gas, and this is just for the non-animated image. Nonetheless, for the purists with ETH to burn, I’ve also added a direct upload option that writes the encoded payload directly to the contract. This is now fully supported by the front-end, and users who do so will be rewarded with a flashing lightning icon (as opposed to the normal lightning icon). The lightning bolt button lets others know that you’ve encoded the static data on-chain, while the lock button lets others know that you’ve encoded the animated data on-chain. You can also click on the icon to take you to a new 0xmons showcase page that reads and decodes directly from on-chain. So, when this process finishes, your 0xmon will get two shiny new icons on the front-end.