steppsr


How To Mint Using CLI

Want to mint some NFT from the CLI? You've come to the right blog!

This blog is written for Linux CLI.

Let's get started!


Project Folder Structure

Here is the folder structure you should create. 

~/project_name/
    deploy/
        images/
        metadata/

Here are the Linux commands to create the folder structure:

cd ~
mkdir project_name
cd project_name
mkdir deploy
cd deploy
mkdir images
mkdir metadata

The banner, icon, and license files, should be put into the deploy folder.

The metadata.csv file, should be in the project_name folder.

The following scripts should be in the project_name folder:

gen_metadata_files.sh
gen_mint_commands.sh
upload.sh

Icon, Banner, & License Files

Before we do anything else, we want to get the icon, banner, and license files put into the folder structure and uploaded to the web so we'll have URLs to use later when creating the metadata files. Once the files are in the deploy folder, then we will be ready to upload the files.

Prior to June 30, 2024, we'll use NFT.storage to upload the files. You will need an API Key from NFT.storage to use in the script.

After June 30, you may want to research filebase.com. I'll update later with more details to use filebase.

Best size for Icon file is:  350 pixels by 350 pixels.

Best size for Banner file is a 4:1 ratio. I use 1568 pixels by 392 pixels.

Bash - upload.sh Source Code

#!/bin/bash
#
# DESCRIPTION:	upload image to nft.storage
# USAGE:		bash upload.sh upload filename.png
# 1st parameter is the action to perform. 2nd parameter is the filename
#   upload      upload file to nft.storage and get back the CID, hash, and URI
#

# USER CONFIG -- BEGIN
apikey=""
fingerprint=""
wallet_id=""
fee="1"
royaltybasispoints="400"
royaltyaddress=""
targetaddress=""
# USER CONFIG -- END

# application working folder
appdir=`pwd`

# input parameters
action=$1
fname1=$2

cid=""
remote_datahash=""
local_datahash=""

upload_file() {

    fname=$1
    get_content_type $fname
    contype=$?
    get_output_type $contype
    otype=$?
    response=`curl -s -X 'POST' "https://api.nft.storage/upload" -H "Content-Type: $contype" -H "Authorization: Bearer $apikey" --data-binary "@$fname"`
    cid=`echo $response | jq -r '.value.cid'`
    remote_hash=`curl -s "https://$cid.ipfs.nftstorage.link" | sha256sum | cut -c 1-64`
    local_hash=`sha256sum $fname | cut -c 1-64`
    uri="https://$cid.ipfs.nftstorage.link"
    d=`date +'%Y-%m-%d %h:%i:%s'`
    if [ "$remote_hash" == "$local_hash" ]; then
        echo "$d ==== $otype ====" >> $appdir/.upload.log
        echo "$d CID : $cid" >> $appdir/.upload.log
        echo "$d Hash: $local_hash" >> $appdir/.upload.log
        echo "$d URI : $uri" >> $appdir/.upload.log
        return 0
    else
        echo "$d The hashes between local and remote did not match. $fname" >> $appdir/.upload.log
        return 1
    fi
}

get_content_type() {
    fname=$1
    case $fname in
        *.md)
            contype="text/markdown"
            otype="LICENSE";;
        *.json)
            contype="application/json"
            otype="METADATA";;
        *.png)
            contype="image/*"
            otype="IMAGE";;
        *.jpg)
            contype="image/*"
            otype="IMAGE";;
        *.webp)
            contype="image/*"
            otype="IMAGE";;
        *.gif)
            contype="image/*"
            otype="IMAGE";;
        *.svg)
            contype="image/*"
            otype="IMAGE";;
        *.jpeg)
            contype="image/*"
            otype="IMAGE";;
        *.tiff)
            contype="image/*"
            otype="IMAGE";;
        *.tif)
            contype="image/*"
            otype="IMAGE";;
        *.psd)
            contype="image/*"
            otype="IMAGE";;
        *.pdf)
            contype="image/*"
            otype="IMAGE";;
        *.eps)
            contype="image/*"
            otype="IMAGE";;
        *.ai)
            contype="image/*"
            otype="IMAGE";;
        *.indd)
            contype="image/*"
            otype="IMAGE";;
        *.raw)
            contype="image/*"
            otype="IMAGE";;
    esac
    return 0
}

get_output_type() {
    contype=$1
    case $contype in
        image/*)
            otype="IMAGE";;
        application/json)
            otype="METADATA";;
        text/markdown)
            otype="LICENSE";;
    esac
    return 0
}

case $action in
    upload)
        upload_file $fname1
        get_content_type $fname1
        get_output_type $contype
        echo "$local_hash,$uri"
        ;;
esac

Be sure to update the top of the script to input your parameters such as "apikey", "fingerprint", "wallet_id", etc.

To run the script to upload the files:

cd ~/project_name
bash upload.sh upload .\deploy\banner.png
bash upload.sh upload .\deploy\icon.png
bash upload.sh upload .\deploy\license.pdf

You will want to save the values for CID, Hash, and URI for each file. We'll need these later.


Create UUID for the Collection ID

You will need an ID for the Collection. Each metadata.json file will use that ID in the metadata.json file.

The CHIP-0007 specification requires a UUID for the value.

You can use Online UUID to create UUID for you project.


Create The metadata.csv File

The metadata.csv file will be used by the script to generate all the individual metadata.json files for your NFTs. You can build the metadata.csv file in a spreadsheet application or just a text editor. Just be sure to save it as a CSV file and put it into the project_name folder.

The format is:  Filename, NFT Name, Attribute 1, Attribute 2

Example file:

001.png,S-Q,Era=50s,Fetish=Pixel Passion: Captivated by the crisp clarity of high-resolution robotic vision.
002.png,K1-L2,Era=50s,Fetish=Bot Bondage: Enthralled by the constraints and controls of robotic limbs.
003.png,4-YHE,Era=50s,Fetish=Binary Bliss: Delighting in the pure digital dance of zeros and ones.

Create Metadata JSON Files

I have created  a Bash script to help create all the metadata.json files for you NFTs.

Bash - gen_metadata_files.sh Source Code

#!/bin/bash

###################################
#### Process the images        ####
###################################
echo "Generate Metadata Files"
echo "-----------------------"

appdir=`pwd`
updir="./deploy/metadata"
cd $updir

# LOG FILE
logfile="$appdir/run.log"

###################################
#### Create the Metadata files ####
###################################

c=0
# open metadata.csv master file

# loop through each line and create metadata file
input="$appdir/metadata.csv"
while IFS= read -r line
do
    this_file=$(echo "$line" | cut --fields 1 --delimiter=,)
    this_name=$(echo "$line" | cut --fields 2 --delimiter=,)

    this_attr_1=$(echo "$line" | cut --fields 3 --delimiter=,)
    this_attr_1_name=$(echo "$this_attr_1" | cut --fields 1 --delimiter== | tr -d '\n')
    this_attr_1_value=$(echo "$this_attr_1" | cut --fields 2 --delimiter== | tr -d '\n')

    this_attr_2=$(echo "$line" | cut --fields 4 --delimiter=,)
    this_attr_2_name=$(echo "$this_attr_2" | cut --fields 1 --delimiter== | tr -d '\n')
    this_attr_2_value=$(echo "$this_attr_2" | cut --fields 2 --delimiter== | tr -d '\n')

    c=$(($c+1))

	filename=$(basename -- "$this_file")
	extension="${filename##*.}"
	filename="${filename%.*}"

    # build the collection json first
    md_col_name="YOUR_PROJECT_NAME"
    md_col_desc="YOUR_DESCRIPTION"
    md_col_id="YOUR_UUID"

	# icon image (typicall 350x350 or 512x512 pixels)
	md_col_att1_label="icon"
	md_col_att1_value="YOUR_ICON_URL"

	# banner image (typically 1568x392 pixels)
	md_col_att2_label="banner"
	md_col_att2_value="YOUR_BANNER_URL"

    md_col_att3_label="twitter"
    md_col_att3_value="YOUR_TWITTER_USERNAME"

    md_col_att4_label="website"
    md_col_att4_value="YOUR_WEBSITE"

    # make a json object for the collection metadata
    json_collection=`jq -n --arg id "$md_col_id" --arg name "$md_col_name" --argjson attributes "[$images]" '$ARGS.named' `

    # append attributes into the collections attributes array
    json_collection=`echo $json_collection | jq	'.attributes += [{"type":"'"$md_col_att1_label"'", "value": "'"$md_col_att1_value"'"}]'`
    json_collection=`echo $json_collection | jq	'.attributes += [{"type":"'"$md_col_att2_label"'", "value": "'"$md_col_att2_value"'"}]'`
    json_collection=`echo $json_collection | jq	'.attributes += [{"type":"'"$md_col_att3_label"'", "value": "'"$md_col_att3_value"'"}]'`
    json_collection=`echo $json_collection | jq	'.attributes += [{"type":"'"$md_col_att4_label"'", "value": "'"$md_col_att4_value"'"}]'`

    # build the main json file
    format="CHIP-0007"
    
    #Title will have Collection Name, NFT Number, and NFT Name
    imgtitle="$md_col_name: #$filename $this_name"
    imgdesc="YOUR_DESCRIPTION"
    minter="Bash CLI"
    #sensitivity. Should be true or false DO NOT wrap in double quotes. The value needs to be boolean, not string for CHIP-0007
    sens=false

    image_json=`jq -n --arg format "$format" --arg name "$imgtitle" --arg description "$imgdesc" --arg minting_tool "$minter" --argjson sensitive_content $sens --argjson collection "$json_collection" '$ARGS.named' --argjson attributes "[]" `
    
	# append attributes into the attributes array
    image_json=`echo $image_json | jq '.attributes += [{"trait_type": "'"$this_attr_1_name"'", "value": "'"$this_attr_1_value"'"}]'`
	image_json=`echo $image_json | jq '.attributes += [{"trait_type": "'"$this_attr_2_name"'", "value": "'"$this_attr_2_value"'"}]'`

	# write the metadata json into the output file
    printf "$image_json" > "$filename.json"

	# write to screen during runtime (and to a log file)
	echo "$c - $filename.json $a $this_name"

done < "$input"

cd $appdir

Be sure to update all the "YOUR" values for your project. 

To run the script to create the metadata.json files:

bash gen_metadata_files.sh

Validate the JSON File Schema

I would recommend using one of the created JSON files to validate the JSON was created & formatted correctly. You should be able to copy the contents of one of the JSON files and paste into the "Input JSON" (right) box on JSON Schema Validator - CHIP-0007. If you do have issues, you can delete all the JSON files, edit the script to make corrections, then run the `bash gen_metadata_files.sh` script again.


Images & Metadata Files

Make sure your images are in the images folder, and the metadata.json files were created in the metadata folder.


Create Mint Commands

The gen_mint_commands.sh script will take all your information and build the commands to mint your NFTs.

Bash - gen_mint_commands.sh Source Code

#!/bin/bash

appdir=`pwd`

cid=""
fingerprint=""
wallet_id=""
royalty_points="500"
fee="0.000000000001"
royalty_address=""
target_address=""
license_hash=""
license_uri=""

outfilename="mint_commands.sh"
echo "#!/bin/bash" > $outfilename

echo "Beginning NFT Collection Mint..."
for i in $(seq -w 001 100)
do
	echo "$i"
	data_uri="https://$cid.ipfs.nftstorage.link/$i.png"
	meta_uri="https://$cid.ipfs.nftstorage.link/$i.json"

	echo "data_uri = $data_uri"
	echo "meta_uri = $meta_uri"
	
	remote_data_hash=`curl -s "$data_uri" | sha256sum | cut -c 1-64`
    data_hash=`sha256sum $appdir/deploy/images/$i.png | cut -c 1-64`

	remote_meta_hash=`curl -s "$meta_uri" | sha256sum | cut -c 1-64`
    meta_hash=`sha256sum $appdir/deploy/metadata/$i.json | cut -c 1-64`

    if [ "$remote_data_hash" == "$data_hash" ]; then
        if [ "$remote_meta_hash" == "$meta_hash" ]; then
			# now lets build a mint command
			mint_cmd="aba wallet nft mint -f $fingerprint -i $wallet_id -ra $royalty_address -ta $target_address -nh $data_hash -u $data_uri -mh $meta_hash -mu $meta_uri -lh $license_hash -lu $license_uri -m $fee -rp $royalty_points"
			echo $mint_cmd >> $outfilename
        else
        	echo "The metadata hashes between local and remote did not match. $i.json" >> $outfilename
        fi
    else
        echo "The data hashes between local and remote did not match. $i.png" >> $outfilename
    fi

	echo "sleep 300" >> $outfilename

done

Be sure to update all the settings at the top of the script for your project: cid, fingerprint, wallet_id, royalty_points, fee, royalty_address, target_address, license_hash, license_uri.

Note: the script expects the image file to have a "PNG" extension, if you used a different filetype, you will need to adjust the script for your file extension.

Note: you will need to adjust the "for" loop for the number of NFTs in your project, and also the number scheme. The script assumes leading zeros on the number and the number will be the name of the image and metadata file. Example:  001.png and 001.json

Note: you may wish to adjust the value in the sleep command. The script is using 300 seconds (5 mins) and the time between mint commands. Adjust as you see fit but just know this is "batch minting" and not "bulk minting" so you'll need time for wallet to catch up. The NFTs are minted one at a time and not 25 in each spend bundle.

This script was written for the ABA Blockchain, but you can easily do a search & replace of "aba wallet" for "chia wallet" on the output file if you want to use with Chia instead.

To run the script to create the mint_command.sh script:

bash gen_mint_commands.sh

mint_commands.sh

The final result is the mint_commands.sh script. This will be a list of each mint command to run. You can keep and run the whole script at once, or break it into multiple batches as desired. For example, maybe you have a total of 200 NFTs but you want 100 in the first batch and 100 in the second batch, this is easy to do by just using cut/paste to move half the mint commands to a new file.

To run the script to mint:

bash mint_commands.sh