All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.io.eqoty.secretk.client.CosmWasmClient.kt Maven / Gradle / Ivy

Go to download

A Kotlin multiplatform REST client utilizing secret network's gRPC gateway endpoints.

There is a newer version: 6.4.1-rc
Show newest version
package io.eqoty.secretk.client

import io.eqoty.secretk.BroadcastMode
import io.eqoty.secretk.types.Account
import io.eqoty.secretk.types.response.SimulateTxsResponse
import io.eqoty.secretk.types.response.TxsResponse
import io.eqoty.secretk.types.response.TxsResponseData
import io.eqoty.secretk.types.result.GetNonceResult
import io.eqoty.secretk.utils.EncryptionUtils
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonObject

open class CosmWasmClient protected constructor(
    apiUrl: String,
    encryptionUtils: EncryptionUtils,
    broadcastMode: BroadcastMode = BroadcastMode.Block
) {
    internal val restClient = RestClient(apiUrl, broadcastMode, encryptionUtils)

    /** Any address the chain considers valid (valid bech32 with proper prefix) */
    protected var anyValidAddress: String? = null
    private var chainId: String? = null

    suspend fun getChainId(): String {
        if (chainId == null) {
            val response = restClient.nodeInfo()
            val chainId = response.node_info.network
            if (chainId == "") throw Error("Chain ID must not be empty")
            this.chainId = chainId
        }

        return chainId!!
    }

    suspend fun getNonce(address: String): GetNonceResult {
        val account = this.getAccount(address)
        if (account?.address == null) {
            throw Error(
                "Account $address does not exist on chain. Send some tokens there before trying to query nonces.",
            )
        }
        return GetNonceResult(
            accountNumber = account.accountNumber,
            sequence = account.sequence,
        )
    }

    suspend fun getAccount(address: String): Account? {
        val account = this.restClient.authAccounts(address)
        if (account.address == null || account.address === "") {
            return null
        } else {
            this.anyValidAddress = account.address
            return Account(
                address = account.address,
                balance = account.coins!!,
                pubkey = account.public_key,
                accountNumber = account.account_number!!,
                sequence = account.sequence!!,
            )
        }
    }

    suspend fun postTx(tx: UByteArray): TxsResponseData {
        val response: TxsResponse = restClient.postTx(tx, false)
        val txResponse = response.tx_response
        if (txResponse.txhash.isBlank()) {
            throw Error("Unexpected response data format")
        }
        if (txResponse.txhash.contains("""^([0-9A-F][0-9A-F])+$""")) {
            throw Error("Received ill-formatted txhash. Must be non-empty upper-case hex")
        }

        if (txResponse.code != 0) {
            throw Error("Broadcasting transaction failed with code ${txResponse.code} (codespace: ${txResponse.codespace}). Log: ${txResponse.rawLog}")
        }

        return txResponse
    }

    suspend fun postSimulateTx(tx: UByteArray): SimulateTxsResponse {
        val response: SimulateTxsResponse = restClient.postTx(tx, true)
        return response
    }


    /**
     * Makes a smart query on the contract, returns the parsed JSON document.
     *
     * Promise is rejected when contract does not exist.
     * Promise is rejected for invalid query format.
     * Promise is rejected for invalid response format.
     *
     * Note: addedParams allows for query string additions such as "&height=1234567"
     */
    suspend fun queryContractSmart(
        contractAddress: String,
        queryMsg: String,
        contractCodeHash: String? = null,
    ): String {
        try {
            return this.restClient.queryContractSmart(
                contractAddress,
                Json.parseToJsonElement(queryMsg).jsonObject,
                contractCodeHash,
            )
        } catch (t: Throwable) {
            if (t is Error) {
                if (t.message?.startsWith("not found: contract") == true) {
                    throw Error("No contract found at address $contractAddress")
                } else {
                    throw t
                }
            } else {
                throw t
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy