From e7005fd93ec766e8eecc2fde8ae5234a98651e43 Mon Sep 17 00:00:00 2001 From: Guillermo Orellana Date: Mon, 9 Sep 2024 19:17:59 +0200 Subject: [PATCH] expose RPC objects and add arrow extensions --- .idea/gradle.xml | 1 + gradle.properties | 2 +- libs.versions.toml | 2 + settings.gradle.kts | 1 + .../build.gradle.kts | 116 ++++++++++++++++++ .../net/avianlabs/solana/arrow/Either.kt | 27 ++++ .../solana/arrow/SolanaKotlinError.kt | 15 +++ .../net/avianlabs/solana/SolanaClient.kt | 7 +- .../solana/client/ExecuteException.kt | 3 - .../client/{RpcResponse.kt => Response.kt} | 8 +- .../avianlabs/solana/client/RpcKtorClient.kt | 15 +-- .../solana/methods/getAccountInfo.kt | 25 ++-- .../avianlabs/solana/methods/getBalance.kt | 24 ++-- .../solana/methods/getFeeForMessage.kt | 24 ++-- .../solana/methods/getLatestBlockhash.kt | 22 ++-- .../getMinimumBalanceForRentExemption.kt | 22 ++-- .../net/avianlabs/solana/methods/getNonce.kt | 2 + .../solana/methods/getRecentBlockhash.kt | 22 ++-- .../solana/methods/getSignaturesForAddress.kt | 22 ++-- .../solana/methods/getTokenAccountBalance.kt | 24 ++-- .../solana/methods/getTransaction.kt | 21 ++-- .../solana/methods/isBlockHashValid.kt | 26 ++-- .../solana/methods/requestAirdrop.kt | 24 ++-- .../solana/methods/sendTransaction.kt | 31 +++-- .../domain/program/SystemProgramTest.kt | 9 +- 25 files changed, 314 insertions(+), 181 deletions(-) create mode 100644 solana-kotlin-arrow-extensions/build.gradle.kts create mode 100644 solana-kotlin-arrow-extensions/src/commonMain/kotlin/net/avianlabs/solana/arrow/Either.kt create mode 100644 solana-kotlin-arrow-extensions/src/commonMain/kotlin/net/avianlabs/solana/arrow/SolanaKotlinError.kt delete mode 100644 solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/client/ExecuteException.kt rename solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/client/{RpcResponse.kt => Response.kt} (75%) diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 0d7501a..e5bb7ee 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -10,6 +10,7 @@ diff --git a/gradle.properties b/gradle.properties index 315b4d6..c711405 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=0.1.15 +version=0.2.0 # Kotlin #kotlin.code.style=official kotlin.js.compiler=ir diff --git a/libs.versions.toml b/libs.versions.toml index 514e5b3..c1c5a6f 100644 --- a/libs.versions.toml +++ b/libs.versions.toml @@ -14,6 +14,7 @@ mavenPublish = "0.29.0" skie = "0.8.2" # Libraries +arrow = "1.2.4" junit5 = "5.11.0" junitPioneer = "2.2.0" kermit = "2.0.4" @@ -25,6 +26,7 @@ okio = "3.9.0" serialization = "1.7.1" [libraries] +arrow-core = { module = "io.arrow-kt:arrow-core", version.ref = "arrow" } bouncyCastle = { module = "org.bouncycastle:bcpkix-jdk15to18", version = "1.78.1" } coreLibraryDesugaring = { module = "com.android.tools:desugar_jdk_libs", version = "2.1.0" } coroutinesAndroid = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 32097a0..e32bb96 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -26,6 +26,7 @@ dependencyResolutionManagement { } include(":solana-kotlin") +include(":solana-kotlin-arrow-extensions") include(":tweetnacl-multiplatform") dependencyResolutionManagement { diff --git a/solana-kotlin-arrow-extensions/build.gradle.kts b/solana-kotlin-arrow-extensions/build.gradle.kts new file mode 100644 index 0000000..a6cd7f0 --- /dev/null +++ b/solana-kotlin-arrow-extensions/build.gradle.kts @@ -0,0 +1,116 @@ +plugins { + alias(libs.plugins.kotlinMultiplatform) + alias(libs.plugins.kotlinSerialization) + alias(libs.plugins.mavenPublish) + alias(libs.plugins.dokka) + signing +} + +group = "net.avianlabs.solana" +version = properties["version"] as String + + +kotlin { + applyDefaultHierarchyTemplate() + explicitApi() + + jvm { + // set the target JVM version + compilations.all { + kotlinOptions { + jvmTarget = "17" + } + } + } + + mingwX64() + linuxX64() + + sourceSets { + val jvmMain by getting + + val jvmTest by getting + + val commonMain by getting { + dependencies { + api(project(":solana-kotlin")) + implementation(libs.coroutinesCore) + implementation(libs.kermit) + implementation(libs.arrow.core) + } + } + val commonTest by getting { + dependencies { + implementation(libs.kotlinTest) + implementation(libs.coroutinesTest) + } + } + + val nativeMain by getting + + val linuxMain by getting + + val mingwMain by getting + } +} + +tasks.withType { + kotlinOptions { + jvmTarget = "17" + } +} + +signing { + useGpgCmd() +} + +publishing { + repositories { + mavenLocal() + repositories { + maven { + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/avianlabs/solana-kotlin") + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } + } + } + } + publications { + withType { + pom { + name = "Solana Kotlin Arrow Extensions" + description = "Arrow extensions for Solana Kotlin" + licenses { + license { + name = "MIT" + url = "https://opensource.org/licenses/MIT" + } + } + url = "https://github.com/avianlabs/solana-kotlin" + issueManagement { + system = "GitHub" + url = "https://github.com/avianlabs/solana-kotlin" + } + scm { + connection = "https://github.com/avianlabs/solana-kotlin.git" + url = "https://github.com/avianlabs/solana-kotlin" + } + developers { + developer { + name = "Avian Labs Engineers" + email = "engineering@avianlabs.net" + } + } + } + } + } +} + +mavenPublishing { + if (rootProject.findProperty("signPublications") != "false") { + signAllPublications() + } +} diff --git a/solana-kotlin-arrow-extensions/src/commonMain/kotlin/net/avianlabs/solana/arrow/Either.kt b/solana-kotlin-arrow-extensions/src/commonMain/kotlin/net/avianlabs/solana/arrow/Either.kt new file mode 100644 index 0000000..2beaa4d --- /dev/null +++ b/solana-kotlin-arrow-extensions/src/commonMain/kotlin/net/avianlabs/solana/arrow/Either.kt @@ -0,0 +1,27 @@ +package net.avianlabs.solana.arrow + +import arrow.core.Either +import arrow.core.left +import arrow.core.right +import net.avianlabs.solana.arrow.SolanaKotlinError.RpcError.* +import net.avianlabs.solana.client.Response +import net.avianlabs.solana.client.RpcError + +public fun Response.toEither(): Either = + if (error != null) { + error!!.toRpcError().left() + } else if (result != null) { + result!!.right() + } else { + SolanaKotlinError.MalformedResponse("both error and result are null").left() + } + +private fun RpcError.toRpcError(): SolanaKotlinError = when (code) { + -32700 -> ParseError(message) + -32600 -> InvalidRequest(message) + -32601 -> MethodNotFound(message) + -32602 -> InvalidParams(message) + -32603 -> InternalError(message) + in -32000 downTo -32099 -> ServerError(message) + else -> SolanaKotlinError.UnknownError(message) +} diff --git a/solana-kotlin-arrow-extensions/src/commonMain/kotlin/net/avianlabs/solana/arrow/SolanaKotlinError.kt b/solana-kotlin-arrow-extensions/src/commonMain/kotlin/net/avianlabs/solana/arrow/SolanaKotlinError.kt new file mode 100644 index 0000000..2431fab --- /dev/null +++ b/solana-kotlin-arrow-extensions/src/commonMain/kotlin/net/avianlabs/solana/arrow/SolanaKotlinError.kt @@ -0,0 +1,15 @@ +package net.avianlabs.solana.arrow + +public sealed interface SolanaKotlinError { + public sealed interface RpcError : SolanaKotlinError { + public data class ParseError(val message: String) : RpcError + public data class InvalidRequest(val message: String) : RpcError + public data class MethodNotFound(val message: String) : RpcError + public data class InvalidParams(val message: String) : RpcError + public data class InternalError(val message: String) : RpcError + public data class ServerError(val message: String) : RpcError + } + + public data class MalformedResponse(val message: String) : SolanaKotlinError + public data class UnknownError(val message: String) : SolanaKotlinError +} diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/SolanaClient.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/SolanaClient.kt index 15bf043..d48323b 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/SolanaClient.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/SolanaClient.kt @@ -2,9 +2,9 @@ package net.avianlabs.solana import io.ktor.client.* import io.ktor.http.* -import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonArray +import net.avianlabs.solana.client.Response import net.avianlabs.solana.client.RpcInvocation import net.avianlabs.solana.client.RpcKtorClient import kotlin.coroutines.resume @@ -35,7 +35,6 @@ public class SolanaClient( ), ) - @OptIn(ExperimentalSerializationApi::class) internal val json: Json = Json { ignoreUnknownKeys = true isLenient = true @@ -46,8 +45,8 @@ public class SolanaClient( internal suspend inline fun invoke( method: String, params: JsonArray? = null, - ): T? { + ): Response { val invocation = RpcInvocation(method, params, headerProviders) - return client.invoke(invocation).result + return client.invoke(invocation) } } diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/client/ExecuteException.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/client/ExecuteException.kt deleted file mode 100644 index b9007bc..0000000 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/client/ExecuteException.kt +++ /dev/null @@ -1,3 +0,0 @@ -package net.avianlabs.solana.client - -public data class ExecuteException(val error: RpcError) : RuntimeException(error.toString()) diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/client/RpcResponse.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/client/Response.kt similarity index 75% rename from solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/client/RpcResponse.kt rename to solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/client/Response.kt index 62171f9..ea754fe 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/client/RpcResponse.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/client/Response.kt @@ -3,7 +3,7 @@ package net.avianlabs.solana.client import kotlinx.serialization.Serializable @Serializable -public data class RpcResponse( +public data class Response( val id: Int, val jsonrpc: String, val result: T? = null, @@ -11,13 +11,13 @@ public data class RpcResponse( ) { @Serializable public data class RPC( - val context: Context?, - val value: T? = null, + val context: Context, + val value: T, ) { @Serializable public data class Context( - val slot: Long, + val slot: ULong, val apiVersion: String?, ) } diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/client/RpcKtorClient.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/client/RpcKtorClient.kt index 8c3c8c0..551e81f 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/client/RpcKtorClient.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/client/RpcKtorClient.kt @@ -40,25 +40,20 @@ public class RpcKtorClient( } } - internal suspend inline fun invoke(invocation: RpcInvocation): RpcResponse = + internal suspend inline fun invoke(invocation: RpcInvocation): Response = execute(makeRequest(invocation)) internal inline fun makeRequest(invocation: RpcInvocation): RpcRequest = RpcRequest(requestIdGenerator.next(), invocation) - internal suspend inline fun execute(request: RpcRequest): RpcResponse { - val response = ktorClient.post(url) { + internal suspend inline fun execute(request: RpcRequest): Response = + ktorClient.post(url) { contentType(ContentType.Application.Json) - setBody(request.buildBody()) + setBody(request.buildBody()) request.invocation.headerProviders.forEach { (header, valueProvider) -> header(header, valueProvider()) } - } - response.body()["error"]?.let { - throw ExecuteException(Json.decodeFromJsonElement(it)) - } - return response.body() - } + }.body() internal inline fun RpcRequest.buildBody(): JsonObject { val body: MutableMap = mutableMapOf( diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getAccountInfo.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getAccountInfo.kt index 9349ce2..0ba1445 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getAccountInfo.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getAccountInfo.kt @@ -7,28 +7,25 @@ import kotlinx.serialization.json.addJsonObject import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.put import net.avianlabs.solana.SolanaClient -import net.avianlabs.solana.client.RpcResponse +import net.avianlabs.solana.client.Response import net.avianlabs.solana.domain.core.Commitment import net.avianlabs.solana.tweetnacl.ed25519.PublicKey public suspend fun SolanaClient.getAccountInfo( publicKey: PublicKey, commitment: Commitment? = null, -): AccountInfo? { - val result = invoke>( - method = "getAccountInfo", - params = buildJsonArray { - add(publicKey.toBase58()) - addJsonObject { - put("encoding", "base64") - commitment?.let { - put("commitment", it.value) - } +): Response> = invoke( + method = "getAccountInfo", + params = buildJsonArray { + add(publicKey.toBase58()) + addJsonObject { + put("encoding", "base64") + commitment?.let { + put("commitment", it.value) } } - ) - return result!!.value -} + } +) /** * Account information diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getBalance.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getBalance.kt index 31e561a..7354630 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getBalance.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getBalance.kt @@ -5,7 +5,8 @@ import kotlinx.serialization.json.addJsonObject import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.put import net.avianlabs.solana.SolanaClient -import net.avianlabs.solana.client.RpcResponse.RPC +import net.avianlabs.solana.client.Response +import net.avianlabs.solana.client.Response.RPC import net.avianlabs.solana.domain.core.Commitment import net.avianlabs.solana.tweetnacl.ed25519.PublicKey @@ -18,17 +19,14 @@ import net.avianlabs.solana.tweetnacl.ed25519.PublicKey public suspend fun SolanaClient.getBalance( account: PublicKey, commitment: Commitment? = null, -): Long { - val result = invoke>( - method = "getBalance", - params = buildJsonArray { - add(account.toBase58()) - commitment?.let { - addJsonObject { - put("commitment", it.value) - } +): Response> = invoke( + method = "getBalance", + params = buildJsonArray { + add(account.toBase58()) + commitment?.let { + addJsonObject { + put("commitment", it.value) } } - ) - return result!!.value!! -} + } +) diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getFeeForMessage.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getFeeForMessage.kt index ddbcfba..023413a 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getFeeForMessage.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getFeeForMessage.kt @@ -6,7 +6,8 @@ import kotlinx.serialization.json.addJsonObject import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.put import net.avianlabs.solana.SolanaClient -import net.avianlabs.solana.client.RpcResponse.RPC +import net.avianlabs.solana.client.Response +import net.avianlabs.solana.client.Response.RPC import net.avianlabs.solana.domain.core.Commitment /** @@ -19,17 +20,14 @@ import net.avianlabs.solana.domain.core.Commitment public suspend fun SolanaClient.getFeeForMessage( message: ByteArray, commitment: Commitment? = null -): Long { - val result = invoke>( - method = "getFeeForMessage", - params = buildJsonArray { - add(message.encodeBase64()) - commitment?.let { - addJsonObject { - put("commitment", it.value) - } +): Response> = invoke( + method = "getFeeForMessage", + params = buildJsonArray { + add(message.encodeBase64()) + commitment?.let { + addJsonObject { + put("commitment", it.value) } } - ) - return result!!.value!! -} + } +) diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getLatestBlockhash.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getLatestBlockhash.kt index 83771eb..b09b00c 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getLatestBlockhash.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getLatestBlockhash.kt @@ -5,7 +5,8 @@ import kotlinx.serialization.json.addJsonObject import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.put import net.avianlabs.solana.SolanaClient -import net.avianlabs.solana.client.RpcResponse +import net.avianlabs.solana.client.Response +import net.avianlabs.solana.client.Response.RPC import net.avianlabs.solana.domain.core.Commitment /** @@ -15,19 +16,16 @@ import net.avianlabs.solana.domain.core.Commitment */ public suspend fun SolanaClient.getLatestBlockhash( commitment: Commitment? = null, -): LatestBlockHash { - val result = invoke>( - method = "getLatestBlockhash", - params = buildJsonArray { - commitment?.let { - addJsonObject { - put("commitment", it.value) - } +): Response> = invoke( + method = "getLatestBlockhash", + params = buildJsonArray { + commitment?.let { + addJsonObject { + put("commitment", it.value) } } - ) - return result!!.value!! -} + } +) @Serializable public data class LatestBlockHash( diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getMinimumBalanceForRentExemption.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getMinimumBalanceForRentExemption.kt index 54dc923..86b6536 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getMinimumBalanceForRentExemption.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getMinimumBalanceForRentExemption.kt @@ -5,6 +5,7 @@ import kotlinx.serialization.json.addJsonObject import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.put import net.avianlabs.solana.SolanaClient +import net.avianlabs.solana.client.Response import net.avianlabs.solana.domain.core.Commitment /** @@ -16,17 +17,14 @@ import net.avianlabs.solana.domain.core.Commitment public suspend fun SolanaClient.getMinimumBalanceForRentExemption( dataLength: Long, commitment: Commitment? = null, -): Long { - val result = invoke( - method = "getMinimumBalanceForRentExemption", - params = buildJsonArray { - add(dataLength) - commitment?.let { - addJsonObject { - put("commitment", it.value) - } +): Response = invoke( + method = "getMinimumBalanceForRentExemption", + params = buildJsonArray { + add(dataLength) + commitment?.let { + addJsonObject { + put("commitment", it.value) } } - ) - return result!! -} + } +) diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getNonce.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getNonce.kt index 6893f9c..25b4f1a 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getNonce.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getNonce.kt @@ -11,6 +11,8 @@ public suspend fun SolanaClient.getNonce( publicKey: PublicKey, commitment: Commitment? = null ): NonceAccount? = getAccountInfo(publicKey, commitment) + .result + ?.value ?.dataBytes ?.let { data -> val decoded = NonceAccountData.read(Buffer().write(data)) diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getRecentBlockhash.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getRecentBlockhash.kt index 9918a1e..b264517 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getRecentBlockhash.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getRecentBlockhash.kt @@ -5,7 +5,8 @@ import kotlinx.serialization.json.addJsonObject import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.put import net.avianlabs.solana.SolanaClient -import net.avianlabs.solana.client.RpcResponse +import net.avianlabs.solana.client.Response +import net.avianlabs.solana.client.Response.RPC import net.avianlabs.solana.domain.core.Commitment import net.avianlabs.solana.domain.core.FeeCalculator @@ -23,19 +24,16 @@ import net.avianlabs.solana.domain.core.FeeCalculator ) public suspend fun SolanaClient.getRecentBlockhash( commitment: Commitment? = null, -): RecentBlockHash { - val result = invoke>( - method = "getRecentBlockhash", - params = buildJsonArray { - commitment?.let { - addJsonObject { - put("commitment", it.value) - } +): Response> = invoke( + method = "getRecentBlockhash", + params = buildJsonArray { + commitment?.let { + addJsonObject { + put("commitment", it.value) } } - ) - return result!!.value!! -} + } +) @Serializable public data class RecentBlockHash( diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getSignaturesForAddress.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getSignaturesForAddress.kt index 5277fea..2c8f7ff 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getSignaturesForAddress.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getSignaturesForAddress.kt @@ -3,6 +3,7 @@ package net.avianlabs.solana.methods import kotlinx.serialization.Serializable import kotlinx.serialization.json.* import net.avianlabs.solana.SolanaClient +import net.avianlabs.solana.client.Response import net.avianlabs.solana.domain.core.Commitment import net.avianlabs.solana.tweetnacl.ed25519.PublicKey @@ -18,20 +19,17 @@ import net.avianlabs.solana.tweetnacl.ed25519.PublicKey public suspend fun SolanaClient.getSignaturesForAddress( account: PublicKey, commitment: Commitment? = null, -): List { - val result = invoke>( - method = "getSignaturesForAddress", - params = buildJsonArray { - add(account.toBase58()) - commitment?.let { - addJsonObject { - put("commitment", it.value) - } +): Response> = invoke( + method = "getSignaturesForAddress", + params = buildJsonArray { + add(account.toBase58()) + commitment?.let { + addJsonObject { + put("commitment", it.value) } } - ) - return result!! -} + } +) @Serializable public data class SignatureInformation( diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getTokenAccountBalance.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getTokenAccountBalance.kt index e98635f..2df1664 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getTokenAccountBalance.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getTokenAccountBalance.kt @@ -6,7 +6,8 @@ import kotlinx.serialization.json.addJsonObject import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.put import net.avianlabs.solana.SolanaClient -import net.avianlabs.solana.client.RpcResponse.RPC +import net.avianlabs.solana.client.Response +import net.avianlabs.solana.client.Response.RPC import net.avianlabs.solana.domain.core.Commitment import net.avianlabs.solana.tweetnacl.ed25519.PublicKey @@ -20,20 +21,17 @@ import net.avianlabs.solana.tweetnacl.ed25519.PublicKey public suspend fun SolanaClient.getTokenAccountBalance( tokenAccount: PublicKey, commitment: Commitment? = null, -): TokenAmountInfo { - val result = invoke>( - method = "getTokenAccountBalance", - params = buildJsonArray { - add(tokenAccount.toBase58()) - commitment?.let { - addJsonObject { - put("commitment", it.value) - } +): Response> = invoke( + method = "getTokenAccountBalance", + params = buildJsonArray { + add(tokenAccount.toBase58()) + commitment?.let { + addJsonObject { + put("commitment", it.value) } } - ) - return result!!.value!! -} + } +) @Serializable public data class TokenAmountInfo( diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getTransaction.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getTransaction.kt index f0f4a3c..526d907 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getTransaction.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/getTransaction.kt @@ -3,6 +3,7 @@ package net.avianlabs.solana.methods import kotlinx.serialization.Serializable import kotlinx.serialization.json.* import net.avianlabs.solana.SolanaClient +import net.avianlabs.solana.client.Response import net.avianlabs.solana.domain.core.Commitment /** @@ -15,19 +16,17 @@ import net.avianlabs.solana.domain.core.Commitment public suspend fun SolanaClient.getTransaction( signature: String, commitment: Commitment? = null, -): TransactionResponse? { - return invoke( - method = "getTransaction", - params = buildJsonArray { - add(signature) - commitment?.let { - addJsonObject { - put("commitment", it.value) - } +): Response = invoke( + method = "getTransaction", + params = buildJsonArray { + add(signature) + commitment?.let { + addJsonObject { + put("commitment", it.value) } } - ) -} + } +) @Serializable public data class TransactionResponse( diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/isBlockHashValid.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/isBlockHashValid.kt index 15b6e3a..6bb5908 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/isBlockHashValid.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/isBlockHashValid.kt @@ -5,7 +5,8 @@ import kotlinx.serialization.json.addJsonObject import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.put import net.avianlabs.solana.SolanaClient -import net.avianlabs.solana.client.RpcResponse.RPC +import net.avianlabs.solana.client.Response +import net.avianlabs.solana.client.Response.RPC import net.avianlabs.solana.domain.core.Commitment /** @@ -20,18 +21,15 @@ public suspend fun SolanaClient.isBlockHashValid( blockHash: String, commitment: Commitment? = null, minContextSlot: Long? = null, -): Boolean { - val result = invoke>( - method = "isBlockhashValid", - params = buildJsonArray { - add(blockHash) - if (listOfNotNull(commitment, minContextSlot).isNotEmpty()) { - addJsonObject { - commitment?.let { put("commitment", it.value) } - minContextSlot?.let { put("minContextSlot", it) } - } +): Response> = invoke( + method = "isBlockhashValid", + params = buildJsonArray { + add(blockHash) + if (listOfNotNull(commitment, minContextSlot).isNotEmpty()) { + addJsonObject { + commitment?.let { put("commitment", it.value) } + minContextSlot?.let { put("minContextSlot", it) } } } - ) - return result!!.value!! -} + } +) diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/requestAirdrop.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/requestAirdrop.kt index 5df5c69..5121b9b 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/requestAirdrop.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/requestAirdrop.kt @@ -5,6 +5,7 @@ import kotlinx.serialization.json.addJsonObject import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.put import net.avianlabs.solana.SolanaClient +import net.avianlabs.solana.client.Response import net.avianlabs.solana.domain.core.Commitment import net.avianlabs.solana.tweetnacl.ed25519.PublicKey @@ -19,18 +20,15 @@ public suspend fun SolanaClient.requestAirdrop( publicKey: PublicKey, lamports: Long, commitment: Commitment? = null -): String { - val result = invoke( - method = "requestAirdrop", - params = buildJsonArray { - add(publicKey.toBase58()) - add(lamports) - commitment?.let { - addJsonObject { - put("commitment", it.value) - } +): Response = invoke( + method = "requestAirdrop", + params = buildJsonArray { + add(publicKey.toBase58()) + add(lamports) + commitment?.let { + addJsonObject { + put("commitment", it.value) } } - ) - return result!! -} + } +) diff --git a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/sendTransaction.kt b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/sendTransaction.kt index bfe1747..f892a45 100644 --- a/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/sendTransaction.kt +++ b/solana-kotlin/src/commonMain/kotlin/net/avianlabs/solana/methods/sendTransaction.kt @@ -6,11 +6,13 @@ import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.put import net.avianlabs.solana.SolanaClient +import net.avianlabs.solana.client.Response import net.avianlabs.solana.domain.core.Commitment import net.avianlabs.solana.domain.core.Transaction /** * Send a signed transaction to the cluster + * * @param transaction The signed transaction to send * @param skipPreflight If true, skip the preflight check * @param preflightCommitment The commitment level to use for the preflight check @@ -24,19 +26,16 @@ public suspend fun SolanaClient.sendTransaction( preflightCommitment: Commitment = Commitment.Finalized, maxRetries: Int? = null, minContextSlot: Long? = null, -): String { - val result = invoke( - method = "sendTransaction", - params = buildJsonArray { - add(transaction.serialize().encodeBase64()) - add(buildJsonObject { - put("encoding", "base64") - put("skipPreflight", skipPreflight) - put("preflightCommitment", preflightCommitment.value) - maxRetries?.let { put("maxRetries", it) } - minContextSlot?.let { put("minContextSlot", it) } - }) - } - ) - return result!! -} +): Response = invoke( + method = "sendTransaction", + params = buildJsonArray { + add(transaction.serialize().encodeBase64()) + add(buildJsonObject { + put("encoding", "base64") + put("skipPreflight", skipPreflight) + put("preflightCommitment", preflightCommitment.value) + maxRetries?.let { put("maxRetries", it) } + minContextSlot?.let { put("minContextSlot", it) } + }) + } +) diff --git a/solana-kotlin/src/commonTest/kotlin/net/avianlabs/solana/domain/program/SystemProgramTest.kt b/solana-kotlin/src/commonTest/kotlin/net/avianlabs/solana/domain/program/SystemProgramTest.kt index c81b8b9..41fd5f8 100644 --- a/solana-kotlin/src/commonTest/kotlin/net/avianlabs/solana/domain/program/SystemProgramTest.kt +++ b/solana-kotlin/src/commonTest/kotlin/net/avianlabs/solana/domain/program/SystemProgramTest.kt @@ -32,9 +32,10 @@ class SystemProgramTest { val balance = client.getBalance(keypair.publicKey) println("Balance: $balance") - val rentExempt = client.getMinimumBalanceForRentExemption(SystemProgram.NONCE_ACCOUNT_LENGTH) + val rentExempt = + client.getMinimumBalanceForRentExemption(SystemProgram.NONCE_ACCOUNT_LENGTH).result!! - val blockhash = client.getLatestBlockhash() + val blockhash = client.getLatestBlockhash().result!!.value val initTransaction = Transaction() .addInstruction( @@ -84,12 +85,12 @@ class SystemProgramTest { .build() .sign(keypair) - val testSignature = client.sendTransaction(testTransaction) + val testSignature = client.sendTransaction(testTransaction).result!! println("Advanced nonce account: $testSignature") delay(15.seconds) - val testTxInfo = client.getTransaction(testSignature, Commitment.Confirmed) + val testTxInfo = client.getTransaction(testSignature, Commitment.Confirmed).result println("Transaction info: ${testTxInfo?.decode()}") val newNonce = client.getNonce(nonceAccount.publicKey, Commitment.Processed)