Grant request by Matic Mike

Submission Date

November 13, 2021

Project Links

Website: https://maticmike.club/

Project Description

Matic Mike was inspired by other high utility NFT projects in the space that are 100% on chain. We wanted to make something special that is fully on chain with no api, but also have a full functioning and easy to use interface for everyone to enjoy. The goal here is not only to release a fun, free project, but also to show how dynamic the NFT space can be, ranging from pure artwork to a full-scale collectibles game with it’s own ecosystem.

You can read a full rundown and guide of the current release here.

What it does

Full 25 minute detailed overview video

Matic Mike is a free, 100% on-chain generative ERC721 NFT game on the Polygon network with a Polygon <-> Ethereum bridge, and is accompanied by a fully compliant ERC20 Token, Matic Mike Juice ($HGH) with a Polygon <-> Ethereum bridge as well.

As stated, Matic Mike is a 100% on chain generated NFT. When we say 100%, we mean 100% as each Mike’s traits are chosen on mint, and drawn out pixel by pixel on chain. Every trait has a power level associated with it, with each Mike having their own power level associated with them. Power levels are used in all the gaming functionality which we’ll explain further down the line.

The Minting Process

Matic Mike is now fully minted on the Polygon chain. To onboard interested users, we airdropped $1000 in MATIC to users who signed up for our whitelist for gas on the Polygon network. The mint price was as follows…

  • 1-2500: Free Mint (1 per whitelist, and once public sale was actived, up to 10 per wallet)
  • 2500-4000: 1 $HGH
  • 4000-6000: 2 $HGH
  • 6000-8000: 3 $HGH
  • 8000-10000: 4 $HGH
  • After 2500, free “Burn Rerolls” were activated, allowing users to burn their mint and generate a new mint.

$HGH and It’s Uses

Let’s talk a little bit about $HGH and what it is used for in-game in Matic Mike NFT’s present state. Before we get into the functions of $HGH, we should talk about how to earn $HGH. As stated, Matic Mike was a 100% free mint, and after 2500 used our new ERC20 token $HGH. To earn $HGH, you must have a Mike, and he is staked “in the gym,” also known as the $HGH contract, with an emissions rate of 1 $HGH over 24 hours per Matic Mike staked in the $HGH contract. The first feature was obviously the tokenized minting process, now let’s take a look at the “token injections.”

ERC20 → ERC721 Token Injection

One of the unique features about the Matic Mike NFT is the ability to dynamically modify traits all on-chain at the cost of $HGH. We call this “Token Injection” and it is the process of burning off $HGH for a small chance to upgrade the tier of rarity of a random trait. This was a feature included in our initial release 2 weeks ago. The cost to inject Matic Mike for a chance to upgrade started at 1 $HGH and increases on a global scale by 3 $HGH for every successful injection. Token injections have about a 5.5% success rate, and the $HGH used per attempt is burned from the circulating supply. We’ll explain how this is built in the next section.

The PvP Battle Royale

The other current use of $HGH is our player vs player battle royale contract, also known as the “Dance Royale.” This is a rolling 50 man queue system done completely on-chain that costs 1 $HGH to enter, with the option of adding 0-5 additional $HGH for adding 1-10 power level per additional $HGH injected. The optional injection $HGH is burned from the circulating supply, while the entry fee is added to the pot for the current royale. Upon completion, the winner receives 70% of the royale pot, 2nd place receives 20%, and 3rd 10%.

A complete log of analytics are stored in the PvP Dance Royale contract, and our Web Interface gives a nice look at individual token stats. Analytics for wallet address data is also stored on-chain, with plans to integrate a future contract with a “name your wallet” function and a custom uri slug on the website. This will give complete analytical history for addresses even if you sell or trade your Mike in the future.

How we built it

The Matic Mike NFT and Matic Mike Juice ($HGH) initial release was a total of 5 smart contracts.

And the PvP Battle Royale Contract is one single contract, but 2 more contracts are planned in the near future for a more in-depth analytical look as well as the “Name your Club” contract.

The Matic Mike NFT Minting Process

Simulate Minting Here

Let’s first start by getting into the minting process of the Matic Mike NFT. Every mint generates new unique metadata by looping through and generating 8 random numbers (this part does not utilize chainlink VRF so we could quickly return to the user) which are used to determine the rarity of each trait. Depending on where the number falls, it selects a number (0-9) of the trait and pieces together a “hash” or “dna code” for the token id. That DNA code and token ID is sent to the data contract when pulling the tokenURI or other read calls and the metadata is generated on demand.

We also integrated the free “burn rerolls” which essentially sent the token id being burned to a dead address, and ran the same minting process over again. This is what pushed the mint to fully mint out very quickly. There are examples of all these functions in the 5 minute overview video.

The Data & Reading From the Data Contract

Let’s first start with how we populated the data. We store the data for each trait in a struct as follows…

struct Trait{
	string traitName;
	string traitType;
	string pixels;
	uint256 pixelCount;
	uint8 powerLevel;
}

This is pretty straight forward, but we should get into what the pixel string looks like, and how it works. Every “pixels” string is composed of each pixel by 4 characters, let’s use the example ab23. The first 2 characters represent the x and y coordinates, encoded as a letter. so a = 0, and b = 1. This mean’s we are plotting a pixel at 0,1. The last 2 characters represent a css class associated with the color. So we are plotting a pixel at 0,1 with a css class of “c23”. We loop through each trait and plot these pixel strings during our calls. Because we do have such a large mapping of pixels, we also loaded full XML of pre-plotted data for the body and outfits.

It is worth noting, for further expansion we include this bit of code…

if(xxlAddress != nullAddress){
    IMikeExtended.Traits[] memory XxlTraits = IMikeExtended(xxlAddress).getAllPlayerLoot(_tokenId);

    for(uint256 i=0; i < XxlTraits.length; i++){
        if(XxlTraits[i].valid && XxlTraits[i].pixelCount > 0){
            svgString = string(
                abi.encodePacked(
                    svgString,
                    XxlTraits[i].pixels
                )
            );
        }
    }
}

This is for our expansion projects, in which we’ll be able to pull new graphics directly into the SVG string. Each additional trait will be plotted in 1 long string.

The ERC721 contract will call the data contract for tokenURI (which grabs the attributes and SVG, and base64 encodes for return) and power level inqueries.

It’s worth noting, I drew everything out in photoshop, then mapped everything out pixel by pixel in a 24x24 SVG and wrote the style sheet that is stored on the data contract, this took over 30 hours.

The ERC20 Contract and Staking

Simulate Staking Here

The “gym” as we call it is a pretty simple mechanic. You stake your MIKE into the ERC20 contract ($HGH) and record the timestamp sent. You can claim the accumulated $HGH at any time, at an emissions rate of 1 per day per MIKE staked, with a max of 10 MIKEs per wallet staking.

Included in this is the same set of functionality, but mapped by contract addresses. This gives us the ability to add multiple contracts that can stake at different emissions rates for future projects. We plan on allowing our “Evil Club Owner” NFT to stake at an emissions rate of .25 $HGH per 24 hours.

ERC20 → ERC721 Token Injection

Simulate Token Injection Here
You must have a MIKE minted and unstaked, you can open $HGH faucet from #15 “openFaucet” on $HGH polygon mumbai contract

Our Matic Mike NFT contract allows for “injecting” Mike with the $HGH token for a chance to upgrade a random trait. We determine all randomization in this method by working off of a random number provided by a Chainlink VRF call. Let’s dig in.

First, we take payment in $HGH for the injection attempt. This is burned from the total supply, and a Chainlink VRF function is called, storing the request ID to the token being attempted at upgrade.

In our fulfillRandomness call we first check to see if we fall in the 5.5% range we’re looking for to proceed with the upgrade. If not, nothing happens, but if true, we’ll move onto the next call, which is determining which trait to try and upgrade. We do this by a simple modulo call to determine a 1-9 range.

Once the trait we are going to upgrade is selected, try to increase it’s rarity by 1 or 2 rarities by subtracting from the number (if > 0), recreating the “dna code” hash with the new number, and making sure it does not exist in the hash map (all MIKEs must remain unique). If it doesn’t exist, we save the hash to the token and it is now upgraded, otherwise, we continue to move rarity positions over by 1 to until we hit a successful upgrade which the hash doesn’t exist. If it steps through every combination and all hashes exist, the upgrade will also be unsuccessful.

Upon completion of a successful upgrade, we increase the global price of $HGH for upgrade attempts by 3. This is to preserve rarities and deflate $HGH supply.

The PvP Dance Royale Contract

First, let’s list the links involved with this contract interface so you can easily jump from page to page. Make sure you have your Mike minted if you plan on sampling the queue system. Please note, if you do want to test on live environment, please send “Mike Dev” a message in discord and I’ll send you some $HGH. $HGH has no max supply, and no faucet on mainnet, so I earn at the same rate as everyone else.

As mentioned in the previous section. The dance royale has a rolling 50 man queue system, which lowers to 15 man after 30 minutes if the queue hasn’t filled in an effort to keep queues rolling (all numbers and times are adjustable). Lets go through a few of the requirements to enter.

  1. We have an active flag in case we ever need to freeze entries for whatever reason.
  2. The optional $HGH added to your MIKE entering battle must be a non decimal integer
  3. The optional $HGH added must be less than the maximum allowed juice (adjustable, currently 5).
  4. You must be owner of the MIKE, however the MIKE can be staked in the $HGH contract.
  5. The current Royale Rumble id does not exceed the rumble size, and the battle is not already in progress.
  6. You can only enter a unique MIKE once per content.

It is also worth noting, if you are the first in queue, you populate the analytics for the last royale. This is not done during the actual royale call due to gas limitations and ensuring Chainlink doesn’t run out of gas during the callback.

Optional $HGH added is tracked and burned, before calling the Chainlink VRF function.

Here is the code for the enter royale function, it is pretty self explanatory. We make use of a lot of mappings to quickly handle all requests.

// enter battle royale
function enterRoyale(uint256 _tokenId, uint8 _hghJuice) public returns (uint256){
	require(active, "Dance Royale not currently active");
	require((_hghJuice * wagerMulti) % wagerMulti == 0, "HGH Amount cannot be a decimal");
	require(_hghJuice <= maxJuice, "Over the maximum juice amount");
	require(IHgh(hghAddress).balanceOf(msg.sender) >= (_hghJuice * wagerMulti) + currentPrice, "Not enough HGH in wallet balance");

	// check in gym as well
	require(IMaticMike(mmAddress).ownerOf(_tokenId) == msg.sender || IHgh(hghAddress).getStaker(_tokenId) == msg.sender, "Not the owner of token");
	require(royaleParticipants[_rumbleId.current()] < rumbleSize && !battleIsComplete[_rumbleId.current()], "Royale trigger currently in progress. Try again in a minute");

	// require that they are not already entered in the competition...
	require(!tokenToRumble[_tokenId][_rumbleId.current()], "Already entered in competition");

	// if new rumble populate analytics from previous rumble
	if(_rumbleId.current() != 0 && royaleParticipants[_rumbleId.current()] == 0){
		populateWinners(_rumbleId.current() - 1);
	}

	// burn the juiced up amount
	IHgh(hghAddress).burnFrom(msg.sender, _hghJuice * wagerMulti);

	// transfer 1 HGH to contract
	IHgh(hghAddress).transferFrom(msg.sender, address(this), currentPrice);

	// begin royale entry
	royaleParticipants[_rumbleId.current()]++;
	royalePot[_rumbleId.current()] = royalePot[_rumbleId.current()] + wagerMulti;
	tokenToRumble[_tokenId][_rumbleId.current()] = true;

	// Chainlink VRF
	bytes32 requestId = requestRandomness(keyHash, fee);

	responseIdToBattle[requestId] = BattleType(
		1,
		_rumbleId.current(),
		_tokenId,
		_hghJuice,
		wagerMulti
	);

	rumbleIdParticipants[_rumbleId.current()].push(_tokenId);
	tokenToRumblesEntered[_tokenId].push(_rumbleId.current());
	addressToRumblesEntered[msg.sender].push(_rumbleId.current());

	return _rumbleId.current();
}

Once a user has entered into the competition, we need to determine their roll. This is done by first calculating their power level. We assign a random additional powerlevel (up to the optional $HGH, multiplied by 9, plus the optional $HGH).

if(responseIdToBattle[requestId].juicedUp > 0){
	powerup = (randomness % (responseIdToBattle[requestId].juicedUp * 9)) + responseIdToBattle[requestId].juicedUp;
}

We then query the Matic Mike contract for power level, add it to the previous calculation, and determine the roll…

uint powerlevel = IMaticMike(mmAddress).getPowerLevel(responseIdToBattle[requestId].tokenId) + powerup;

address tokenHolder;

// check if in gym and assign accordingly
if(IMaticMike(mmAddress).ownerOf(responseIdToBattle[requestId].tokenId) != hghAddress){
	tokenHolder = IMaticMike(mmAddress).ownerOf(responseIdToBattle[requestId].tokenId);
}

else{
	tokenHolder = IHgh(hghAddress).getStaker(responseIdToBattle[requestId].tokenId);
}

uint256 roll = randomness % powerlevel;

rumbleIdToRolls[rumbleId].push(
	RollInfo(
		responseIdToBattle[requestId].tokenId,
		tokenHolder,
		roll
	)
);

Once all the entries are in for the current royale, we calculate the winner by looping through all the roles, coin flipping on ties, and saving 1st, 2nd, and 3rd place. Payouts are done instantly sending the $HGH pot as follows…

  • 70% to First Place
  • 20% to Second Place
  • 10% to Third Place

The next Royale queue begins immediately, and as previously state, the analytics are stored on the first person who queues the into the next royale.

It is worth noting, we are saving wins by Token ID as well as wins by Address. This is for the future “Name Your Club” project in which we’ll have full details on club wins and analytics whether they still hold the token which they won or lost with.

DiscordJS and Additional Functionality with Ethereum Bridge

We run a discord bot using discordjs running on our server using foreverjs. Some of the functionality we have implemented is…

  • /supply
    • returns circulating supply of $HGH, Matic Mikes, Unique Wallets Staking, Total Burned, and other useful info
  • /powerlevel {id}
    • Returns Powerlevel of the Token ID
  • /peek {address}
    • Returns all OpenSea links of the address, both staked and unstaked tokens
  • /snapshot {id}
    • Returns a snapshot of all the traits and an opensea link of the Token ID

The Ethereum Bridge TokenURI points to our website which runs a simple NodeJS script to query and return the polygon Matic Mike contract MetaData. For speed, we save a cached copy of the json on the server, and it is overwritten periodically with new data in case any upgrades occur or additional traits are pulled in in the future with our PvE contract.

Challenges we ran into

I had some hickups along the way as this was my first major blockchain project. I’ll go over each issue individually and how it was resolved.

Gas Limit Issues on Read Functions

I ran into the problem when calling the TokenURI where if a combination of traits led to a very large amount of pixels, it would run out of gas. This is because the body and clothing portion of the SVG uses a good amount of pixels. To resolve this, instead of drawing out these attributes pixel by pixel, I loaded in the entire section of the SVG and append it to the result in one loop. We still draw out most of the smaller traits pixel by pixel, but after realizing how low cost it is to populate something like this on Polygon, we could just load more data into the contract without having to worry about a pixel by pixel drawing.

Onboarding Users to Polygon Chain

It was very hard with our whitelist explaining how to get Matic on Polygon, as well as just getting users onboarded in general. I put a guide together prior to minting that helped with this, and automatically added the polygon network to their web3 wallet.

A Small Error in the Contract Code

When a MIKE was burn rerolled, we modify the “dna” hash to reflect that it has been burned, and a pitchfork type of drawing is placed on the MIKE signifying it has been sent to the dead wallet. I forgot to run this function when sending the hash to the data contract, so I had to replace the data contract mid mint to call back to the ERC721 contract to see if the token belongs to the DEAD address, and modify the hash on the data contract.

If I could go back and change it, I would probably integrate an upgradable contract to fix the error in the main contract.

OpenSea Not Refreshing MetaData and Not Having Polygon API

Instead of being able to force refresh metadata like you are able to on OpenSea with ethereum contracts, I needed to create a browser automation script that constantly runs to refresh metadata to reflect potential user upgrades from token injections, and in the future, loot from the boss contract NFTs.

Chainlink on Polygon

This was kind of a scary moment, but I had loaded some LINK onto the contract for Chainlink VRF functionality yet was getting an insufficient LINK balance. I quickly realized after re-reading the documentation that I needed to convert to the official LINK token on Polygon using the PegSwap service. This was a relief, however there is now some LINK stuck in the contract forever!

Marketing, Marketing, Marketing

I am in desperate need of marketing help for this project to gain attention and actually bring in more active users. Unfortunately due to the quick “flip” mentality on a lot of NFT projects, we have a good amount of users listing for a very low price on OpenSea and not participating in the PvP Dance Royale contract, and I’m afraid will not participate in my future PvE Evil Club Owners NFT contract I plan on releasing in December.

My goal with this hackathon is to hopefully place, and potentially draw some attention to the work I’ve been putting in on really expanding what NFTs can do.

Accomplishments that we’re proud of

  • 10,000 Matic Mikes were minted over the course of 12 hours
  • 7363 of those Mikes were burn rerolled, leaving a total supply of 2637
  • Of those 2637, we average over 2200 staked (in the gym). That signifies we have a lot of long-term holders
  • My ethereum bridge worked, although I am the only one who has used it
  • Almost 18,000 $HGH has been generated through staking over the course of this project
  • Over 632 unique wallets own a Matic Mike, which I am happy with that number
  • I was told by almost everyone on the night of minting that it was the most fun minting experience they ever had
  • The launch was relatively smooth for both the minting, and the PvP Battle Royale contract.
  • We are a week into the PvP Battle Royale, and already have over 50 Royales complete!

What we learned

  • Solidity, and working with blockchain in general
    • This was the first blockchain project I’ve worked on. I’ve been a big fan of Ethereum and Polygon in general but never got around to actually working with it. I now consider myself pretty up to speed with the core concepts.
  • Chainlink VRF - I had no idea until I started writing out the code I whiteboarded that true random numbers weren’t technically possible on chain. Chainlink VRF was a true asset with this. I am also very excited to expand my use of Chainlink in the future, and I’ve got some CRAZY ideas brewing.
  • DiscordJS and Web3
    • I was very happy to find DiscordJS and it was a pleasure to work with. You can do some really cool things with it and I think it is especially useful for web3 functionality
  • Reignited my passion for coding
    • I’ve been a full stack developer for 12 years, but this brought me back to college and not having the robust amount of documentation I am used to today. Although a lot of documentation exists, because blockchain is still relatively “new” you can’t just Google every problem and come up with a solution.
  • Learned just how much one can get done if TRULY motivated. This is the most amount of work I’ve done in the least amount of time I think in my entire career.

What’s next for Matic Mike NFT Game

The unreleased phase of our project is our PvE Evil Club Owners NFT contract. Although we won’t have time to complete this prior to the chainlink hackathon deadline, we should give a rundown so you can see more ways $HGH and the genesis Matic Mike NFT will play a role in the future of this project.

The idea is that Matic Mike will need to summon the Evil Club Owner NFT by staking in the Club contract, which will assign a randomized time period, between 1 week and 1 month, to summon out the Club Owner. You will also need to burn off 100 $HGH to start summoning the owner, and will be able to send more $HGH on a daily basis to reduce the amount of time it takes to summon the boss. My initial thought is 10 $HGH will reduce the amount of time Mike needs to be staked in the club by 1 hour.

Once the Evil Club Owner is spawned, not only will they be able to stake inside the gym and earn $HGH (at a lower emissions rate than Mike), they will also have a power level associated with themselves as well as a piece of loot. Matic Mike will be able to go into battle with his Evil Club Owner and if Mike is successful in defeating them, Mike will pull the trait and new graphic directly onto his original Matic Mike NFT. The club owner will only be able to be looted once, but will be used in future player vs player concepts. Each Matic Mike will be able to summon 2 club owners and a total of 2 new trait types with 9 different trait values will be randomly generated in the loot of the club owners.

The future of this project will be released in seasons, where the club owner and “name your club” contracts will finish up season 1, and season 2 will begin with Mike training a new apprentice, and the next chapter of PvP and PvE will revolve around Mike helping his apprentice through all walks of life in this crazy NFT space.

Amount requested

50000 USD

Milestones

$10,000 Marketing: Launching of Evil Club Owners NFT - Early December
$10,000 Marketing: Season 2 begins Jan 1, Launch the Name your Club & Club Analytics
$10,000 Marketing: Mid January - Launching the $HGH Marketplace, design your club and buy items with $HGH to increase your overall wallets base power level
$10,000 Marketing: Early February - Launch the Club Owners vs Matic Mikes PvP Contract
$10,000 Marketing: Early March - Launch the Matic Mike Train Your Apprentice Contract to close out season 2

Grant Request Status

Approved

2 Likes