Cardano

Cardano-client-lib : A Java Library to interact with Cardano — Part I

In this post, I am going to introduce a Java library called “cardano-client-lib”. You can use this library in a Java application to interact with Cardano blockchain.

Why a Cardano Client Java Library ?

Currently, I am working on a project called “Cardano IntelliJ IDEA plugin (IntelliAda)”, which is a Catalyst Fund 3 funded project. You can check the Catalyst proposal here. When I started this project, I realized that there are client side libraries available for Cardano in languages like JavaScript, Rust (Cardano-serilization-lib), but I was not able find any Java library doing the similar thing without relying on cardano-cli (Cardano command line tool).

As Cardano IntelliJ Plugin is written in java, I need a client library in Java, so that I don’t need to rely on Cardano-cli tool inside the plugin to generate address, sign transaction and other operations. Because of that I started working on cardano-client-lib project to provide address generation, transaction serialization and signing support through a Java library.

The preview version (0.1.0) of this library in now available in Maven central repository, so you can use it in your java application.

This library also provides support to interact with Cardano blockchain to query blockchain and submit transactions through few simple Backend Apis. Currently, only one implementation available for Backend Api, which is for Blockfrost endpoint. More backends will be supported in future releases. (Cardano Wallet Backend, Cardano-ogmios ..)

The following key features are currently supported in this library

  • Address Generation (Base Address, Enterprise Address)
  • Build and serialize transaction to CBOR format
  • Apis to build Metadata
  • A converter to convert Metadata to Json (No Schema)
  • Payment transaction (ADA, Native tokens) signing and submission to Cardano network (through Blockfrost Backend Api)
  • Transaction with metadata
  • Api to mint native tokens
  • Apis to query Cardano blockchain through many Blockfrost backend apis (AddressService, AssetService, BlockService, EpochService,MetadataService, TransactionService …)

Current Limitations

  • Currently, this library is using “Cardano-serialization-lib” rust library through JNI, mainly for address generation and transaction signing. So it bundles the platform dependent binaries of Cardano-serialization-lib in the Jar. Because of that, this library is currently supported only on the following platforms

Apple MacOS (Intel and Apple Silicon)
Linux (x86_64) (Ubuntu 18.04 and above or compatible …)
Windows 64bits (x86_64)

Note: This limitation is temporary. The plan is to remove this dependency in the future release by implementing address generation and transaction signing natively in Java.

  • The library doesn’t support any stake pool related operations. Though in future, stake pool related operations can be added.

Let’s see how we can use this library to create and post a transfer transaction with Ada.

  1. Add cardano-client-lib dependency to your application

If you are using Maven,


    com.bloxbean.cardano
    cardano-client-lib
    0.1.0

If you are using Gradle,

implementation 'com.bloxbean.cardano:cardano-client-lib:0.1.0'

Note: You can check the latest released version in project’s GitHub.

2. Create a new Account

Account account = new Account(Networks.testnet()); 
String baseAddress = account.baseAddress();

3. Import from Mnemonic Phrase

Provide 24 words mnemonic phrase to derive the base account address.

String mnemonic = "behind hope swing table fat joy phone spoil response exercise dose fame mystery day food lens debate slam lawsuit board behind allow excuse extend";
Account account = new Account(Networks.testnet(), mnemonic); 
String baseAddress = account.baseAddress();

4. Get Backend Service

Provide Blockfrost Cardano network and Project Id to get an instance of Blockfrost backend service.

Register at https://blockfrost.io/ to get a free account and a project id for Cardano Testnet.

BackendService backendService =
     BackendFactory.getBlockfrostBackendService(
        Constants.BLOCKFROST_TESTNET_URL, );

5. Get Other services from Backend Service

The followings are the example of few major services you can get from BackendService. You can use these services to interact with Cardano blockchain.

a. Get an instance of TransactionHelperService to build a payment or token mint transaction and submit to the Cardano network.

TransactionHelperService txnHelperService 
               = backendService.getTransactionHelperService();

b. Get an instance of FeeCalculationService to calculate the estimated fees of a transaction.

FeeCalculationService feeCalcService 
                        = backendService.getFeeCalculationService();

c. Get TransactionService to query the blockchain for a transaction id.

TransactionService txnService
                        = backendService.getTransactionService();

d. Get BlockService to get the block information from the blockchain.

BlockService blockService = backendService.getBlockService();

e. Get an instance of AssetService to get Asset details.

AssetService assetService = backendService.getAssetService();

f. Get an instance of UtxoService to fetch Utxos.

UtxoService utxoService = backendService.getUtxoService()

g. Get an instance of MetadataService to fetch metdata

MetadataService metadataService 
                        = backendService.getMetadataService();

6. Top-up your account with test Ada

If you are on Cardano testnet, you can get some Testnet Ada token from the Testnet faucet here.

Note: You can use Account api to create new testnet accounts.

7. Create your first Ada Payment Transaction

Now that we have some test Ada tokens, we can create a payment transaction to transfer Ada from funded account to another account.

PaymentTransaction paymentTransaction =
        PaymentTransaction.builder()
             .sender(senderAccount) //Sender Account object
             .receiver(receiver)   // Receiver baseAddress as String
             .amount(BigInteger.valueOf(1500000))
             .unit(CardanoConstants.LOVELACE)
             .build();

Note: In the above transaction, we are trying to send 1.5 Ada (1500000 Lovelace) from sender’s account to receiver’s account.

6. Get the latest slot information and then calculate TTL (Time To Live)

In the below code snippet, we are getting the latest block through BlockService and then adding 1000 to the current slot number to calculate TTL.

long ttl = blockService.getLastestBlock().getValue().getSlot() + 1000;

7. Create a TransactionDetailsParams Object, set TTL and calculate the estimated fee using FeeCalculation service

TransactionDetailsParams detailsParams =
        TransactionDetailsParams.builder()
                .ttl(ttl)
                .build();

BigInteger fee 
     = feeCalculationService.calculateFee(paymentTransaction, detailsParams, null); 

8. Set the fee in the transaction request object

Now that we have estimated fee for our transaction, let’s set it in our PaymentTransaction request object.

paymentTransaction.setFee(fee);

9. Submit Transaction to the Cardano network

To submit the transaction to the network, you need to use TransactionHelperService. TransactionHelperService will get the required Utxos and then create the inputs and outputs accordingly before sending the transaction request to the network. It also calculates the min-ada required for each outputs.

Result result 
          = transactionHelperService.transfer(paymentTransaction, detailsParams);

If everything is ok, you should get the result success status as “true” and result value as “Transaction id”.

if(result.isSuccessful())
    System.out.println("Transaction Id: " + result.getValue());
else
    System.out.println("Transaction failed: " + result);

Now wait for sometime, so that the our transaction is mined.

You can now go to Cardano Testnet Explorer to check the transaction details.

10. Transfer Native Token

To transfer native tokens from one account to another, you need to use the same PaymentTransaction api to build the native token transfer request and set the native token’s asset id in the “unit” field of the payment request. Other steps are exactly same.

PaymentTransaction paymentTransaction =
        PaymentTransaction.builder()
                .sender(senderAccount)
                .receiver(receiver)
                .amount(BigInteger.valueOf(3000))
                .unit("d11b0562dcac7042636c9dbb44897b38.......")
                .build();
//Calculate Ttl = Latest slot + 1000
long ttl = blockService
              .getLastestBlock().getValue().getSlot() + 1000;
TransactionDetailsParams detailsParams =
        TransactionDetailsParams.builder()
                .ttl(ttl)
                .build();
//Calculate fee
BigInteger fee 
      = feeCalculationService.calculateFee(paymentTransaction,            detailsParams, null);
//Set fee
paymentTransaction.setFee(fee);

Result result 
            = transactionHelperService.transfer(paymentTransaction, detailsParams);

Check also :

Resources

Full Source Code:

public void transfer() 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);

        String receiver = "addr_test1qqwpl7h3g84mhr36wpetk904p7fchx2vst0z696lxk8ujsjyruqwmlsm344gfux3nsj6njyzj3ppvrqtt36cp9xyydzqzumz82";

        PaymentTransaction paymentTransaction =
                PaymentTransaction.builder()
                        .sender(sender) //Sender Account object
                        .receiver(receiver)   // Receiver baseAddress as String
                        .amount(BigInteger.valueOf(1500000))
                        .unit(CardanoConstants.LOVELACE)
                        .build();

        long ttl = blockService.getLastestBlock().getValue().getSlot() + 1000;

        TransactionDetailsParams detailsParams =
                TransactionDetailsParams.builder()
                        .ttl(ttl)
                        .build();

        BigInteger fee
                = feeCalculationService.calculateFee(paymentTransaction, detailsParams, null);
        paymentTransaction.setFee(fee);

        Result<String> result
                = transactionHelperService.transfer(paymentTransaction, detailsParams);

        if(result.isSuccessful())
            System.out.println("Transaction Id: " + result.getValue());
        else
            System.out.println("Transaction failed: " + result);
    }

Published on Java Code Geeks with permission by Satya Ranjan, partner at our JCG program. See the original article here: Cardano-client-lib : A Java Library to interact with Cardano — Part I

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