diff --git a/settings.gradle.kts b/settings.gradle.kts index 9272dd5..e1e0baa 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -18,5 +18,5 @@ rootProject.name = "Rpc Core" include(":rpccore") include(":okiodriver") include(":ktordriver") -include(":solana") +include(":solanaclient") diff --git a/solana/build.gradle.kts b/solanaclient/build.gradle.kts similarity index 100% rename from solana/build.gradle.kts rename to solanaclient/build.gradle.kts diff --git a/solana/src/commonMain/kotlin/com/solana/rpc/SolanaRpcClient.kt b/solanaclient/src/commonMain/kotlin/com/solana/rpc/SolanaRpcClient.kt similarity index 69% rename from solana/src/commonMain/kotlin/com/solana/rpc/SolanaRpcClient.kt rename to solanaclient/src/commonMain/kotlin/com/solana/rpc/SolanaRpcClient.kt index 0dcac88..a983235 100644 --- a/solana/src/commonMain/kotlin/com/solana/rpc/SolanaRpcClient.kt +++ b/solanaclient/src/commonMain/kotlin/com/solana/rpc/SolanaRpcClient.kt @@ -15,6 +15,7 @@ import kotlinx.serialization.builtins.nullable import kotlinx.serialization.builtins.serializer import kotlinx.serialization.json.* import kotlin.math.pow +import kotlin.random.Random import kotlin.time.Duration.Companion.seconds import kotlin.time.TimeSource @@ -22,31 +23,31 @@ class SolanaRpcClient(val rpcDriver: Rpc20Driver) { constructor(url: String, networkDriver: HttpNetworkDriver): this(Rpc20Driver(url, networkDriver)) - suspend fun requestAirdrop(address: SolanaPublicKey, amountSol: Float) = + suspend fun requestAirdrop(address: SolanaPublicKey, amountSol: Float, requestId: String? = null) = rpcDriver.makeRequest( - AirdropRequest(address, (amountSol*10f.pow(9)).toLong()), + AirdropRequest(address, (amountSol*10f.pow(9)).toLong(), requestId), String.serializer() ) - suspend fun getBalance(address: SolanaPublicKey, commitment: String = "confirmed") = - rpcDriver.makeRequest(BalanceRequest(address, commitment), SolanaResponseSerializer(Long.serializer())) + suspend fun getBalance(address: SolanaPublicKey, commitment: String = "confirmed", requestId: String? = null) = + rpcDriver.makeRequest(BalanceRequest(address, commitment, requestId), SolanaResponseSerializer(Long.serializer())) - suspend fun getMinBalanceForRentExemption(size: Long, commitment: String? = null) = - rpcDriver.makeRequest(RentExemptBalanceRequest(size, commitment), Long.serializer()) + suspend fun getMinBalanceForRentExemption(size: Long, commitment: String? = null, requestId: String? = null) = + rpcDriver.makeRequest(RentExemptBalanceRequest(size, commitment, requestId), Long.serializer()) - suspend fun getLatestBlockhash() = - rpcDriver.makeRequest(LatestBlockhashRequest(), SolanaResponseSerializer(BlockhashResponse.serializer())) + suspend fun getLatestBlockhash(commitment: String? = null, minContextSlot: Long? = null, requestId: String? = null) = + rpcDriver.makeRequest(LatestBlockhashRequest(commitment, minContextSlot, requestId), SolanaResponseSerializer(BlockhashResponse.serializer())) - suspend fun sendTransaction(transaction: Transaction) = - rpcDriver.makeRequest(SendTransactionRequest(transaction), String.serializer()) + suspend fun sendTransaction(transaction: Transaction, skipPreflight: Boolean = false, requestId: String? = null) = + rpcDriver.makeRequest(SendTransactionRequest(transaction, skipPreflight, requestId), String.serializer()) suspend fun sendAndConfirmTransaction(transaction: Transaction) = sendTransaction(transaction).apply { result?.let { confirmTransaction(it) } } - suspend fun getSignatureStatuses(signatures: List) = - rpcDriver.makeRequest(SignatureStatusesRequest(signatures), + suspend fun getSignatureStatuses(signatures: List, searchTransactionHistory: Boolean = false, requestId: String? = null) = + rpcDriver.makeRequest(SignatureStatusesRequest(signatures, searchTransactionHistory, requestId), SolanaResponseSerializer(ListSerializer(SignatureStatus.serializer().nullable)) ) @@ -67,7 +68,7 @@ class SolanaRpcClient(val rpcDriver: Rpc20Driver) { // wait a bit before retrying val mark = timeSource.markNow() var inc = 0 - while(timeSource.markNow() - mark < 0.3.seconds && isActive) { inc++ } + while(mark.elapsedNow() < 0.3.seconds && isActive) { inc++ } if (!isActive) break // breakout after timeout } @@ -76,8 +77,11 @@ class SolanaRpcClient(val rpcDriver: Rpc20Driver) { } //region Requests - class AirdropRequest(address: SolanaPublicKey, lamports: Long, requestId: String = "1") - : JsonRpc20Request( + sealed class SolanaRpcRequest(method: String, params: JsonElement?, id: String? = null) + : JsonRpc20Request(method, params, id ?: "$method-${Random.nextInt(100000000, 999999999)}") + + class AirdropRequest(address: SolanaPublicKey, lamports: Long, requestId: String? = null) + : SolanaRpcRequest( method = "requestAirdrop", params = buildJsonArray { add(address.base58()) @@ -86,8 +90,8 @@ class SolanaRpcClient(val rpcDriver: Rpc20Driver) { id = requestId ) - class BalanceRequest(address: SolanaPublicKey, commitment: String = "confirmed", requestId: String = "1") - : JsonRpc20Request( + class BalanceRequest(address: SolanaPublicKey, commitment: String = "confirmed", requestId: String? = null) + : SolanaRpcRequest( method = "getBalance", params = buildJsonArray { add(address.base58()) @@ -98,19 +102,22 @@ class SolanaRpcClient(val rpcDriver: Rpc20Driver) { requestId ) - class LatestBlockhashRequest(commitment: String = "confirmed", requestId: String = "1") - : JsonRpc20Request( + class LatestBlockhashRequest(commitment: String? = null, minContextSlot: Long? = null, requestId: String? = null) + : SolanaRpcRequest( method = "getLatestBlockhash", params = buildJsonArray { - addJsonObject { - put("commitment", commitment) + if (commitment != null || minContextSlot!= null) { + addJsonObject { + commitment?.let { put("commitment", commitment) } + minContextSlot?.let { put("minContextSlot", minContextSlot) } + } } }, requestId ) - class SendTransactionRequest(transaction: Transaction, skipPreflight: Boolean = true, requestId: String = "1") - : JsonRpc20Request( + class SendTransactionRequest(transaction: Transaction, skipPreflight: Boolean = false, requestId: String? = null) + : SolanaRpcRequest( method = "sendTransaction", params = buildJsonArray { add(Base58.encodeToString(transaction.serialize())) @@ -121,8 +128,8 @@ class SolanaRpcClient(val rpcDriver: Rpc20Driver) { requestId ) - class SignatureStatusesRequest(transactionIds: List, searchTransactionHistory: Boolean = false, requestId: String = "1") - : JsonRpc20Request( + class SignatureStatusesRequest(transactionIds: List, searchTransactionHistory: Boolean = false, requestId: String? = null) + : SolanaRpcRequest( method = "getSignatureStatuses", params = buildJsonArray { addJsonArray { transactionIds.forEach { add(it) } } @@ -133,8 +140,8 @@ class SolanaRpcClient(val rpcDriver: Rpc20Driver) { requestId ) - class RentExemptBalanceRequest(size: Long, commitment: String? = null, requestId: String = "1") - : JsonRpc20Request( + class RentExemptBalanceRequest(size: Long, commitment: String? = null, requestId: String? = null) + : SolanaRpcRequest( method = "getMinimumBalanceForRentExemption", params = buildJsonArray { add(size) diff --git a/solana/src/commonMain/kotlin/com/solana/serializers/SolanaResponseSerializer.kt b/solanaclient/src/commonMain/kotlin/com/solana/serializers/SolanaResponseSerializer.kt similarity index 100% rename from solana/src/commonMain/kotlin/com/solana/serializers/SolanaResponseSerializer.kt rename to solanaclient/src/commonMain/kotlin/com/solana/serializers/SolanaResponseSerializer.kt diff --git a/solana/src/commonTest/kotlin/com/solana/rpc/RpcClientTests.kt b/solanaclient/src/commonTest/kotlin/com/solana/rpc/RpcClientTests.kt similarity index 98% rename from solana/src/commonTest/kotlin/com/solana/rpc/RpcClientTests.kt rename to solanaclient/src/commonTest/kotlin/com/solana/rpc/RpcClientTests.kt index 78b1b22..f30c25b 100644 --- a/solana/src/commonTest/kotlin/com/solana/rpc/RpcClientTests.kt +++ b/solanaclient/src/commonTest/kotlin/com/solana/rpc/RpcClientTests.kt @@ -104,7 +104,7 @@ class RpcClientTests { Transaction(listOf(sig), this) } - val response = rpc.sendTransaction(transaction) + val response = rpc.sendTransaction(transaction, skipPreflight = true) // then assertNull(airdropResponse.error)