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
- Cardano-client-lib: A Java Library to interact with Cardano -Part I
- 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.
- 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<String> 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> 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<ScriptPubkey, Keys> tuple1 = ScriptPubkey.createWithNewKey();
ScriptPubkey scriptPubkey1 = tuple1._1;
SecretKey sk1 = tuple1._2.getSkey();//Key 2 - Single Key Policy
Tuple<ScriptPubkey, Keys> tuple2 = ScriptPubkey.createWithNewKey();
ScriptPubkey scriptPubkey2 = tuple2._1;
SecretKey sk2 = tuple2._2.getSkey();//Key 3 - Single Key Policy
Tuple<ScriptPubkey, Keys> 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:
Resources
- Cardano-client-lib GitHub repository (https://github.com/bloxbean/cardano-client-lib)
- Example Source code (https://github.com/bloxbean/cardano-client-examples)