# Create Metadata

This assumes there already was a previous deployment to rinkeby, with the utilization of `AdvancedCollectible[-1]`

### Setup

* create new folder "metadata" in brownie project root
* create new file: sample\_metadata.py
* create new folder within metadata, "rinkeby"

{% code title="sample\_metadata.py" %}

```python
metadata_template = {
    "name": "",
    "description": "",
    "image": "",
    "attributes": [{"trait_type": "cuteness", "value": 100}]
}
```

{% endcode %}

![](https://1628544884-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTgomzlmn9NrxUY0OQ3cD%2Fuploads%2FCiYeUXIQKVg99rOcGuW5%2Fimage.png?alt=media\&token=2e12eaf6-c4a9-4187-a251-011a8f42b1f3)

### create\_metadata.py

In our scripts folder, create new file: create\_metadata.py

We will use this script to assign the URI for each NFT.

{% hint style="info" %}
talk about NFT token URI etc - what, how
{% endhint %}

{% code title="create\_metadata.py" %}

```python
from brownie import AdvancedCollectible, network
from metadata.sample_metadata import metadata_template
from pathlib import Path

breed_mapping = {0: "PUG", 1: "SHIBA_INU", 2: "ST_BERNARD"}

def get_breed(breed_number):
    return breed_mapping[breed_number]


def main():
    advanced_collectible = AdvancedCollectible[-1]
    number_of_NFTS = advanced_collectible.tokenCounter()
    print(f"The number of NFTs minted so far is {number_of_NFTS}")

    for tokenID in range(number_of_NFTS):
        breed = get_breed(advanced_collectible.tokenIdToBreed(tokenID))
        metadata_filename = f"./metadata/{network.show_active()}/{tokenID}-{breed}.json"
    
        collectible_metadata = metadata_template
        if Path(metadata_filename).exists():
            print(f"{metadata_filename} exists! Delete to overwrite")
        else:
            print(f"Creating Metadata file: {metadata_filename}")
            collectible_metadata["name"] = breed
            collectible_metadata["description"] = f"An adorable {breed} pup!"
            print(collectible_metadata)

            image_path = "./img" + breed.lower().replace("_", "-") + ".png"
            image_uri = upload_to_ipfs()
            collectible_metadata["image_uri"] = image_uri

```

{% endcode %}

* call on previous rinkeby deployment
* check number of NFTs minted
* for each tokenID, get the breed via get*breed(),* and structure the filename and path as metadata\_filename

![metadata\_filenamecollectible\_metadata](https://1628544884-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTgomzlmn9NrxUY0OQ3cD%2Fuploads%2FDsulF4aPboz43TbnwO65%2Fimage.png?alt=media\&token=bf4de4ec-8784-4333-93ea-51e64ef775ca)

* collectible\_metadata collects the metadata\_template to be used as a base for modification
* We then check if the required metadata\_filename exists, using Path library.&#x20;
* Else, we will create a new one using the template as reference, adding the following
  * name
  * description
  * image URI ->  collectible\_metadata\["image\_uri"] = image\_uri

### image-uri

How do we get the image URI? Currently the images are in our local img folder. We need them to be hosted on IPFS and pass their IPFS URI into collectible\_metadata\["image\_uri"]&#x20;

To that end, we will have to install IPFS cli:[ ](https://docs.ipfs.io/how-to/command-line-quick-start/)<https://docs.ipfs.io/how-to/command-line-quick-start/>

{% hint style="info" %}
Interestingly, ipfs daemon command works in terminal, command prompt.
{% endhint %}

On running ipfs daemon on terminal we will see the following:

![](https://1628544884-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTgomzlmn9NrxUY0OQ3cD%2Fuploads%2F3Biweuce0GfaAEvNuJcx%2Fimage.png?alt=media\&token=03690554-190a-4c51-b126-ac92a0c72939)

We will be working with **/api/v0/add** to add our file to IPFS: <https://docs.ipfs.io/reference/http/api/#http-rpc-commands>

{% tabs %}
{% tab title="upload\_to\_ipfs(filepath)" %}

```python
def upload_to_ipfs(filepath):
    # open image as binary - open(rb)
    with Path(filepath).open("rb") as fp:
        image_binary = fp.read()
        ipfs_url = "http://127.0.0.1:5001"     #get from WebUI 
        endpoint = "/api/v0/add"
        response = requests.post(ipfs_url + endpoint, files={"file":image_binary}) #post request
        ipfs_hash = response.json()["Hash"]     #response returns dictionary
        # "./img/0-PUG.png"  -> split on /, grab last part of array, which is "0-PUG.png"
        filename = filepath.split("/")[-1:][0]
        image_uri = f"https://ipfs.io/ipfs/{ipfs_hash}?filename={filename}"
        print(image_uri)
        return image_uri
```

{% endtab %}

{% tab title="def main" %}

```python
def main():
    advanced_collectible = AdvancedCollectible[-1]
    number_of_NFTS = advanced_collectible.tokenCounter()
    print(f"The number of NFTs minted so far is {number_of_NFTS}")

    for tokenID in range(number_of_NFTS):
        breed = get_breed(advanced_collectible.tokenIdToBreed(tokenID))
        metadata_filename = f"./metadata/{network.show_active()}/{tokenID}-{breed}.json"
    
        collectible_metadata = metadata_template
        if Path(metadata_filename).exists():
            print(f"{metadata_filename} exists! Delete to overwrite")
        else:
            print(f"Creating Metadata file: {metadata_filename}")
            collectible_metadata["name"] = breed
            collectible_metadata["description"] = f"An adorable {breed} pup!"
            print(collectible_metadata)
            # convert underscores to dashes to be URI compatible
            image_path = "./img/" + breed.lower().replace("_", "-") + ".png"
            image_uri = upload_to_ipfs(image_path)
         #   collectible_metadata["image_uri"] = image_uri
```

{% endtab %}
{% endtabs %}

* ipfs\_url -> retrieved from running ipds daemon
* endpoint -> as per api endpoint reference
* response -> structuring and sending a post response (can also use curl)
* ipfs\_hash -> response returns JSON string on successful call to endpoint - decode it as a python dict via .json()

![reponse returns a dictionary](https://1628544884-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTgomzlmn9NrxUY0OQ3cD%2Fuploads%2F6225ELA959HCow84cZD5%2Fimage.png?alt=media\&token=e9689679-0ad6-421b-b8f6-9da9cc8d2b6f)

* extract filename from filepath and together with the IPFS hash, construct the image URI

{% hint style="info" %}
More on JSON: [https://www.usna.edu/Users/cs/nchamber/courses/forall/s20/lec/l25/#:\~:text=JSON%20at%20its%20top%2Dlevel,%2C%20other%20dictionaries%2C%20and%20lists.](https://www.usna.edu/Users/cs/nchamber/courses/forall/s20/lec/l25/)
{% endhint %}

#### print(image\_uri)

will return an ipfs link, like so:

<https://ipfs.io/ipfs/QmUPjADFGEKmfohdTaNcWhp7VGk26h5jXDA7v3VtTnTLcW?filename=st-bernard.png> &#x20;

{% hint style="warning" %}
The image will be available as long as you are running your ipfs node.

To make the data highly available without needing to run a local IPFS daemon 24/7, you can request that a remote pinning service store a copy of your IPFS data on their IPFS nodes.
{% endhint %}

#### Creating metadate files

Now that we have filled all the fields in the metadata file, we are going to write it as a json file into our directory.

```python
        with open(metadata_filename, "w") as file:
            json.dump(collectible_metadata, file)
        upload_to_ipfs(metadata_filename)
```

This will create a json file in our metadata/rinkeby folder upon running:

`brownie run scripts/advcollectible/create_metadata.py --network rinkeby`

![](https://1628544884-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTgomzlmn9NrxUY0OQ3cD%2Fuploads%2FrlNpLBJBVTn7N3TXtVOc%2Fimage.png?alt=media\&token=2326675c-cded-438a-ba7a-36fc30469be5)

#### Final code at this point:

```python
from brownie import AdvancedCollectible, network
from metadata.sample_metadata import metadata_template
from pathlib import Path
import requests, json

breed_mapping = {0: "PUG", 1: "SHIBA_INU", 2: "ST_BERNARD"}

def get_breed(breed_number):
    return breed_mapping[breed_number]


def main():
    advanced_collectible = AdvancedCollectible[-1]
    number_of_NFTS = advanced_collectible.tokenCounter()
    print(f"The number of NFTs minted so far is {number_of_NFTS}")

    for tokenID in range(number_of_NFTS):
        breed = get_breed(advanced_collectible.tokenIdToBreed(tokenID))
        metadata_filename = f"./metadata/{network.show_active()}/{tokenID}-{breed}.json"
    
        collectible_metadata = metadata_template
        if Path(metadata_filename).exists():
            print(f"{metadata_filename} exists! Delete to overwrite")
        else:
            print(f"Creating Metadata file: {metadata_filename}")
            collectible_metadata["name"] = breed
            collectible_metadata["description"] = f"An adorable {breed} pup!"
            print(collectible_metadata)
            # convert underscores to dashes to be URI compatible
            image_path = "./img/" + breed.lower().replace("_", "-") + ".png"
            image_uri = upload_to_ipfs(image_path)
            collectible_metadata["image_uri"] = image_uri
            
            with open(metadata_filename, "w") as file:
                json.dump(collectible_metadata, file)
            upload_to_ipfs(metadata_filename)


def upload_to_ipfs(filepath):
    # open image as binary - opne(rb)
    with Path(filepath).open("rb") as fp:
        image_binary = fp.read()
        ipfs_url = "http://127.0.0.1:5001"     #get from WebUI 
        endpoint = "/api/v0/add"
        response = requests.post(ipfs_url + endpoint, files={"file": image_binary})       #post request
        ipfs_hash = response.json()["Hash"]     #response returns dictionary. 
        # "./img/0-PUG.png"  -> split on /, grab last part of array, which is "0-PUG.png"
        filename = filepath.split("/")[-1:][0]
        image_uri = f"https://ipfs.io/ipfs/{ipfs_hash}?filename={filename}"
        print(image_uri)
        return image_uri   
```

{% hint style="info" %}
11:33 - Refactor to check if file has already been uploaded to IPFS, so we don't upload every single time. (check github for code)
{% endhint %}

### Alternative: Pinata

deploy to Pinata -> upload\_pinata.py

Reference: <https://docs.pinata.cloud/api-pinning/pin-file>   <br>

* create account at Pinata and generate api key
* 11:20 - 11:31

![](https://1628544884-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTgomzlmn9NrxUY0OQ3cD%2Fuploads%2FfbX7LNZnq7FQPcDWXe06%2Fimage.png?alt=media\&token=6c27c8a9-3330-4d75-9d3e-cc86d81093e0)

You should also see the pinned file:

![](https://1628544884-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTgomzlmn9NrxUY0OQ3cD%2Fuploads%2Ff1NkMRUfB5CX3AkxYRHc%2Fimage.png?alt=media\&token=f1c7479b-380c-44f7-921f-1e55b32ba16d)
