Skip to main content

Kotlin client

note

We are currently updating this documentation. While it offers a general overview, some details may be outdated. Please check back soon for the latest version.

The Kotlin client library, postchain-client, provides the capability for interacting with a blockchain from a client app written in Kotlin or Java. With this library, you can easily send transactions and retrieve queries from a Rell blockchain node.

You can access the project repository here.

Postchain-client

Postchain-client is a Kotlin client that makes queries and transactions from an application.

Setup

You must add these package registries to use the library since they're unavailable on Maven Central. The specific The steps for adding the URL may differ depending on your chosen build tool.

For Maven, add this to your pom.xml:

<project>
<dependencies>
<dependency>
<groupId>net.postchain.client</groupId>
<artifactId>postchain-client</artifactId>
</dependency>
</dependencies>

<repositories>
<repository>
<id>chromia-parent</id>
<name>Chromia parent GitLab Registry</name>
<url>https://gitlab.com/api/v4/projects/50818999/packages/maven</url>
</repository>
<repository>
<id>postchain</id>
<name>Postchain GitLab Registry</name>
<url>https://gitlab.com/api/v4/projects/32294340/packages/maven</url>
</repository>
<repository>
<id>postchain-client</id>
<name>Postchain Client GitLab Registry</name>
<url>https://gitlab.com/api/v4/projects/46288950/packages/maven</url>
</repository>
</repositories>
</project>

For Gradle, add this to your build.gradle.kts:

repositories {
maven("https://gitlab.com/api/v4/projects/50818999/packages/maven")
maven("https://gitlab.com/api/v4/projects/32294340/packages/maven")
maven("https://gitlab.com/api/v4/projects/46288950/packages/maven")
}

dependencies {
implementation("net.postchain.client:postchain-client")
}

Usage

Initializing the client

import net.postchain.client.config.PostchainClientConfig
import net.postchain.crypto.Secp256K1CryptoSystem
import net.postchain.client.core.PostchainClient
import net.postchain.client.impl.PostchainClientProviderImpl
import net.postchain.client.request.EndpointPool
import net.postchain.common.BlockchainRid
import net.postchain.common.hexStringToByteArray
import net.postchain.common.tx.TransactionStatus
import net.postchain.crypto.KeyPair

fun main() {
val cryptoSystem = Secp256K1CryptoSystem()
val bcRid: BlockchainRid = BlockchainRid.buildFromHex("...") // The blockchain RID of the chain (can be found in the logs when P.C. server starts)
val pubKey0 = "...".hexStringToByteArray() // This must be a real public key
val privKey0 = "...".hexStringToByteArray() // This must be a real private key
val keyPair0 = KeyPair(pubKey0, privKey0)
val sigMaker0 = cryptoSystem.buildSigMaker(keyPair0)
val endpointPool = EndpointPool.singleUrl("http://127.0.0.1:7740") // Running P.C. server on localhost
val psClient: PostchainClient = PostchainClientProviderImpl().createClient(
PostchainClientConfig(bcRid, endpointPool, listOf(keyPair0))
)
}

Queries

psClient.query("hello_world", GtvFactory.gtv(mapOf()))

Transactions

Create a basic transaction, sign it, and send it.

val txBuilder = psClient.transactionBuilder()
txBuilder.addOperation("nop") // Operation "nop" without arguments
txBuilder.sign(sigMaker0) // Sign it

val result = txBuilder.post()
when (result.status) {
TransactionStatus.WAITING -> println("TX has been put into the TX queue of the Postchain server")
TransactionStatus.REJECTED -> println("TX most likely wrong number of args")
TransactionStatus.CONFIRMED -> println("TX has been included in a block")
TransactionStatus.UNKNOWN -> println("Investigate")
}

Build a transaction containing an operation with arguments, sign it, and send it.

val txBuilder = psClient.transactionBuilder()
txBuilder.addOperation("set_name", GtvFactory.gtv(name))
//addNop makes tx unique, so one can send the same operation more than one time
txBuilder.addNop()
txBuilder.sign(sigMaker0) // Sign it
val result = txBuilder.post()

Chromia client

The Chromia client is an alternative to the Postchain client and can communicate more easily with Chromia networks. When initialized, it will look and connect to the system nodes of the network.

Setup

For Maven, add this to your pom.xml:

<project>
<dependencies>
<dependency>
<groupId>net.postchain.client</groupId>
<artifactId>chromia-client</artifactId>
</dependency>
</dependencies>

<repositories>
<repository>
<id>chromia-parent</id>
<name>Chromia parent GitLab Registry</name>
<url>https://gitlab.com/api/v4/projects/50818999/packages/maven</url>
</repository>
<repository>
<id>postchain</id>
<name>Postchain GitLab Registry</name>
<url>https://gitlab.com/api/v4/projects/32294340/packages/maven</url>
</repository>
<repository>
<id>postchain-client</id>
<name>Postchain Client GitLab Registry</name>
<url>https://gitlab.com/api/v4/projects/46288950/packages/maven</url>
</repository>
</repositories>
</project>

For Gradle, add this to your build.gradle.kts:

repositories {
maven("https://gitlab.com/api/v4/projects/50818999/packages/maven")
maven("https://gitlab.com/api/v4/projects/32294340/packages/maven")
maven("https://gitlab.com/api/v4/projects/46288950/packages/maven")
}

dependencies {
implementation("net.postchain.client:postchain-client")
}

Example usage

To create a client and wait for a transaction to be anchored:

val chromiaClient = StandardChromiaClient("http://127.0.0.1:7740")
chromiaClient.awaitAnchoredTx(
BlockchainRid.buildFromHex("335C75E08AFAC7D6678263F1A13D5AFED9CD009344B6349107D7CEEA3A40EA08"),
TxRid("3DE7FC7BCF6DAF2FFD8564D46D73F42C069818DDC249835535AD50D8D9270FF3"))

FT4 Client

The FT4 client enables interaction with dapps via the FT4 library, focusing on authentication, accounts, and asset management.

Setup

For Maven add this to your pom.xml:

<project>
<dependencies>
<dependency>
<groupId>net.postchain.client</groupId>
<artifactId>ft4-client</artifactId>
</dependency>
</dependencies>

<repositories>
<repository>
<id>chromia-parent</id>
<name>Chromia parent GitLab Registry</name>
<url>https://gitlab.com/api/v4/projects/50818999/packages/maven</url>
</repository>
<repository>
<id>postchain</id>
<name>Postchain GitLab Registry</name>
<url>https://gitlab.com/api/v4/projects/32294340/packages/maven</url>
</repository>
<repository>
<id>postchain-client</id>
<name>Postchain Client GitLab Registry</name>
<url>https://gitlab.com/api/v4/projects/46288950/packages/maven</url>
</repository>
</repositories>
</project>

For Gradle, add this to your build.gradle.kts:

repositories {
maven("https://gitlab.com/api/v4/projects/50818999/packages/maven")
maven("https://gitlab.com/api/v4/projects/32294340/packages/maven")
maven("https://gitlab.com/api/v4/projects/46288950/packages/maven")
}

dependencies {
implementation("net.postchain.client:ft4-client")
}

Features

Authentication

The FT4 client supports both Chromia and Ethereum-style authentication for operations:

Chromia Authentication

// Assuming you have initialized a PostchainClient and TransactionBuilder
val operationName = "your_operation_name"

val cryptoSystem = Secp256K1CryptoSystem()
val bcRid: BlockchainRid = BlockchainRid.buildFromHex("33398FDBB5BB91A2ECD7FC95D95948267D4CC7E277D3A18A46745C6E03583F3F") // The blockchain RID of the chain (can be found in the logs when P.C. server starts)
val pubKey0 = "020CA58A45A1F97C8EE7A95B49738517FD11A072F1F9AC2450E13875EBD817BA2E".hexStringToByteArray() // This must be a real public key
val privKey0 = "4CB84F555AD0F93C938EB8EF0E10F1CE129D143D74A6516F7D8E89ED21954593".hexStringToByteArray() // This must be a real private key
val keyPair0 = KeyPair(pubKey0, privKey0)
val sigMaker0 = cryptoSystem.buildSigMaker(keyPair0)
val endpointPool = EndpointPool.singleUrl("http://127.0.0.1:7740") // Running P.C. server on localhost
val psClient: PostchainClient = PostchainClientProviderImpl().createClient(PostchainClientConfig(bcRid, endpointPool, listOf(keyPair0)))
val txBuilder = psClient.transactionBuilder()

val accountId: ByteArray = "8ECB5E014C0FED6FCC50765802D0D15E210C64079D88A416D7852CC75F9407B4".hexStringToByteArray() // The FT4 account ID

// Add an authentication operation to the transaction
addFtAuthenticationOp(
psClient,
txBuilder,
operationName,
pubKey0,
accountId
)

// Add the operation that requires authentication
txBuilder.addOperation(operationName, gtv("arg1"))

// Sign and post the transaction
txBuilder.sign(sigMaker)
val result = txBuilder.post()

Ethereum Authentication

// Implement the EvmSigner interface
val evmSigner = object : EvmSigner {
override fun sign(address: ByteArray, message: String): Signature {
// Implement EVM signing logic here
return Signature(byteArrayOf(), byteArrayOf(), 0)
}
}

// Assuming you have initialized a PostchainClient and TransactionBuilder
val evmAddress: ByteArray = byteArrayOf() // The Ethereum address
val accountId: ByteArray = byteArrayOf() // The FT4 account ID
val operationName = "your_operation_name"
val operationArgs: List<Gtv> = listOf(gtv("arg1")) // Arguments for the operation

// Add the authentication operation to the transaction
addEvmAuthenticationOp(
psClient,
txBuilder,
operationName,
operationArgs,
evmAddress,
accountId,
null, // Optional auth descriptor ID
evmSigner
)

// Add the operation that requires authentication
txBuilder.addOperation(operationName, gtv("arg1"))

// Post the transaction
val result = txBuilder.post()

For operations where an EVM signer is not yet part of an account auth descriptor, use addEvmSignaturesOp instead:

// Add the signatures operation to the transaction
addEvmSignaturesOp(
psClient,
txBuilder,
operationName,
operationArgs,
evmAddress,
accountId,
null, // Optional auth descriptor ID
evmSigner
)

Authentication Descriptors

The FT4 client provides helper functions for working with authentication descriptors:

// Assuming you have initialized a PostchainClient
val accountId: ByteArray = byteArrayOf() // The account ID
val signer: ByteArray = byteArrayOf() // The signer's public key or address

// Get auth descriptors for the account and signer
val authDescriptors = psClient.getAccountAuthDescriptorsBySigner(accountId, signer)

// Work with the auth descriptors
for (descriptor in authDescriptors) {
// Get the flags for the auth descriptor
val flags = descriptor.flags()

// Get the number of signers
val signerCount = descriptor.numberOfSigners()

// For single-signer auth descriptors
if (descriptor.authType == AuthType.S) {
val signerPublicKey = descriptor.getSingleSigner()
// Process the signer public key
}

// For multi-signer auth descriptors
if (descriptor.authType == AuthType.M) {
val signerPublicKeys = descriptor.getMultiSigners()
// Process the list of signer public keys
}
}

Asset Management

// Assuming you have initialized a PostchainClient
val accountId: ByteArray = "8ECB5E014C0FED6FCC50765802D0D15E210C64079D88A416D7852CC75F9407B4".hexStringToByteArray() // The FT4 account ID
val assetId: ByteArray = "718B90D1E7C7B77D5329EDA83B31B43424BC8B2A155B05DBF8FDB985098DC447".hexStringToByteArray() // The asset for which the balance is requested
val balance: BigInteger = getAssetBalance(psClient, accountId, assetId)