Skip to content

Commit

Permalink
add getAccountInfo, getNonce RPCs and decoder for NonceAccountData
Browse files Browse the repository at this point in the history
  • Loading branch information
wiyarmir committed Mar 21, 2024
1 parent f3dc2fa commit 1c88e68
Show file tree
Hide file tree
Showing 19 changed files with 328 additions and 141 deletions.
2 changes: 1 addition & 1 deletion .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions solana-kotlin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ kotlin {
listOf(
iosArm64(),
iosSimulatorArm64(),
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "SolanaKotlin"
export(project(":tweetnacl-multiplatform"))
isStatic = true
}
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "SolanaKotlin"
export(project(":tweetnacl-multiplatform"))
isStatic = true
}
}

mingwX64()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ public class RpcKtorClient(
install(ContentNegotiation) { json(json = json) }
expectSuccess = true
install(Logging) {
logger = Logger.DEFAULT
level = LogLevel.ALL
logger = Logger.SIMPLE
level = LogLevel.NONE
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package net.avianlabs.solana.domain.core

import kotlinx.serialization.Serializable
import okio.BufferedSource

@Serializable
public data class FeeCalculator(
val lamportsPerSignature: ULong,
) {
public companion object {
public fun read(data: BufferedSource): FeeCalculator = FeeCalculator(
lamportsPerSignature = data.readLongLe().toULong(),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package net.avianlabs.solana.domain.core

import net.avianlabs.solana.tweetnacl.ed25519.PublicKey
import okio.BufferedSource

public data class NonceAccountData(
val version: UInt,
val state: UInt,
val authorizedPubkey: PublicKey,
val nonce: String,
val feeCalculator: FeeCalculator,
) {
public companion object {
public fun read(data: BufferedSource): NonceAccountData {
val version = data.readIntLe().toUInt()
val state = data.readIntLe().toUInt()
val authorizedPubkey = PublicKey.read(data)
val nonce = PublicKey.read(data).toBase58()
val feeCalculator = FeeCalculator.read(data)
return NonceAccountData(
version = version,
state = state,
authorizedPubkey = authorizedPubkey,
nonce = nonce,
feeCalculator = feeCalculator,
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package net.avianlabs.solana.domain.core

import net.avianlabs.solana.tweetnacl.ed25519.PublicKey
import okio.BufferedSource

public fun PublicKey.Companion.read(data: BufferedSource): PublicKey = PublicKey(
bytes = data.readByteArray(32),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package net.avianlabs.solana.methods

import io.ktor.util.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.add
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.domain.core.Commitment
import net.avianlabs.solana.tweetnacl.ed25519.PublicKey

public suspend fun SolanaClient.getAccountInfo(
publicKey: PublicKey,
commitment: Commitment? = null,
): AccountInfo? {
val result = invoke<RpcResponse.RPC<AccountInfo>>(
method = "getAccountInfo",
params = buildJsonArray {
add(publicKey.toBase58())
addJsonObject {
put("encoding", "base64")
commitment?.let {
put("commitment", it.value)
}
}
}
)
return result!!.value
}

/**
* Account information
* @param executable `true` if this account's data contains a loaded program (and is now read-only)
* @param owner The public key of the program that owns the account
* @param lamports The number of lamports assigned to the account
* @param data The data held in this account
* @param rentEpoch The epoch at which this account will next owe rent
*/
@Serializable
public data class AccountInfo(
val executable: Boolean,
val owner: String,
val lamports: ULong,
val data: List<String>,
val rentEpoch: ULong,
) {
public val ownerPublicKey: PublicKey
get() = PublicKey.fromBase58(owner)

public val dataBytes: ByteArray
get() = data.first().decodeBase64Bytes()
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package net.avianlabs.solana.methods

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.encodeToJsonElement
import kotlinx.serialization.json.add
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.domain.core.Commitment
Expand All @@ -20,15 +21,14 @@ public suspend fun SolanaClient.getBalance(
): Long {
val result = invoke<RPC<Long>>(
method = "getBalance",
params = JsonArray(buildList {
add(json.encodeToJsonElement<PublicKey>(account))
commitment?.let { add(json.encodeToJsonElement(BalanceParams(it.value))) }
})
params = buildJsonArray {
add(account.toBase58())
commitment?.let {
addJsonObject {
put("commitment", it.value)
}
}
}
)
return result!!.value!!
}

@Serializable
internal data class BalanceParams(
val commitment: String? = null,
)
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package net.avianlabs.solana.methods

import io.ktor.util.encodeBase64
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.encodeToJsonElement
import io.ktor.util.*
import kotlinx.serialization.json.add
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.domain.core.Commitment
Expand All @@ -21,15 +22,14 @@ public suspend fun SolanaClient.getFeeForMessage(
): Long {
val result = invoke<RPC<Long>>(
method = "getFeeForMessage",
params = JsonArray(buildList {
add(json.encodeToJsonElement<String>(message.encodeBase64()))
commitment?.let { add(json.encodeToJsonElement(FeeForMessageParams(it.value))) }
})
params = buildJsonArray {
add(message.encodeBase64())
commitment?.let {
addJsonObject {
put("commitment", it.value)
}
}
}
)
return result!!.value!!
}

@Serializable
internal data class FeeForMessageParams(
val commitment: String? = null,
)
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package net.avianlabs.solana.methods

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.encodeToJsonElement
import kotlinx.serialization.json.add
import kotlinx.serialization.json.addJsonObject
import kotlinx.serialization.json.buildJsonArray
import kotlinx.serialization.json.put
import net.avianlabs.solana.SolanaClient
import net.avianlabs.solana.domain.core.Commitment

Expand All @@ -18,17 +19,14 @@ public suspend fun SolanaClient.getMinimumBalanceForRentExemption(
): Long {
val result = invoke<Long>(
method = "getMinimumBalanceForRentExemption",
params = JsonArray(buildList {
add(json.encodeToJsonElement(dataLength))
params = buildJsonArray {
add(dataLength)
commitment?.let {
add(json.encodeToJsonElement(GetMinimumBalanceForRentExemptionParams(it.value)))
addJsonObject {
put("commitment", it.value)
}
}
})
}
)
return result!!
}

@Serializable
internal data class GetMinimumBalanceForRentExemptionParams(
val commitment: String? = null,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package net.avianlabs.solana.methods

import net.avianlabs.solana.SolanaClient
import net.avianlabs.solana.domain.core.Commitment
import net.avianlabs.solana.domain.core.FeeCalculator
import net.avianlabs.solana.domain.core.NonceAccountData
import net.avianlabs.solana.tweetnacl.ed25519.PublicKey
import okio.Buffer

public suspend fun SolanaClient.getNonce(
publicKey: PublicKey,
commitment: Commitment? = null
): NonceAccount? = getAccountInfo(publicKey, commitment)
?.dataBytes
?.let { data ->
val decoded = NonceAccountData.read(Buffer().write(data))
NonceAccount(
authorizedPubkey = decoded.authorizedPubkey,
nonce = decoded.nonce,
feeCalculator = decoded.feeCalculator,
)
}

public data class NonceAccount(
val authorizedPubkey: PublicKey,
val nonce: String,
val feeCalculator: FeeCalculator,
)
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package net.avianlabs.solana.methods

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.encodeToJsonElement
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.domain.core.Commitment
import net.avianlabs.solana.domain.core.FeeCalculator

/**
* Returns the latest blockhash
Expand All @@ -17,26 +19,19 @@ public suspend fun SolanaClient.getRecentBlockhash(
): RecentBlockHash {
val result = invoke<RpcResponse.RPC<RecentBlockHash>>(
method = "getRecentBlockhash",
params = JsonArray(buildList {
commitment?.let { add(json.encodeToJsonElement(RecentBlockHashParams(it.value))) }
})
params = buildJsonArray {
commitment?.let {
addJsonObject {
put("commitment", it.value)
}
}
}
)
return result!!.value!!
}

@Serializable
public data class RecentBlockHashParams(
val commitment: String? = null,
)

@Serializable
public data class RecentBlockHash(
val blockhash: String,
val feeCalculator: FeeCalculator,
) {

@Serializable
public data class FeeCalculator(
val lamportsPerSignature: Long = 0,
)
}
)
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package net.avianlabs.solana.methods

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.encodeToJsonElement
import kotlinx.serialization.json.*
import net.avianlabs.solana.SolanaClient
import net.avianlabs.solana.domain.core.Commitment
import net.avianlabs.solana.tweetnacl.ed25519.PublicKey
Expand All @@ -23,25 +21,18 @@ public suspend fun SolanaClient.getSignaturesForAddress(
): List<SignatureInformation> {
val result = invoke<List<SignatureInformation>>(
method = "getSignaturesForAddress",
params = JsonArray(buildList {
add(json.encodeToJsonElement<PublicKey>(account))
params = buildJsonArray {
add(account.toBase58())
commitment?.let {
add(json.encodeToJsonElement(SignaturesForAddressParams(commitment = it.value)))
addJsonObject {
put("commitment", it.value)
}
}
})
}
)
return result!!
}

@Serializable
internal data class SignaturesForAddressParams(
val limit: Long? = null,
val before: String? = null,
val until: String? = null,
val commitment: String? = null,
val minContextSlot: Long? = null,
)

@Serializable
public data class SignatureInformation(
var err: JsonElement?, // TODO
Expand Down
Loading

0 comments on commit 1c88e68

Please sign in to comment.