Concordium Semi-Fungible Token Minting Tutorial

Bogachan Yigitbasi
15 min readOct 23, 2022

--

Hello there! In this tutorial, we are going to mint semi-fungible tokens on Concordium using Node-SDK. Before we start, let me remind you this, there are multiple ways to mint NFTs on Concordium, using other Concordium SDKs. Some of them may be easier for you based on your prior experience. You can find all the SDKs and other useful materials from this link and we will use concordium-client for the next tutorial to show an alternative command line tool.

In the last tutorial, we have covered many things including how you can mint an NFT on Concordium and set up our development environment including node configurations, mobile wallet and key exports, decrypting wallet in order to get our signKey, build, deploy, initialize, mint and transfer. If you have any issues regarding these steps, either you can check that tutorial or you can post it to our developer support platform.

Because of so much work we have done about setting up in the last one, we will be focusing on primarily the minting part in this tutorial but as you know we have a cool announcement, Concordium Wallet browser extension is released! Therefore, I’ll be using the web wallet for this one and all of the upcoming tutorials. You can find detailed information about it in this link from the website.

You can start by cloning the repository by running the command below.

git clone -b post2 --recurse-submodules https://github.com/chainorders/concordium-nft-tutorials.git

We are going to use this smart contract that is provided by Concordium team. And the flow will be the same as the first tutorial, first we will go over the wallet setup and key exports, then focus on the storage solutions and preparation of metadata, and finally development part including minting, transferring and querying balances.

Semi-Fungible Tokens

When do you need a semi fungible token or why do you need them in the first place? Of course depending on your use case; they can really add more value to your project as they bring both fungibility and non-fungibility, not to mention that it may arise as a significantly cheaper option than minting non-fungible tokens for everything. Let me shed a bit more light on these vague words, and you can find more info in this article.

Assume that you are about to visit an exhibition and it’s expected 10.000 people will visit it therefore there are 10.000 tickets. You have 3 tickets for you and your friends. You can change your ticket with your friends or anyone else, or you can buy that ticket from anyone who will not make it? The only thing that matters to the person at the entrance is, do you have a ticket to enter the place. Because there is no difference in that sense, any one of those tickets will allow you to join the event. So you have to have at least one of them but it doesn’t really matter which one. We utilize both fungibility and non-fungibility in this way. This is a perfect use case for a semi-fungible token!

What if there are different groups of tickets like the bronze and gold ones for example gold ones have direct access to the party tonight with a very limited amount? Then you will need to mint 2 types of semi-fungible tokens like 10000 bronze concert tickets and 400 exclusive fan tickets. You can implement your use case with regular NFTs with a 10400 minting process and it will exactly give you the same functionality. Well, that will come with some additional costs, right? On the other hand, minting two semi-fungible tokens (with a 10000 + 400 supply) is way cheaper than minting 10400 NFTs.

If you’ve read the semi-fungible article you can skip this part but one of the most brilliant use cases of them is in gaming and the metaverse. They are widely used in online gaming today. In-game items, characters, gold, and coins are perfect examples of it. You can push your imagination, the possibilities are endless I guess, for example I really like the idea of Steve Jobs’s semi-fungible figure on the Sandbox metaverse. As you can see it’s minted as 100 and that indicates 100 different owners could have a right to use it in their game basically. (or only one owner can use it 100 times of course, it’s some sort of licensing in that sense)

Concordium Wallet Web Extension

Let’s start with our brand new wallet, if you don't have it you can install it from this link. Once you installed the web extension to your chrome browser you will have a cute Concordium Wallet logo in your extensions.

You can place the CCD wallet among others!

When you click it, it will ask you to accept the terms and conditions and you’ll proceed to the next screen. !IMPORTANT! In this window, you will see a 24-word passphrase, basically they are referring to your private key, so you need to make sure that it’s protected, save them in a secure place-safest write them on a piece of paper and lock it in your vault on the bank. You can find more information on this link about it but basically, anyone who knows these passphrases can access your wallet. And now temporarily copy and paste them somewhere to look while retyping it because we are going to create your first wallet!

As a next step, the wallet will ask for that 24-word passphrase in the same order. When you fill it out in the textbox, it will be initiated your first wallet.

Since this is a tutorial, we are going to use a testnet wallet and luckily, Concordium has provided a test account for developers, which means you are not obliged to participate in the ID verification procedure. But I need to remind you that the real beauty behind this blockchain is ID. If you want to read more about its advantages, practical use cases, real-world scenarios, and more you can visit the website. Anyway, let's get back to our topic, basically, you should select the Concordium Testnet, and from the next window select the Concordium IP. Just hit the submit button and you will be created your first testnet identity.

Then you need to create an account, by clicking on the “Create Account” button and selecting Concordium as the answer to “Which identity should create the account?” You will create your first account, congratulations! Initially, it will look a bit grey, but when the verification process is done your wallet will have a green background.

Great, what’s next? Now we need to get the test CCDs. It’s a very easy step, just click the “Request CCD” button and the transaction will be transferred to your wallet. And when the second transaction is done you will have your 2000 testnet CCDs. All of your previous transactions will be listed below in this window since we established referring to the Today section. Before going deeper about screens, let me change the theme. I love it with the dark theme. In the “Wallet Settings” window you will see a toggle button to go to the dark mode and you will see how fancy it looks.

If you click the arrow icon, the second one from the bottom left you will enter transaction window. It will allow you to transfer CCDs. You can type the amount of CCD and need to define the recipient’s address in this section. As you can see just below those textboxes, there is a value highlighting the “Estimated transaction fee” in CCD terms. While I am writing this tutorial CCD price is around 0.01167 and the estimation is 0.83489, multiply those which makes 1 euro-cent as it’s expected. That is one of Concordium’s strengths, right? You can estimate the costs beforehand and it allows helps you to calculate your business expenses in the future. In the QR section, you can copy your wallet address and if you are on mobile you can scan the QR code with your camera and it will read automatically the address of the account.

In the last section, you can export your private key which is important for us to develop. Finally, now we have only one step before starting the development of the tutorial! Let’s get our signKey from the wallet export file. When you click the export file button it asks you for the passcode (the one you entered at the beginning, not 24 words) to show your private key.

When you do the steps above you will be able to download it actually with a name like this <YOUR PUBLIC ADDRESS>.export. Open it up with a text editor and you will find your signKey, verifyKey in there. Copy signKey and your address. We will use it while deploying and interacting with our contract.

Decentralized Storage — IPFS

In the first tutorial, we went through all the necessary steps describing how to install and run an IPFS node and uploaded an image together in order to get a CID (Content Identifier) based URL for our token. This time, we will use a tool called Pinata pinning service. It is free for less than 1GB of storage, I strongly recommend you have an enterprise account for commercial projects. What it does is basically, they are running a node that pinned your data which makes you don't have to run a node on your system. As it’s a peer-2-peer decentralized storage solution, remember there has to be at least one node that stores your data. That is why running a node on a server that pins your own data for commercial projects is always a good decision. Anyway, Pinata does that for you.

When you sign-up for it, you’ll be redirected to a dashboard. You can either upload your files one by one using the upload button or you can use the API key. I’ll prefer the second option, it may get things a bit complex but definitely will provide you more flexibility and save some time especially if you are going to mint multiple tokens. And if you are a bit nerd like me, it makes you feel like you have more control over it.

Installation of Pinata

First, make sure you have npm installed on your system, then run the command below. This will install the pinata upload tool to your computer.

npm i -g pinata-upload-cli

Then you will need a token provided by Pinata. In your profile section when you click it, you’ll see an API Keys section. Visit that page and create an API Key for yourself. You can check the details in this link. Copy the JWT and the other API data and store them somewhere as explained and add the JWT token value in the command below. That will authenticate you as the owner of that pinata account

pinata-cli <JWT>

Now, from your device you are able to upload data to Pinata, those will be pinned by it and you can use it freely. We will store this image, as gratitude of us for Satoshi. Run the command below to upload your data file. If you are in the media folder just type its name and the extension like: satoshi.png

pinata-cli -u ../PATH_TO/<YOUR DATA>

If it’s successful you will have something like the above, pay attention to this IpfsHash value. It is your asset’s unique Content Identifier (CID). You can see the image in this link. God, love that cartoon!

Metadata

For our semi-fungible token, we will create metadata that holds the IPFS link inside of it, a description, a name, and the attributes of course based on CIS-2 standard. For more details, you can check the previous tutorial’s metadata section or CIS-2 from this link.

Generate your own metadata.

Upload your metadata with the command below and your metadata will be stored on the IPFS.

pinata-cli -u ../PATH_TO/<YOUR METADATA>.json
https://ipfs.io/ipfs/QmSyhV2EuRm2id48QkKiFHtQkwhyxB1s2F6xP3b6Sty553

Build Contract Module

Finally, we have everything prepared in order to mint our tokens. We have created a wallet, exported it, and stored our data on IPFS using Pinata. We have an API Key, that will allow us to upload from our system, both our data and metadata are available and pinned already so we will not worry about running a local node. We are ready to mint our semi-fungible tokens.

Make sure you are working in the cis2-multi directory, and create a dist folder for our schema and smart contract compiled into wasm. One small reminder here, remember CIS-2 allows you to mint fungible, non-fungible and semi-fungible tokens. Concordium’s token standard is applicable to all types of tokens.

cd cis2-multi
mkdir -p ../dist/smart-contract-multi
cargo concordium build --out ../dist/smart-contract-multi/module.wasm.v1 --schema-out ../dist/smart-contract-multi/schema.bin

Install Required Packages

We are going to invoke some functions from our deployed contract using ts-client and will cover minting and transferring NFTs. You can install all the dependent packages with either “yarn” or “npm” if you don't have the node in your system you should install it first.

cd node-cli
yarn install
yarn add -g ts-node

Deploy Contract Module

When you cloned the repository, all necessary functions for node-cli were automatically cloned into the node-cli folder. These functions allow you to interact with the smart contract. Basically, there are 1:1 implementations of all functions in the smart contract. Please make sure you have the function below, in the cli.ts file.

Run the command below in order to deploy the contract that is built in the previous step.

ts-node ./src/cli.ts deploy --wasm ../dist/smart-contract-multi/module.wasm.v1 --sender $ACCOUNT --sign-key $SIGN_KEY

If you have the output below, congrats! You’ve successfully deployed your semi-fungible token smart contract on Concordium!

You can also verify it either by looking at the ccdscan or the testnet dashboard lookup section. Now what we need to do is go to the dashboard and get the hash value from there, using the url in the terminal. Simply copy the link from the terminal and visit to look at the status of your transaction. Click on the “Deployed module with reference” and copy the hash value. We are going to use it while initializing the contract in the next section.

Hey, wait for a minute.. It should also be possible to check it from the wallet, right? Let’s check it. Excellent!

You can see the transaction details.

Initialize Contract

Now we need to initialize the deployed contract, it’s a lot easier than the previous steps. After deploying a contract we have to initialize it, it’s like object-oriented programming. We create a class which is a module, and then we initialize it to create an object, right? Which is the same here. An object of a class is a way to store both states of the class and its functionality. This time we are going to use the hash value we got in the previous step. First, make sure initialize function is implemented in your cli.ts file.

Run the code below, here we use hash value in the <MODULE-HASH> part, signKey from your exported key file, contract name as <YOUR-CONTRACT-NAME> (in this case CIS2-Multi), and the address of your account. That will create another transaction on the chain obviously.

ts-node ./src/cli.ts init --module <MODULE-HASH> --sender <ACCOUNT-ADDRESS> --sign-key <SIGN-KEY> --contract <YOUR-CONTRACT-NAME>

If you have this output that means you are successfully initialized your contract. Now let’s go to that URL to get our contracts index value. From the dashboard, you can easily see the index, my account address as sender, event details, and transaction hash. The Index value is important here, it’s like the address of my contract instance, we will need it when we are interacting with the contract.

Mint Function

Now, we are ready to call our mint function. First, you should place the setupCliUpdateContract function below in your cli.ts file. In this step, we serialize the parameters taken from the terminal that is going to be input for our update function.

Run the command below with the index value you get in the previous step, your account address, and the signKey from your exported private key file. Also, you need to set the mint parameters in the mint-multi-params.json file described below. The account address is my wallet address, we are going to generate 10000 copies of it, URL is the Pinata link of the metadata file and the hash is the SHA-256 output of the link.

ts-node ./src/cli.ts mint --sender $ACCOUNT --sign-key $SIGN_KEY --wait --contract CIS2-Multi --schema ../dist/smart-contract-multi/schema.bin --params ../nft-artifacts/mint-multi.json --index <CONTRACT_INDEX>

Let’s check the dashboard one more time by using the url value from the terminal.

We have just minted 10000 semi-fungible tokens on Concordium successfully! As you can see the cost is around 6.105 CCD, which makes 0.0759525 Euros for 10000 semi-fungible tokens! Today 1 CCD is $0.01238, you can check the current price from this link. Again, I’d like to highlight something, this indicates nothing! This cost fully depends on the amount of data you stored on the chain. As we stored only a metadata link and a hash value relatively small amount of CCD is required in order to mint.

Let’s get the metadata on-chain and see what we have in there. In order to do that, we will use setupCliInvokeContract and we are gonna use view functions since with this function we are not going to change the state of the blockchain, there will be no transaction fee. This is almost the same with the setupCliUpdateContract except there are no internal state changes in the smart contract. View functions will read the current state of the contract.

We can expect the IPFS URL pinned by Pinata that we add in the metadata.json file and a hash value as we add it in the mint function. I just wanted to show you how can you store on-chain another value in addition to the url. In order to get the details on-chain run the following command. If you are using cargo-concordium 2.1.0 you dont need to specify the schema but for newer versions add <YOUR SCHEMA NAME>. You can check the version of your cargo-concordium with the commands cargo-concordium — help or cargo-concordium — version

ts-node ./src/cli.ts view --sender $ACCOUNT --contract CIS2-Multi --schema ../dist/smart-contract-multi/schema.bin --index <CONTRACT_INDEX>

Transfer Function

Now, we will transfer one token to someone else assume that you are organizing an event/exhibition in your virtual theatre and your guests/visitors have to have a ticket in order to pay you a visit. Go to the transfer-multi.json file and change the parameters accordingly. From is the sender address, To is the receiver address, also you need to specify the token_id and the amount.

These parameters will be read by the command below and put accordingly as arguments while running however you can also specify them as parameters.

ts-node ./src/cli.ts transfer --params ../nft-artifacts/transfer-multi.json --schema ../dist/smart-contract-multi/schema.bin --index <YOUR INDEX> --sender <ACCOUNT-ADDRESS> --sign-key <SIGN-KEY> --contract <YOUR-CONTRACT-NAME>

Now let’s check the current state of our token contract with view command in the previous step.

Brilliant! As you can see, the owner has 9995 tokens left and my second account has 5 as we specified the amount of token to transfer. Using these tickets, me and my 4 friends can enter the venue now!

--

--

Bogachan Yigitbasi

Computer Engineer | Blockchain Enthusiast | Life-Time Learner | NFT | Gaming| Web3