Cardano

Cardano-client-lib: Minting a new Native Token in Java — Part III

This is the third part of cardano-client-lib series. In this post, I will explain how to create a new Native Token using Java. In this post also, we will be using Blockfrost backend api.

You can check Part I and Part II of this series before continuing with this post

  1. Cardano-client-lib: A Java Library to interact with Cardano -Part I
  2. Cardano-client-lib: Transaction with Metadata in Java- Part II

In Cardano, you can mint a new native token without writing a smart contract. Users can transact with ada, and an unlimited number of user-defined (custom) tokens natively.

Let’s create a new native token.

  1. Project and account setup

If you have not setup your project yet, please follow the step-1 to step-6 from Part I.

2. Create a Policy Script & Policy Id

In Cardano, token minting policies are written using multi-signature scripts. This allows the asset controller to express conditions such as the need for specific token issuers to agree to mint new tokens, or to forbid minting tokens after a certain slot.

The library provides following classes to create different types of supported policies :

  • ScriptPubKey
  • ScriptAll
  • ScriptAny
  • ScriptAtLeast
  • RequireTimeAfter
  • RequireTimeBefore

You can build a very simple minting policy, which grants the right to mint tokens to a single key or build a complex policy by combining above classes.

In this post, we will create a simple policy, which grants the right to mint tokens to a single key.

Let’s create a key-pair which we can be used to create the policy.

Keys keys = KeyGenUtil.generateKey();
VerificationKey vkey = keys.getVkey();
SecretKey skey = keys.getSkey();

Create a ScriptPubKey, which grants the right to mint tokens to the above generated key.

ScriptPubkey scriptPubkey = ScriptPubkey.create(vkey);

We can now generate policy id from scriptPubKey object.

String policyId = scriptPubkey.getPolicyId();

3. Define our new native token using MultiAsset class

Create an instance of MultiAsset class. Use the policy id generated in previous step. Create an asset object with a custom name and token quantity.

MultiAsset multiAsset = new MultiAsset();
multiAsset.setPolicyId(policyId);
Asset asset = new Asset("TestCoin", BigInteger.valueOf(250000));
multiAsset.getAssets().add(asset);

4. Attach Metadata to Mint Token transaction (Optional)

If you want to attach some metadata to this token mint transaction, you can do so using Metadata apis provided by the library.

CBORMetadataMap tokenInfoMap
        = new CBORMetadataMap()
        .put("token", "Test Token")
        .put("symbol", "TTOK");

CBORMetadataList tagList
        = new CBORMetadataList()
        .add("tag1")
        .add("tag2");

Metadata metadata = new CBORMetadata()
        .put(new BigInteger("770001"), tokenInfoMap)
        .put(new BigInteger("770002"), tagList);

5. Create Token Minting request

Create a token minting transaction request using MintTransaction class.

MintTransaction mintTransaction =
        MintTransaction.builder()
                .sender(sender)
                .mintAssets(Arrays.asList(multiAsset))
                .policyScript(scriptPubkey)
                .policyKeys(Arrays.asList(skey))
                .build();

Note: Apart from setting the multiAsset object created in the step-3, we are also adding our policy script (scriptPubKey) and policy secret key (skey) which were generated in step-2.

If you don’t set policy script and policy keys, the token mint transaction will fail.

If the receiver field is not set, the minted token will be allocated to the sender account.

6. Calculate TTL (Time To Live) and fee

Calculate TTL

long ttl = blockService.getLastestBlock().getValue().getSlot() + 1000;
TransactionDetailsParams detailsParams =
        TransactionDetailsParams.builder()
                .ttl(ttl)
                .build();

Calculate fee and set the fee in mint transaction

BigInteger fee
         = feeCalculationService.calculateFee(mintTransaction,            detailsParams, metadata);

mintTransaction.setFee(fee);

7. Submit the Mint Token transaction

Finally, submit the token mint transaction using TransactionHelperService.

Result result 
         = transactionHelperService.mintToken(mintTransaction,     detailsParams, metadata);
if(result.isSuccessful())
    System.out.println("Transaction Id: " + result.getValue());
else
    System.out.println("Transaction failed: " + result);

8. Check transaction details in Cardano Explorer

Now go to Cardano Testnet Explorer and check transaction details.

It may take some time for the transaction to be mined.

You should now see the minted token under the receiver’s address. (If no receiver is specified, under sender’s address)

9. Get details of our newly minted asset

First get asset id by combining previously generated policy id and then the HEX encoded value of our asset name.

String policyId = "abe83f0124320fc4e6f50605e7986390453bcc0c913c920a249545eb";
String assetName = HexUtil.encodeHexString("TestCoin".getBytes(StandardCharsets.UTF_8));

String assetId = policyId + assetName;

Then use AssetService to get asset details.

Result asset = assetService.getAsset(assetId);
System.out.println(JsonUtil.getPrettyJson(asset.getValue()));

Output:

{
  "policy_id" : "abe83f0124320fc4e6f50605e7986390453bcc0c913c920a249545eb",
  "asset_name" : "54657374436f696e",
  "fingerprint" : "asset1uw2v9tzrp6ntvzc48l28j2jc2r4k569hxxk463",
  "quantity" : "4000",
  "initial_mint_tx_hash" : "d9da361f3e5237832cfcbdea16d440c9ea3e5026c7370c368291aafb5c2646a6"
}

10. Create complex policies by combining different script classes

In the below policy script example, we are creating a ScriptAll policy by combining RequireTimeBefore and ScriptAtLeast script.

//Key 1 - Single Key Policy
Tuple tuple1 = ScriptPubkey.createWithNewKey();
ScriptPubkey scriptPubkey1 = tuple1._1;
SecretKey sk1 = tuple1._2.getSkey();
//Key 2 - Single Key Policy
Tuple tuple2 = ScriptPubkey.createWithNewKey();
ScriptPubkey scriptPubkey2 = tuple2._1;
SecretKey sk2 = tuple2._2.getSkey();
//Key 3 - Single Key Policy
Tuple tuple3 = ScriptPubkey.createWithNewKey();
ScriptPubkey scriptPubkey3 = tuple3._1;
SecretKey sk3 = tuple3._2.getSkey();
//AtLeast policy with min-required key 2
ScriptAtLeast scriptAtLeast = new ScriptAtLeast(2)
        .addScript(scriptPubkey1)
        .addScript(scriptPubkey2)
        .addScript(scriptPubkey3);

long slot = getTtl();
RequireTimeBefore requireTimeBefore = new RequireTimeBefore(slot);
//Create the final ScriptAll policy by combining RequireTimeBefore and ScriptAtLeast
ScriptAll scriptAll = new ScriptAll()
        .addScript(requireTimeBefore)
        .addScript(
                scriptAtLeast
        );

You can print the the JSON value of Script object and store it in a file. The generated JSON object is compatible with cardano-cli command line tool.

Full source code:

public void mintToken() throws ApiException, AddressExcepion, CborSerializationException {
        BackendService backendService =
                BackendFactory.getBlockfrostBackendService(Constants.BLOCKFROST_TESTNET_URL, Constant.BF_PROJECT_KEY);
        FeeCalculationService feeCalculationService = backendService.getFeeCalculationService();
        TransactionHelperService transactionHelperService = backendService.getTransactionHelperService();
        BlockService blockService = backendService.getBlockService();

        String senderMnemonic = "kit color frog trick speak employ suit sort bomb goddess jewel primary spoil fade person useless measure manage warfare reduce few scrub beyond era";
        Account sender = new Account(Networks.testnet(), senderMnemonic);

        Keys keys = KeyGenUtil.generateKey();
        VerificationKey vkey = keys.getVkey();
        SecretKey skey = keys.getSkey();

        ScriptPubkey scriptPubkey = ScriptPubkey.create(vkey);

        String policyId = scriptPubkey.getPolicyId();

        MultiAsset multiAsset = new MultiAsset();
        multiAsset.setPolicyId(policyId);
        Asset asset = new Asset("TestCoin", BigInteger.valueOf(50000));
        multiAsset.getAssets().add(asset);

        CBORMetadataMap tokenInfoMap
                = new CBORMetadataMap()
                .put("token", "Test Token")
                .put("symbol", "TTOK");

        CBORMetadataList tagList
                = new CBORMetadataList()
                .add("tag1")
                .add("tag2");

        Metadata metadata = new CBORMetadata()
                .put(new BigInteger("770001"), tokenInfoMap)
                .put(new BigInteger("770002"), tagList);


        MintTransaction mintTransaction =
                MintTransaction.builder()
                        .sender(sender)
                        .mintAssets(Arrays.asList(multiAsset))
                        .policyScript(scriptPubkey)
                        .policyKeys(Arrays.asList(skey))
                        .build();

        long ttl = blockService.getLastestBlock().getValue().getSlot() + 1000;
        TransactionDetailsParams detailsParams =
                TransactionDetailsParams.builder()
                        .ttl(ttl)
                        .build();


        BigInteger fee
                = feeCalculationService.calculateFee(mintTransaction, detailsParams, metadata);
        mintTransaction.setFee(fee);

        Result<String<\g; result
                = transactionHelperService.mintToken(mintTransaction,     detailsParams, metadata);
        if(result.isSuccessful())
            System.out.println("Transaction Id: " + result.getValue());
        else
            System.out.println("Transaction failed: " + result);

    }

Resources

  1. Cardano-client-lib GitHub repository (https://github.com/bloxbean/cardano-client-lib)
  2. Example Source code (https://github.com/bloxbean/cardano-client-examples)

Published on Java Code Geeks with permission by Satya Ranjan, partner at our JCG program. See the original article here: Cardano-client-lib: Minting a new Native Token in Java — Part III

Opinions expressed by Java Code Geeks contributors are their own.

Satya

Satya is a solution architect and developer with more than 20 years of experience who has worked in a wide variety of organizations from product development, banking to IT consultancy. He is also a blockchain enthusiast.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button