Skip to content

Commit

Permalink
Ktx Client Sample App: Remove deprecated SolanaKT library (#874)
Browse files Browse the repository at this point in the history
* basic web3core support

* migrate to rpc core
  • Loading branch information
Funkatronics authored Jun 18, 2024
1 parent f711286 commit c87dc6f
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 58 deletions.
2 changes: 1 addition & 1 deletion android/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ multimult = "0.2.3"
nvWebsocketClient = "2.14"
robolectric = "4.12.2"
slf4jAndroid = "1.7.36"
web3Core = "0.3.0-beta3"
web3Core = "0.3.0-beta4"

[libraries]
androidx-activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "androidxActivityKtx" }
Expand Down
4 changes: 3 additions & 1 deletion examples/example-clientlib-ktx-app/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ dependencies {
implementation "com.google.dagger:hilt-android:2.51.1"
kapt "com.google.dagger:hilt-compiler:2.51.1"

implementation 'com.github.metaplex-foundation:SolanaKT:2.1.1'
implementation 'com.solanamobile:rpc-core:0.2.7'
implementation 'com.solanamobile:rpc-solana:0.2.7'
implementation 'com.solanamobile:rpc-ktordriver:0.2.7'
implementation 'org.bitcoinj:bitcoinj-core:0.16.2'
implementation 'com.squareup.okhttp3:okhttp:4.12.0'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.solanamobile.ktxclientsample.usecase

import android.content.SharedPreferences
import android.net.Uri
import com.solana.core.PublicKey
import com.solana.publickey.SolanaPublicKey
import java.lang.IllegalArgumentException
import javax.inject.Inject

Expand All @@ -11,7 +11,7 @@ sealed class WalletConnection
object NotConnected : WalletConnection()

data class Connected(
val publicKey: PublicKey,
val publicKey: SolanaPublicKey,
val accountLabel: String,
val authToken: String,
val walletUriBase: Uri? = null
Expand Down Expand Up @@ -41,17 +41,17 @@ class PersistanceUseCase @Inject constructor(
val newConn = if (key.isNullOrEmpty() || token.isNullOrEmpty()) {
NotConnected
} else {
Connected(PublicKey(key), accountLabel, token, walletUriBase)
Connected(SolanaPublicKey.from(key), accountLabel, token, walletUriBase)
}

return newConn
}
}
}

fun persistConnection(pubKey: PublicKey, accountLabel: String, token: String, walletUriBase: Uri?) {
fun persistConnection(pubKey: SolanaPublicKey, accountLabel: String, token: String, walletUriBase: Uri?) {
sharedPreferences.edit().apply {
putString(PUBKEY_KEY, pubKey.toBase58())
putString(PUBKEY_KEY, pubKey.base58())
putString(ACCOUNT_LABEL, accountLabel)
putString(AUTH_TOKEN_KEY, token)
putString(WALLET_URI_BASE, walletUriBase.toString())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,80 +1,66 @@
package com.solanamobile.ktxclientsample.usecase

import com.solana.Solana
import com.solana.api.Api
import com.solana.api.getBalance
import com.solana.api.getRecentBlockhash
import com.solana.api.getSignatureStatuses
import com.solana.api.requestAirdrop
import com.solana.core.PublicKey
import com.solana.models.SignatureStatusRequestConfiguration
import com.solana.networking.Commitment
import com.solana.networking.HttpNetworkingRouter
import com.solana.networking.Network
import com.solana.networking.RPCEndpoint
import com.solana.networking.KtorNetworkDriver
import com.solana.publickey.SolanaPublicKey
import com.solana.rpc.Commitment
import com.solana.rpc.SolanaRpcClient
import com.solana.rpc.TransactionOptions
import com.solanamobile.ktxclientsample.BuildConfig
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.withContext
import java.net.URL
import javax.inject.Inject

class SolanaRpcUseCase @Inject constructor() {

private val api: Api
private val rpc: SolanaRpcClient

init {
val url = URL(BuildConfig.HELIUS_KEY?.let {
val url = BuildConfig.HELIUS_KEY?.let {
"https://devnet.helius-rpc.com/?api-key=$it"
} ?: "https://api.devnet.solana.com")
} ?: "https://api.devnet.solana.com"

val endPoint = RPCEndpoint.custom(url, url, Network.devnet)
val network = HttpNetworkingRouter(endPoint)

api = Solana(network).api
rpc = SolanaRpcClient(url, KtorNetworkDriver())
}

suspend fun requestAirdrop(pubkey: PublicKey): String =
suspend fun requestAirdrop(pubkey: SolanaPublicKey): String =
withContext(Dispatchers.IO) {
val result = api.requestAirdrop(pubkey, LAMPORTS_PER_AIRDROP)
result.getOrThrow()
val result = rpc.requestAirdrop(pubkey,
LAMPORTS_PER_AIRDROP/LAMPORTS_PER_SOL.toFloat())
result.result ?: throw Error(result.error?.message)
}

suspend fun awaitConfirmationAsync(signature: String): Deferred<Boolean> {
return coroutineScope {
async {
return@async withContext(Dispatchers.IO) {
repeat(5) {
val result = api.getSignatureStatuses(listOf(signature), SignatureStatusRequestConfiguration(true))
val status = result.getOrThrow()[0].confirmationStatus

if (status == Commitment.CONFIRMED.value || status == Commitment.FINALIZED.value) {
return@withContext true
}
}

false
rpc.confirmTransaction(signature, TransactionOptions(commitment = Commitment.CONFIRMED))
.getOrDefault(false)
}
}
}
}

suspend fun getBalance(pubkey: PublicKey, asReadable: Boolean = true): Double =
suspend fun getBalance(pubkey: SolanaPublicKey, asReadable: Boolean = true): Double =
withContext(Dispatchers.IO) {
val result = api.getBalance(pubkey)
val result = rpc.getBalance(pubkey).let { result ->
result.result ?: throw Error(result.error?.message)
}

if (asReadable) {
result.getOrThrow().toDouble() / LAMPORTS_PER_SOL.toDouble()
result.toDouble() / LAMPORTS_PER_SOL.toDouble()
} else {
result.getOrThrow().toDouble()
result.toDouble()
}
}

suspend fun getLatestBlockHash(): String =
withContext(Dispatchers.IO) {
api.getRecentBlockhash().getOrThrow()
rpc.getLatestBlockhash().run {
result?.blockhash ?: throw Error(error?.message)
}
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ package com.solanamobile.ktxclientsample.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.solana.core.PublicKey
import com.solana.core.SerializeConfig
import com.solana.core.Transaction
import com.solana.mobilewalletadapter.clientlib.ActivityResultSender
import com.solana.mobilewalletadapter.clientlib.AdapterOperations
import com.solana.mobilewalletadapter.clientlib.MobileWalletAdapter
Expand All @@ -13,6 +10,9 @@ import com.solana.mobilewalletadapter.clientlib.protocol.MobileWalletAdapterClie
import com.solana.mobilewalletadapter.clientlib.successPayload
import com.solana.mobilewalletadapter.common.signin.SignInWithSolana
import com.solana.programs.MemoProgram
import com.solana.publickey.SolanaPublicKey
import com.solana.transaction.Message
import com.solana.transaction.toUnsignedTransaction
import com.solanamobile.ktxclientsample.usecase.Connected
import com.solanamobile.ktxclientsample.usecase.NotConnected
import com.solanamobile.ktxclientsample.usecase.PersistanceUseCase
Expand Down Expand Up @@ -59,7 +59,7 @@ class SampleViewModel @Inject constructor(
if (persistedConn is Connected) {
viewModelScope.launch {
_state.value.copy(
userAddress = persistedConn.publicKey.toBase58(),
userAddress = persistedConn.publicKey.base58(),
userLabel = persistedConn.accountLabel,
solBalance = solanaRpcUseCase.getBalance(persistedConn.publicKey)
).updateViewState()
Expand All @@ -82,15 +82,15 @@ class SampleViewModel @Inject constructor(
viewModelScope.launch {
connect(sender) { authResult ->
withContext(Dispatchers.IO) {
val publicKey = PublicKey(authResult.accounts.first().publicKey)
val publicKey = SolanaPublicKey(authResult.accounts.first().publicKey)
val blockHash = solanaRpcUseCase.getLatestBlockHash()

val tx = Transaction()
tx.add(MemoProgram.writeUtf8(publicKey, memoText))
tx.setRecentBlockHash(blockHash!!)
tx.feePayer = publicKey
val tx = Message.Builder()
.setRecentBlockhash(blockHash)
.addInstruction(MemoProgram.publishMemo(publicKey, memoText))
.build().toUnsignedTransaction()

val bytes = tx.serialize(SerializeConfig(requireAllSignatures = false))
val bytes = tx.serialize()
val sig = signAndSendTransactions(arrayOf(bytes)).signatures.firstOrNull()
Base58.encode(sig)
}
Expand Down Expand Up @@ -146,7 +146,7 @@ class SampleViewModel @Inject constructor(
when (result) {
is TransactionResult.Success -> {
val currentConn = Connected(
PublicKey(result.authResult.accounts.first().publicKey),
SolanaPublicKey(result.authResult.accounts.first().publicKey),
result.authResult.accounts.first().accountLabel ?: "",
result.authResult.authToken,
result.authResult.walletUriBase
Expand All @@ -156,7 +156,7 @@ class SampleViewModel @Inject constructor(
currentConn.accountLabel, currentConn.authToken, currentConn.walletUriBase)

_state.value.copy(
userAddress = currentConn.publicKey.toBase58(),
userAddress = currentConn.publicKey.base58(),
userLabel = currentConn.accountLabel,
solBalance = solanaRpcUseCase.getBalance(currentConn.publicKey)
).updateViewState()
Expand All @@ -179,7 +179,7 @@ class SampleViewModel @Inject constructor(
}
}

private suspend fun requestAirdrop(publicKey: PublicKey) {
private suspend fun requestAirdrop(publicKey: SolanaPublicKey) {
try {
val tx = solanaRpcUseCase.requestAirdrop(publicKey)
val confirmed = solanaRpcUseCase.awaitConfirmationAsync(tx).await()
Expand Down

0 comments on commit c87dc6f

Please sign in to comment.