Skip to main content

Cardano Native Asset (NFT) 💰

Who is this guide for?

  • For people who want to make NFT's or Native Assets on Cardano
  • For people who know about Cardano

Benefits of NFT's on Cardano

  • Low transaction fees
  • Native on the blockchain

Prerequisites

danger

We made this tutorial for use with Raspberry-Pi-ARM machines running on Linux OS so make sure to download the correct node.js for your local machine/CPU and OS. Currently, the Cardano-node and Cardano-cli are meant to be built from source on Linux machines. Any other OS will have its own build complexities, and we do not cover them in any of our tutorials as of right now. How to build Cardano Node from source

info

If you are using a Raspberry Pi machine here is an easy-to-follow tutorial we made to get a Cardano Relay Node running.

  • cardano-node / cardano-cli set up on local machine
  • Make sure you have a Cardano node running and fully synced to the database
  • Make sure node.js installed
>_ Terminal
#Copy/Paste this into your terminal if node.js is not installed
curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
sudo apt-get install -y nodejs

Verify everything is set up properly on our machine ⚙️

>_ Terminal
#Copy/paste into terminal window
cardano-cli version; cardano-node version

Your output should look like this 👇

>_ Terminal
cardano-cli 1.34.1 - linux-aarch64 - ghc-8.10
git rev 0000000000000000000000000000000000000000
cardano-node 1.34.1 - linux-aarch64 - ghc-8.10
git rev 0000000000000000000000000000000000000000

Verify our node.js version is correct and is on v14.16.1

>_ Terminal
#Copy/paste into terminal window
node -v
>_ Terminal
v14.19.0

Video Walk-through:

Create our project directory and initial setup

Make sure our $NODE_HOME environment variable exists

>_ Terminal
# check for $NODE_HOME
echo $NODE_HOME

If the above command didn't return anything, you need to set the$NODE_HOMEbash environment variable or use a static path for the Cardano node's socket location in 'db' C in your Cardano node directory.

>_Terminal
export NODE_HOME="/home/ada/pi-pool"
# Change this to where cardano-node creates socket
export CARDANO_NODE_SOCKET_PATH="$NODE_HOME/db/socket"

Now let's make our projects directory then create our package.json file and install the cardanocli-js package.

>_ Terminal
mkdir cardano-minter
cd cardano-minter
npm init -y #creates package.json)
npm install cardanocli-js --save
  1. Copy the Cardano node genesis latest build number from the IOHK hydra website
  2. Create a bash shell script to Download the latest Genesis config file needed
>_ Terminal
nano fetch-config.sh
>_ Terminal
echo export NODE_BUILD_NUM=$(curl https://hydra.iohk.io/job/Cardano/iohk-nix/cardano-deployment/latest-finished/download/1/index.html | grep -e "build" | sed 's/.*build\/\([0-9]*\)\/download.*/\1/g') >> $HOME/.bashrc
wget -N https://hydra.iohk.io/build/${NODE_BUILD_NUM}/download/1/testnet-shelley-genesis.json

Now we need to give permissions to our new script to execute then we will run our script and download the genesis files.

>_ Terminal
sudo chmod +x fetch-config.sh
./fetch-config.sh

Next, we make our src folder/directory and then create the Cardano client.

>_ Terminal
mkdir src
cd src
nano cardano.js
info

If you are using testnet make sure you have the correct testnet-magic version number. You can find the current testnet version here or simply look in your testnet-shelley-genesis.json file in your cardano node directory.

src/cardano.js
const CardanocliJs = require("cardanocli-js");
const os = require("os");
const path = require("path");

const dir = path.join(os.homedir(), "cardano-minter");
const shelleyPath = path.join(
os.homedir(),
"pi-pool/files",
"testnet-shelley-genesis.json"
);

const cardanocliJs = new CardanocliJs({
// era: "mary",
network: 'testnet-magic 1097911063',
dir,
shelleyGenesisPath: shelleyPath,
});

module.exports = cardanocliJs

Video Walk-through

Create a local wallet

>_ Terminal
nano create-wallet.js
src/create-wallet.js
const cardano = require("./cardano");

const createWallet = (account) => {
cardano.addressKeyGen(account);
cardano.stakeAddressKeyGen(account);
cardano.stakeAddressBuild(account);
cardano.addressBuild(account);
return cardano.wallet(account);
};

createWallet("ADAPI");
>_ Terminal
cd ..
node src/create-wallet.js

Verify balance wallet balance is Zero, then we fund the wallet

  • First, we need to create a get-balance.js script
>_ Terminal
cd src
nano get-balance.js
src/get-balance.js
// create get-balance.js
const cardano = require("./cardano");

const sender = cardano.wallet("ADAPI");

console.log(sender.balance());
  • Now, Check the balance of our wallet.
>_ Terminal
cd ..
node src/get-balance.js
  • We can go ahead and send some funds (ADA) into our wallet we created, wait a few minutes, and then check the balance again to make sure the transaction was successful.
info

If you are using testnet you must get your tADA from the testnet faucet here.

Video Walk-through

Mint our Native-Asset/NFT on Cardano

Before we proceed to mint our Native Asset we must have a few things taken care of. We need to first get our "asset" onto our IPFS node and generate the IPFS link. If you do not know about IPFS or what it actually does we recommend having a read through the documentation here or watching this video.

Since we are using an image file to be our asset we should upload a smaller thumbnail-sized version of our image (ideally less than 1MB). This will be used on sites like pool.pm to display our assets nicely in our wallets. We then upload the full-size image as our source image.

  • Download IPFS
  • Upload your asset's files to IPFS
  • Get our image thumbnail IPFS link
  • Get the src IPFS link

For reference:

  • image (thumbnail version) - ipfs://QmQqzMTavQgT4f4T5v6PWBp7XNKtoPmC9jvn12WPT3gkSE
  • src (full-size version) - ipfs://Qmaou5UzxPmPKVVTM9GzXPrDufP55EDZCtQmpy3T64ab9N

Create our mint-asset.js script

This script has three main components:

  1. Generate policy id
  2. Define your metadata
  3. Create mint transaction
>_ Terminal
nano mint-asset.js
src/mint-asset.js
const cardano = require("./cardano")

// 1. Get the wallet

const wallet = cardano.wallet("ADAPI")

// 2. Define mint script

const mintScript = {
keyHash: cardano.addressKeyHash(wallet.name),
type: "sig"
}

// 3. Create POLICY_ID

const POLICY_ID = cardano.transactionPolicyid(mintScript)

// 4. Define ASSET_NAME

const ASSET_NAME = "TimeWarpBerry"

// Convert Asset ASCII name to HEX

const ASSET_NAME_HEX = ASSET_NAME.split("").map(c => c.charCodeAt(0).toString(16).padStart(2, "0")).join("");


// 5. Create ASSET_ID

const ASSET_ID = POLICY_ID + "." + ASSET_NAME_HEX

// 6. Define metadata

const metadata = {
721: {
[POLICY_ID]: {
[ASSET_NAME]: {
name: ASSET_NAME,
image: "ipfs://QmUxRuzTi3UZS33rfqXzbD4Heut7zwtGUhuD7qSv7Qt584",
description: "Time Warp Berry NFT",
type: "image/png",
src: "ipfs://QmUxRuzTi3UZS33rfqXzbD4Heut7zwtGUhuD7qSv7Qt584",
// other properties of your choice
authors: ["PIADA", "SBLYR"]
}
}
}
}

// 7. Define transaction

const tx = {
txIn: wallet.balance().utxo,
txOut: [
{
address: wallet.paymentAddr,
value: { ...wallet.balance().value, [ASSET_ID]: 1 }
}
],
mint: [
{ action: "mint", quantity: 1, asset: ASSET_ID, script: mintScript },
],
metadata,
witnessCount: 2
}



if(Object.keys(tx.txOut[0].value).includes("undefined")|| Object.keys(tx.txIn[0].value.includes("undefinded"))){
delete tx.txOut[0].value.undefined
delete tx.txIn[0].value.undefined
}

// 8. Build transaction

const buildTransaction = (tx) => {

const raw = cardano.transactionBuildRaw(tx)
const fee = cardano.transactionCalculateMinFee({
...tx,
txBody: raw
})

tx.txOut[0].value.lovelace -= fee

return cardano.transactionBuildRaw({ ...tx, fee })
}

console.log(tx)
const raw = buildTransaction(tx)

// 9. Sign transaction

const signTransaction = (wallet, tx) => {

return cardano.transactionSign({
signingKeys: [wallet.payment.skey, wallet.payment.skey ],
txBody: tx
})
}

const signed = signTransaction(wallet, raw)

// 10. Submit transaction

const txHash = cardano.transactionSubmit(signed)

console.log(txHash)
  • Run the minting script, then wait a few moments to check the balance in our wallet
>_ Terminal
cd ..
node src/mint-asset.js

Video Walk-through:

Sending your NFT back to Daedulus or Yoroi wallet

Now we must create a new script to send our newly minted NFT to a wallet.

>_ Terminal
cd cardano-minter/src
nano send-back-asset-to-wallet.js

There are few main parts we have to this script in order to send the asset:

  1. Get the wallet
  2. Define the transaction
  3. Build the transaction
  4. Calculate the fee
  5. Pay the fee by subtracting it from the sender's utxo
  6. Build the final transaction
  7. Sign the transaction
  8. Submit the transaction
cardano-minter/src/send-back-asset-to-wallet.js
const cardano = require("./cardano");

// 1. get the wallet
// 2. define the transaction
// 3. build the transaction
// 4. calculate the fee
// 5. pay the fee by subtracting it from the sender utxo
// 6. build the final transaction
// 7. sign the transaction
// 8. submit the transaction

const sender = cardano.wallet("ADAPI");

console.log(
"Balance of Sender wallet: " +
cardano.toAda(sender.balance().amount.lovelace) +
" ADA"
);

const receiver =
"addr_test1qqqydvg5wzd6twvernsjcdjd9akmygyqp7gky7zpm0hrmq3ccwlnumzzuum6k6ja2k47g5dv2p4kwt753mpjjzx8fsmsq2aj0p";

const txInfo = {
txIn: cardano.queryUtxo(sender.paymentAddr),
txOut: [
{
address: sender.paymentAddr,
amount: {
lovelace: sender.balance().amount.lovelace - cardano.toLovelace(1.5),
},
},
{
address: receiver,
amount: {
lovelace: cardano.toLovelace(1.5),
"9e57c3a4aa769063ab4963e3e2fc18aeafb6808b3adbc3f1670a9c00.54696d65576172704265727279": 1,
},
},
],
};

const raw = cardano.transactionBuildRaw(txInfo);

const fee = cardano.transactionCalculateMinFee({
...txInfo,
txBody: raw,
witnessCount: 1,
});

//pay the fee by subtracting it from the sender utxo
txInfo.txOut[0].amount.lovelace -= fee;

//create final transaction
const tx = cardano.transactionBuildRaw({ ...txInfo, fee });

//sign the transaction
const txSigned = cardano.transactionSign({
txBody: tx,
signingKeys: [sender.payment.skey],
});

//subm transaction
const txHash = cardano.transactionSubmit(txSigned);
console.log("TxHash: " + txHash);
>_ Terminal
cd ..
node src/send-back-asset-to-wallet.js

Final Steps to view your NFT

  1. View your nft in your wallet
  2. View your asset on cardanoassets.com
  3. View your asset on pool.pm (see the actual picture)
  4. Show the original minting metadata
  5. Open the src and image ipfs links in your browser to prove that it worked

Video Walk-through

tip

If you liked this tutorial and want to see more like it please consider staking your ADA with any of our Alliance's Stake Pools, or giving a one-time donation to our Alliance https://cointr.ee/armada-alliance.