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!
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
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.
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.
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.
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
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.
Make sure your images are in the images
folder, and the metadata.json
files were created in the metadata
folder.
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
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