DegenerateFarm Logo

Background

Degenerate Farm is based on the artistic career and vision of Russian artist Nadia Khuzina with allusions to the book Animal Farm. A survivor of the Soviet Union, political censorship, and corporate copyright infringement, Nadia began her journey in crypto from the standpoint of rights management, seeking to preserve her rights as an artist. Her artwork covering North Korea, and Kim Jong Un, was ranked ahead of Bitcoin in South Korea's Gentleman Magazine in 2013, and her derivative app Slot Dictator was covered in the main Chinese newspapers.

Nadia was a co-founder, and the sole artist of EtherCats.io, the first NFT project to use Chainlink VRF. This project was a bid to bring people together away from the divisive politics inflamed by the global pandemic, but with Degenerate Farm, it serves as a progression to unite under the original ideological principles of crypto.

While EtherCats brought some of the most spectacularly animated NFTs to the market in a provably random way, and brought along with it other NFT innovations, it lacked the ability to be upgraded. EtherCats also did not allow for random generative properties of the cats. They came with only a rating and multiplier with the intent to be used in a card game (currently being play tested). It was a proof of concept of sorts for Chainlink VRF, and the rapidly growing need for a unique digital identities became much more clear shortly thereafter.

DegenerateFarm's First Characters - The Pig

Problem

While the ERC721 and ERC1155 are permissive standards that allow for mutable metadata, it has not yet been agreed upon how upgrades in real time to NFTs should best be carried out. Current upgradeable patterns revolve around redemptions for different tokens, proxy contracts, and simply minting new tokens. All of these strategies impact the provenance of the NFT, and make it difficult to understand for the end user what is what.

Solution

Degenerate Farm turns that on its heads with the novel process of how it tracks upgrades. It also iterates on the pattern of using the token ID to be the properties of the NFT itself.

Instead of rending the NFT as an image, it takes advantage of the animation_url metadata property to render the NFT as an HTML5 app with a conglomerated group of sprites that are chosen from the JavaScript file by reading the filename (which is the token ID). The idea of making the NFT as a web app was first used by Ether Cards (which this project will be merging with after the hackathon), but with Degenerate Farm we take it further by embedding AlchemyWeb3.js into the NFT. These calls go directly to the mapping of each unique ERC721 token ID's upgrades and are rendered in real time on the NFT. Alchemy's reliability is important because without it, the NFTs will fail to display the upgrades.

Mint Process

Character Traits

The hackathon release will feature the first animal of the project, pigs. In future releases (on Ether Cards), different animals and characters will be available for minting. The pigs are limited to 1024 total NFTs. To reward DegenerateFarm.eth, EtherCats.io, and Ether Cards fans, we will mint the first 16 pigs to be given away in different pre-published ways. This is necessary because in order to activate our OpenSea collection beforehand, we need to mint ourselves first. It would not be fair to hold back these low numbered pigs for ourselves later. It is easiest to give them away.

When a user mints a pig, it sends a request to Chainlink VRF to call the contract back with a random number. Only the VRF coordinator can actually call the function that triggers the mint function. This means there is a delay between when a user's mint transaction is confirmed, and the NFT is actually minted. There also is an additional delay if you want to see it on OpenSea, because OpenSea must then ingest the NFT into their system by parsing the metadata. This is very processor intensive so in peak periods it can take up to an hour, although usually it takes about 1 minute.

The mint function takes the returned random number and uses that to build the pig. Each token ID has 10 property numbers, and the token ID itself prepended to that. This means that each pig will have a incremental order of mint in the name of the NFT, and will also come with all the properties that make up the pig.

Token ID Format

Most of the generative parts of the pig are linear. We have 10 sprites for each relevant body part. This is to keep things simple with the contract, and avoid modulo bias in the least amount of gas. Chainlink VRF currently has a 200,000 gas limit. That means you have some constraint in the operations you can do in calculating the properties of an NFT. In this case, we have a lookup table for only the background, which has offers a 1 in 100 chance of getting a Level 10 background, along with an increasing difficulty up to that point for the other levels. The subsequent properties are all a linear 1 in 10 to get.

Non-Linear Background Rarity

Once the pig is minted by the VRF coordinator calling back, NFT indexers like OpenSea will see the mint event and begin to parse the metadata. In EtherCats, we enumerated all possible token IDs and pre-published them on IPFS. Degenerate Farm, however, has zillions of possible permutations in the token ID, or more specifically 1024 * 10^10. We were already at the limits of IPFS with 4,500 EtherCats metadata files. The only solution is an API, which unfortunately has to be centralized at this point in time, at least for the duration of minting.

Our API is quite simple and uses AWS Lambda. The biggest problem with a centralized API thankfully isn't censorship just yet, but a DDoS attack. AWS has advanced tools for rate limiting, and distributing things to make it harder to pull off. When called, the API replies with the JSON metadata of the token ID requested. Instead of generating all possible combinations of token IDs, we only build the one requested, and only when requested.

There's one small, but clever step before anyone fetches the metadata for the pig, and that's the HTML file generation. We also use Alchemy on our nodejs backend to listen for mint events. When a pig is minted our server automatically generates an HTML file that is linked to in the metadata. The clever part is that every HTML file for each and every pig is exactly the same. The only difference is the name of the HTML file. The base script can build any pig. It does this by reading the file name from the HTML file, which you guessed it, is the token ID. This means that once you build one pig, you've built them all. The token ID is just the input.

After minting is finished, both the base metadata URI, and HTML files can be pointed to IPFS. Once everything is done that needs to be done in the project, then the ability to change the pointer can be permanently disabled in the contract.

Upgrade Process

Upgrading is the hook of this hackathon entry besides the wonderful art. Generative pigs are fun, but leveling up your pig, and trying to get the highest score is what will keep people interested. Having rarity be a dynamic thing encourages people to participate and reach limited time rewards milestones not present in other generative projects.

After a pig is minted it starts with 1,000 chips, depicted in the NFT as a single yellow 1,000 chip, and a random card hand. These cards come from a random 1,000,000 card shoe, meaning it is possible to have duplicate cards of the same suit. If the hand happens to be two aces, then a 25,000 plaque is awarded. In this case it will start with 26,000 points.

When an owner upgrades their pig, they ask Chainlink VRF for another number. After the VRF coordinator calls back, the contract maps the request so that when the VRF coordinator calls back that it triggers an upgrade. When the upgrade function is called, they get an extra chip added to their stack (1,000 for the first 100 chips, and 5,000 after that up to a maximum of 600,000 total chips). Then they get an entirely new card hand each time they upgrade. If on any hand they get aces, the pig gets a 25,000 plaque added.

It's not so simple to max out the stack of plaques though. Once you get three plaques, you will need your aces to have matching suits in order to level up the plaque. (Aces without matching suits are still added to the total aces count.) If you are lucky enough to acquire seven plaques, it then gets very difficult to continue your journey to the maximum 10 plaques. You will need to get matching diamond aces to top up your stack of plaques further.

While the total chip stack is intended as the main rarity metric, the stats of total aces, matching aces, and diamond aces are tracked for the purpose of rarity tie-breaking. If there are two pigs with the maximum number of chip/plaques, then the pig with the most diamond aces will be the rarest. If the total of aces is still tied, then the pig with more matching aces is considered rarest, and if that is also tied, then it is resolved by the total aces count. If the tie still cannot be broken, then the pig with the lower mint number will edge out the other.

The rarity ranking is just for fun, but might be used as the basis for giveaways, airdrops, and access to certain products in the future.

(Note: Below is a technical step-by-step explanation of how this process functions in tutorialized form, including how we use Alchemy for Web3 calls from inside the NFT.)

Purpose

The main purpose of this hackathon entry is to show an alternate way of engineering NFT upgrades in a verifiably random fashion. Like the EtherCats Founders Series, it is a demonstration of what's possible more than a perfection of the technology. We hope this project will influence the thought of not only creators, but infrastructure providers like Alchemy in developing solutions to issues faced by NFT projects in the future.

New to Chainlink VRF

The official docs of Chainlink VRF do not tell people that they can use VRF for different function calls. We believe our code should be added as an example of how to differentiate callbacks to fulfillRandomness, which is the only function the VRF Coordinator can call.

//The VRF Coordinator only calls the function named fulfillRandomness. It doesn't know whether it is providing a random number for a mint or an upgrade. The contract must interpret this from the requestID by checking which mapping it is a part of.
    function fulfillRandomness(bytes32 requestId, uint256 randomNumber) internal override {
        require(msg.sender == vrfCoordinator, "Only the VRF Coordinator may call this function.");
        if (tokenToUpgrade[requestId] != 0) {
            upgradePig(tokenToUpgrade[requestId], randomNumber);
        } else {
            mintPig(minterAddress[requestId], randomNumber);
        }
    }

Bugs Found

1) The animation_url isn't respected as the preview image on indexers like OpenSea. This means OpenSea shows a blank image on mint. We have finished a local version that listens for events and builds a preview image of the minted pig, but need more time to implement on the backend. The need for this is moot once minting is complete, so it is not a top-priority as nobody is going to sell on OpenSea before minting finishes.

2) Alchemy and OpenSea did not imagine such a pattern, so we are working with them to fix both API whitelisting and UX. We hope our project is successful so they can progress forward with the gamified future of NFTs.

3) Web3 is a bit of a joke for login management. While we have used socketio and nonce message signing to authenticate users, DegenerateFarm only needs to know the root account logged in and the network. Unfortunately, our code that worked in the past we realized had some issues. Web3 also doesn't allow for a dapp to log people out. That can only be a user choice. This makes managing state challenging. There are third party services that simplify this, but at the expense of decentralization, so we spent some time refactoring.

4) WebKit. Yea. WebKit is awful and full of bugs. It is extraordinary that the person who envisioned mobile phones being able to run web applications didn't foresee the need for following the rules of standards. It is for this reason we chose to use absolute positioned sprites of all the same dimensions. We intend to use mapped spritesheets as we have done in other projects when it is serviceable in a decentralized way. For now we have chosen a slightly more bloated sprite rendering system to maximize browser compatibility.

## Road Ahead

The pattern of upgradeable NFTs has unlocked a host of multi-billion dollar project ideas (in tomorrow dollar maybe trillions) for us in gamifying DeFi and educational investing. While crypto loves vice, those involved in EtherCats seek to make the future of our children to be in a happier world. Although we see solutions outside of any collective, that doesn't mean we don't recognize the value sharing our ideas to the world in an open source manner. There is nothing in DegenerateFarm the average technical person couldn't do, but it is unlikely for any average person to accomplish anything by simply consuming ideas. It is getting your hands dirty that allows one to find solutions to problems. This is the way of John Galt, and that's exactly what was reinforced to us coming together in this hackathon. We became better at our jobs and learned new skills, and we found many new ways to take NFTs to the next level.

Step-by-Step Process and Technical Discussion

Minting Process

Step 1

Click 'Mint' and pay 25 Matic to the mint function of the smart contract.

Step 2

The smart contract makes a request to Chainlink VRF for a random number attached to a unique request ID. This request ID is important because it allows the contract to keep track of things over the course of two asynchronous transactions from two different addresses. One address is your address, the other is the VRF Coordinator's.

Step 3

The Chainlink VRF Coordinator returns a random number to the smart contract which then is used to mint a pig (with a unique token ID) and transfer it to the transaction matching your request ID.

Step 4

When a pig is minted, a transfer event is fired. Our nodejs backend is subscribed with AlchemyWeb3.js to listen for these events. When one occurs, the backend creates an HTML file that has the token ID as the filename. Every HTML file is exactly the same no matter which pig. The HTML file that is created is literally the NFT. NFTs are just token IDs that have pointers to metadata, and this is no different.

Step 5

Now things get spicy. In the EtherCats Founders Series, there were 9 cats (1 image each), with 500 combinations for each cat coming from a 1 to 100 rating, and a 1x, 2x, 3x, 5x, or 8x multiplier. While it was a 1 in 1 million chance to pull a 100 rated cat with an 8x multiplier, there remained only 4,500 possible JSON metadata files that could be minted. This allowed for the metadata to be enumerated before the contract was even deployed, and allowed for instant gratification see your mint appear after on OpenSea. However, even with this small number of 4,500, we were near the limit of files in an IPFS directory.

To expand things to have billions of possible images, like we have in DegenerateFarm, meant that even if we could enumerate all of the lightweight metadata files, there aren't enough computers on Earth to render or store all of the possible image permutations. The solution to the metadata component is nearly the same as enumerating all possibilities, but instead of outputting all possibilities, we use a metadata API that only spits out the relevant metadata when asked. DegenerateFarm is using the very reliable AWS Lambda for serving metadata until minting is completed. After we know the token IDs of all 1024 pigs, then it is trivial to enumerate the output, and we can move this precious metadata permanently to IPFS.

The solution to the image rendering problem is sprites, and making use of the animation_url standard in NFT metadata. While to the end user the pig appears as a simple image, it is actually absolute positioned sprites of each trait layered on top of each other, and rendered as a full web application. Yes, the animation_url property allows us to load scripts. This means that the immutable token ID that Chainlink VRF helped output is actually the map to every property of your NFT!

When the backend server output a seemingly redundant HTML file, what it was really doing is giving a unique file that the metadata API script could calculate and point to. The HTML file loads a unified script that parses the filename from the HTML file and uses it to load the correct sprites from further parsing the makeup of the token ID itself.

Upgrade Process

Step 1

Enter the Pig # of the pig you want to upgrade and then click the blue 'View Pig' button below. Once your pig is displayed, click the red upgrade button below and pay 2 Matic to the upgrade function of the smart contract.

Step 2

The smart contract makes a request to Chainlink VRF for a random number attached to a unique request ID. This request ID is saved to a different mapping so contract can differentiate between mints and upgrades..

Step 3

The Chainlink VRF Coordinator returns a random number to the smart contract which is then used to update the pig with your upgrade. Each upgrade adds a chip to the stack of the pig. The first 100 upgrades add one visible yellow chip, which are worth 1,000 leaderboard points each respectively. The next 100 upgrades also add one visible white chip, which are worth 5,000 leaderboard points each respectively. You get these chips no matter what hand you get dealt. This keeps happening until chips are capped at 200 total displayed (600,000 leaderboard points). If on any hand, including during minting, you hit any combination of two aces, then you get a coveted plaque worth 25,000 leaderboard points. After three plaques you must hit matching suits on your aces to earn additional plaque, and after seven, you need matching diamond aces until you hit the display cap of 10 plaques. This is hard to achieve, but if there are multiple maxed out ranking point totals, then the tie breakers of total aces, matching aces, and diamond aces are tracked indefinitely. If it is somehow still tied, then the lower mint number is ranked higher. The odds of hitting aces are better than in poker at 1 in 169. This is because each card is dealt from a separate duplicate deck generated from the Chainlink VRF number.

Step 4

It's great that you can level up your pig, but how is it going to be displayed on OpenSea?

This is why DegenerateFarm is so amazing. The same strategy that allows for generative VRF minting also allows us to load a second script! In this case it is AlchemyWeb3.js. Alchemy gives us the ability to make gas free view calls to the state of the blockchain via Web3. This means the same script that generates the pig from sprites can also return sprites based on the current state of your pig. Besides the 30 second lag for Chainlink VRF to call back with a verifiably random number, it takes place in real time.

DegenerateFarm uses Alchemy for Web3 calls because it is absolutely crucial that the dynamic properties of the upgrades are shown all of the time. Alchemy is superior to Infura in running your own node in a number of ways. We are working with them to help develop better whitelisting functionality for API keys for projects using our pattern.

Characters and Personality

We believe that while many people want to base their digital PFP identity on a single 1/1 NFT, there are moods and personalities applicable to life in the metaverse that many will also want to share. It's intended that most humans will only identify sarcastically with these pigs, but they all convey an emotion linked to their underlying personalities that is useful to social expression in various contexts. This means that while each DegenerateFarm pig is a 1/1 PFP with unique traits, they are not so drastically different as to be exclusive to one cause or person.

Pig Jong Un

Pig Jong Un

Grand Marshal Pig Jong Un loves to gamble all night. He's a trash talker who always brings his harem with him to rail when he plays.

Donald Oinkler

Donald Oinkler

Donnie O keeps a tidy pen, but one of the cats spread the rumor that he paid one of the female horses to make it rain on his pile.

Che Chicharrón

Che Chicharrón

Che's a pretty boy who grooms younger pigs into his way of thinking. He plays tight, but aggressive, and aggressive, but tight.

Jamón Castro

Jamón Castro

Jamón reacts to threats with annoying, idiosyncratic play. Trying to time his moves is as ill advised as invading the Bay of Pigs.

Augusto Cochinillo

Augusto Cochinillo

You can't run or hide from el presidente. Augusto Cochinillo is nicknamed by the dogs "The Torturer" because he goes into the tank on every decision.

Hugo Oincéz

Hugo Oincéz

Hugo talks a big game, but is actually in debt to the other pigs for quite a large sum. Every time he has a score, the line at the trough is all the way out to the fence.

Leonid Bacon

Leonid Bacon

Leonid ignores the advice of his backers and puts his money in impulsively. He often falls asleep at the table, and starts unwinnable fights when he is drunk.

Joseph Snortin

Joseph Snortin

Uncle Joe is what most degenerates would refer to as a whale, but be careful, he often claims to have drank more than he actually did to lure you in.

Queen Swill II

Queen Swill II

Despite her status as a fashionista, Queen Swill has always thought of herself as one of the guys. She loves telling a good porky, and mixing it up with piglets a fourth of her age.

Napoleon Saveloy

Napoleon Saveloy

Napoleon is pesky and persistent. The other pigs could learn a thing or two from him. In his mind all animals are equal, but some animals are more equal than others.

Share this project:

Updates

posted an update

One week without updating here. It's felt like that was yesterday, but that day took a month. We are finally done. The only thing left to do is for Edvard to improve the backend to automatically render preview images for the image property in the metadata. We have this working locally, but nodejs, fs, and DOM emulation is fussy with the techniques we've tried.

I am taking some time off. It was a very intense grind. I hope people appreciate our effort. I want people to recognize the patterns we used more than actually buying the NFTs. However, it really is something I would mint myself. I love the art, and I love the concept.

We found the mutli-billion dollar idea doing this (a much more complicated derivative of this concept), so I am very excited about next year. Hopefully my network will continue to grow. It is absolutely exhausting full-stacking things. I need to improve my delegation skills.

Log in or sign up for Devpost to join the conversation.

posted an update

The last 10% always seems to take 90% of the time. I'm not the best frontend developer to say the least, but I can at least rest soundly knowing I'm only half as arrogant as the devs at Google, who frequently take what once took a single click, and turn it into eight.

My salvo at Google is not unwarranted though in this project. I discovered a Chromium CSS bug, that required a weird workaround for displaying the bottom borders of the leaderboard table. I said goodbye to two hours of my life sorting that one. Thanks Google for that PR. You borked Brave as well.

The great thing about this hackathon is that I'm doing it for the love of coding. Edvard, a 'real' CS pro had burnout from years of working for other people. The soullessness that a large company that encourages a culture of making half-baked PRs to not get culled is the antithesis to blockchain development. I know he is enjoying his time with this. The annoying problems we faced are not stress, they are akin to repetition in the weight room. You know there will be benefits to the effort you are giving now down the road, and this time for yourself.

Nadia is a fan of the KISS principle in development. She reminded me that our goal here is not to be perfect, but to show what is possible. Polished details do matter, but there will always be compromises. The main compromise here is just doing it myself in the way I know best for the frontend. Perhaps my disdain for difficult to master JS frameworks like React is misguided when it comes to the complicated state management, and quirkiness of Web3 logins.

A couple years ago I rolled my own Web3 login pattern with nodejs, JWTs, and signature nonces, but we don't need socketio with this frontend. We just need the ability for people to know the state of their Web3 wallet connection so that they can upgrade the right pig, and mint with the correct address on the right network. It sounds simple, but it's not. I feel this is where a service like Moralis can help. My only issue with Moralis is infrastructure centralization.

The arrogant part of me thinks my way is actually great for blockchain because my smooth brained development style ports perfectly to decentralized file services. I think every page should be static when it comes to managing NFT assets. Web3 is the glue to the read-only database that is the blockchain. Why do you need CDNs, nodejs backends, and Nginx to deploy a site?

Polygon is a bit of a chore for newcomers to wrap their head around. Simplifying it for those people is important, but it isn't easy. Web3 currently doesn't think like that for us, the developer. We need tools to easily manage wallet state, chain IDs, and network switching. Why on Earth does Web3 use both an integer and hexadecimal representation of the chain ID?

I think being a little bit thick is helpful sometimes to understand when things don't make sense. However, I hope I am not being like those homophobes who used to say, "Adam and Eve, not Adam and Steve!" when I was a kid. Those guys, and it was always guys...hmmm...were pretty thick too. Maybe we are all degenerates and nobody has any idea what is going on. We could all just be vomiting dogma based on the current state of something. Remember when Jakob Nielsen was cool? I do.

I guess now I'm just being nostalgic for a simpler time. One where a friend's sister hijacking the phone all night prevented your ICQ conversation. I have a feeling that this is the ICQ era of crypto. We will soon long for these days too I believe.

Log in or sign up for Devpost to join the conversation.

posted an update

Edvard and I coordinated the backend. We decided to use AWS Lambda for the metadata API, and our own server for file generation and leaderboards. Once minting is complete we can throw the metadata on IPFS.

Nadia and I had technical meetings in regards to the sprites. I refactored the the contract, frontend, and backend plan to her requirements. She's a believer in keeping things simple. I like to make things complicated. She usually gets her way. In this case it took me a day to adapt to the new sprite format. She combined the right hoof and the body.

We also decided to do 10 pigs total. Nadia selected the characters. We had raucous debates over a few days about who should be in and out. Our mutual shared goal though was freedom. We both hate censorship and cancel culture. We are willing to fight for our right to expression, creativity, and innovation.

The final cut was:

Pig Jong Un Donald Oinkler Che Chicharrón Jamón Castro Augusto Cochinillo Hugo Chicharrón Leonid Bacon Joseph Snortin Queen Swill II Napoleon Saveloy

While Donald Oinkler and the Queen are not despots, and the furthest thing from a socialist or authoritarian, neither were all of the animals in Animal Farm. Dissent, and shortcomings exist in many forms. Not every socialist thinker is a bad person, and not every libertarian ideologue is a good one.

Nadia and I both love the weird. Our current playlist in the car includes Industry Baby, many versions of the title Let's Go Brandon, Moranbong Band, and Russian music from perestroika. We wonder if Lil Nas X realizes he has crossover fans from the right who love him for who he is, or if our right wing friends realize we play North Korean propaganda on repeat for our newborn daughter.

We are all degenerates in some way. Politics makes for very strange alliances that can quickly turn into hate. As long as we are free to both love and hate, the world will find equilibrium.

Log in or sign up for Devpost to join the conversation.

posted an update

Nadia and I have spent the last week furiously working on our respective roles. Nadia has been illustrating the sprites for the pigs with a newborn feeding in hand. We take time giving each other two hour focus blocks. When the baby is with me, I play Animal Farm in English read by an Englishman. When the baby is with her, she plays Animal Farm in Russian language. We can't decide which voice actor is better, but we both agree a California American accent is absolutely unacceptable for anything educational. It is impossible to convey the true meaning of such a wonderful book from a highly imperfect, but self-aware socialist pig, when the accent is from someone clearly sheltered in life. The conflict of Orwell's simplistic ideology as a young man in India being tested in various ways in his journeys throughout the world mirrors that of our own journey, including our time working in Catalonia, India, Russia, Armenia, and the UK. The American son of a flower child with no worldview simply cannot summon the character of his words.

During our tea breaks, we discuss the things we must accomplish. Today I finished the smart contract, and was wiring up the frontend. It will need an audit, but like creative writing, it's best you wait a day to revise, and then you can hand off to other people. Edvard, our technical lead, will be auditing the contract when he has time next week.

I became of aware of the need for a narrated video of the project, so Nadia will now have to make OBS overlays and some promo art. This is ok, since she is almost done with the sprites.

Solidity is a joy to work with because it offers the non-traditional programmer constraints. It's more rigid, and while terrifying at first, it makes it clear how a project should progress. The frontend, art, and backend are all dependent on the functions in the smart contract. This must always come first. We have already had a couple art and mission related decisions that were made due to the call stack limit of 7 variables in a function. While I could have added functions to work around this limitation, it was a great reminder to keep it simple. Like this post, I tend to get verbose when writing code. :-)

Log in or sign up for Devpost to join the conversation.