Creating a Flexible NFT (Part 2)

Part 2

Step 1: Make new netlify project

We begin Part 2 by creating a web page in the same folder as the rest of our code.

touch ./index.html && echo "hello world : )">./index.html

Great that's a beautiful website! Let's deploy it to the internet. Create a git repo, commit your code, and push to the origin:

git add .&& git commit -m 'new website'&& git push -u origin master

I use netlify for hosting because they have an all in one package for deploying sites from repositories, running a build process, adding SSL for custom domains and the ability to add lambda functions. They also have authentication and form handling, but I've never used those features. You could use AWS or Google firebase. Go to netlify.comand register using your github/gitlab/bitbucket account.

We're creating an API endpoint that returns the metadata for our NFT. I know what you're thinking, "isn't this an evil centralized solution??". Yes it is. Why? Because the alternative still sucks. Until we live in a world where I can expect my IPFS file to persist after I stop seeding it, and where I don't have to wait forever for the content, we have to use the current Internet infrastructure. If you look at any successful NFT project, they're doing the same thing. The biggest NFT marketplace, opensea.io, caches all the NFT data they can find and serves it directly. This is because it's better than relying on decentralized solutions at this point. When the decentralized solutions are viable, then our NFT will have an upgradeable metadata endpoint!

Back to netlify, we allow them to have API access to our repo so that they can deploy changes.

Find our repo and select it.

We don't need to add a build command or a publish directory because our website is just one index.html file and it's in the project root. You are probably already on master branch so that won't need to change (although netlify can auto-deploy each branch on a new domain if you want it to). Next click "Deploy site".

If you want to change your site name from the auto generated name, click Site settings and scroll down to Change site name. I changed mine to "block-workshop" which makes it available at https://block-workshop.netlify.com once the deploy process has completed.

If everything went well you should see this beautiful website:

Step 2: Install netlify lambda

Install netlify-lambda as a dev dependency so we can access it with npx. This is a utility for building the lambda function and serving it locally so you can test functions before deploying them.

yarn add netlify-lambda -D
# or
npm install netlify-lambda --save-dev

Add a directory where your lambda functions live. Call it lambda as that makes sense.

mkdir lambda

Create a configuration .toml file for netlify to define where our functions are served from:

touch netlify.toml

Now add the key functions to the toml file which is where the functions are served from after the netlify-lambda builds them:

The file exports a function called handler. This is the same format that AWS uses for their lambda functions (because netlify is a wrapper around AWS). If you have a lambda function you've used with AWS, you can use it with netlify, and if you have any advanced trouble shooting requests regarding these functions, add "AWS" to your query and not "netlify".

Run a local server so we can test the endpoint using the netlify-lambda utility:

This is the deployed format for the functions so that there aren't any name conflicts with your current routing. This is inconvenient syntax though, we'll add proxy rules to the metadata endpoint in a later step.

Step 3: Add Metadata

Now that we've created a dummy endpoint, let's make one that's more useful. Create a new file in your lambda directory called metadata.js and fill it with the same hello world code from before. (Or duplicate the helloworld.js file):

callback which ends the request and fills it with content and header information.

We handle requests for our token metadata that follows the format we built into our Metadata.sol contract. That means it's a GET request with the token ID built into the route of the URL, like https://domain.com/metadata/{tokenId}. To pass GET parameters we use a format like https://domain.com/metadata?tokenId={tokenId}. We could define our tokenURI to follow a format like this, but that's ugly.

Let's work with this format for now and improve it later. We log the event to see if we can find the tokenId parameter passed to the URL. This is easier to do in our local setup so follow the URL pattern http://localhost:9000/metadata?tokenId=666

Add some console.logs to the metadata.js handler function so we can read what's going on in those parameters:

To be compliant with EIP-721 and EIP-1047, the Token Metadata JSON Schema should follow the following format:

{"title":"Asset Metadata","type":"object","properties":{"name":{"type":"string","description":"Identifies the asset to which this token represents",},"description":{"type":"string","description":"Describes the asset to which this token represents",},"image":{"type":"string","description":"A URI pointing to a resource with mime type image/* representing the asset to which this token represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive.",}}}

Lets try returning this, but replace the name with the tokenId, and return an autogenerated image, for example https://dummyimage.com/600x400/000000/fff/&text=test%20image.

Return it in the callback function, and stringify the JSON object before returning it:

callback(null,{
statusCode:200,
body:JSON.stringify(metadata)});

When we check our endpoint (and if you have a JSON prettier browser extension) it returns this:

Step 4: Add proxy routing

On netlify we still use the inconvenient URL format, /.netlify/functions/metadata?tokenId=666, to see the new endpoint. Open the netlify.toml file and add some re-write rules so that we can transform a pretty URL like /metadata/666 into something that our lambda function understands like /.netlify/functions/metadata?tokenId=666:

This redirects queries from /metadata to whatever is at the location /.netlify/functions/metadata. The :tokenId placeholder designates that the value should carry over to the same location in the other url. The status it should returns in the header is 200 which means success.

Step 5: Add opensea.io

To make sure our metadata shows up on sites like opensea we want to serve a format the service understands. The Opensea docs say they expect metadata that adheres to the following example:

{"description":"Friendly OpenSea Creature that enjoys long swims in the ocean.","external_url":"https://openseacreatures.io/3","image":"https://storage.googleapis.com/opensea-prod.appspot.com/puffs/3.png","name":"Dave Starbelly","attributes":[...],}

What do you know! It follows it's own spec! You can now see why it's important to maintain flexibility around your metadata endpoint. Until we live in a world that has settled on a standard that everyone uses and isn't hosted on a lambda function on netlify.

Return to our etherscan certified token and mint our first token. You should see that our updateMetadata transaction is listed there now.

Since I'm using a metamask account that is the same as my deploy account, I have permission to mint a token. Open the write contract tab, authenticate with metamask, and mint a token.

Since I added my own address as the recipient, I should be the proud owner of token #1. I can check using the token view of etherscan we saw before.

Wow, there's a token!

Open opensea and see if they've noticed that we exist. With rarebits and opensea you have to request that they track your token before it shows up in the sidebar, but you can skip that by hard coding the contract address in to the URL. Knowing our token address is at 0x1170a2c7d4913d399f74ee5270ac65730ff961bf and our tokenId is 1 we are able to visit the rinkeby version of the URL like this:

Article Author

1 Comment

Related Articles

Creating a Flexible NFT (Part 1)

Creating a Flexible Non-fungible token The first part of this tutorial shows you how to deploy a Non-fungible token (NFT) using a technique that makes it easy to update details about your token as infrastructure and your needs change. The second part of this tutorial will show how to create a serverless solution for serving your token details as metadata. This is a widely used web2 infrastructure solution that is cheap and scaleable. It is not decentralized; This is a solution for using the Inte

Truffle: Adding a frontend with react box

Earlier in the series, we took a look at how to setup Truffle and use it to compile, deploy and interact with our Bounties.sol smart contract. This article will walk through the steps required to add a simple react.js front end to our Bounties dApp so that users can interact with our smart contract using their web browser. Source code for this tutorial can be found here. Truffle Box Truffle boxes are helpful boilerplate code, pre-configured to help you get up and running quickly developing your