diff --git a/libs/crypto/solana/src/main/kotlin/com/getcode/solana/rpc/Calls.kt b/libs/crypto/solana/src/main/kotlin/com/getcode/solana/rpc/Calls.kt index fea601a3f..5d58322bb 100644 --- a/libs/crypto/solana/src/main/kotlin/com/getcode/solana/rpc/Calls.kt +++ b/libs/crypto/solana/src/main/kotlin/com/getcode/solana/rpc/Calls.kt @@ -20,10 +20,12 @@ class SolanaConnection(rpcUrl: String,) { * Returns the SOL balance (in lamports) for the given public key. */ suspend fun Rpc20Driver.getBalance(publicKey: PublicKey): Result { - val response = makeRequest( - request = GetBalance(publicKey), - resultSerializer = JsonElement.serializer() - ) + val response = runCatching { + makeRequest( + request = GetBalance(publicKey), + resultSerializer = JsonElement.serializer() + ) + }.getOrElse { return Result.failure(it) } val error = response.error if (error != null) { return Result.failure(RpcException(error.code, error.message)) @@ -42,10 +44,12 @@ suspend fun Rpc20Driver.getBalance(publicKey: PublicKey): Result { * Returns 0 if the account does not exist. */ suspend fun Rpc20Driver.getTokenAccountBalance(tokenAccount: PublicKey): Result { - val response = makeRequest( - request = GetTokenAccountBalance(tokenAccount), - resultSerializer = JsonElement.serializer() - ) + val response = runCatching { + makeRequest( + request = GetTokenAccountBalance(tokenAccount), + resultSerializer = JsonElement.serializer() + ) + }.getOrElse { return Result.failure(it) } val error = response.error if (error != null) { // Account not found — treat as zero balance @@ -77,10 +81,12 @@ suspend fun Rpc20Driver.getTokenAccountBalance(tokenAccount: PublicKey): Result< * (e.g., network issue, account not found, or RPC error). */ suspend fun Rpc20Driver.doesAccountExist(publicKey: PublicKey): Result { - val response = makeRequest( - request = GetAccountInfo(publicKey), - resultSerializer = JsonElement.serializer() - ) + val response = runCatching { + makeRequest( + request = GetAccountInfo(publicKey), + resultSerializer = JsonElement.serializer() + ) + }.getOrElse { return Result.failure(it) } val error = response.error if (error != null) { return Result.failure(RpcException(error.code, error.message)) @@ -98,10 +104,12 @@ suspend fun Rpc20Driver.doesAccountExist(publicKey: PublicKey): Result { * Returns the raw account data for the given public key, base64-decoded. */ suspend fun Rpc20Driver.getAccountData(publicKey: PublicKey): Result { - val response = makeRequest( - request = GetAccountInfo(publicKey), - resultSerializer = JsonElement.serializer() - ) + val response = runCatching { + makeRequest( + request = GetAccountInfo(publicKey), + resultSerializer = JsonElement.serializer() + ) + }.getOrElse { return Result.failure(it) } val error = response.error if (error != null) { return Result.failure(RpcException(error.code, error.message)) @@ -127,10 +135,12 @@ suspend fun Rpc20Driver.getAccountData(publicKey: PublicKey): Result */ suspend fun Rpc20Driver.sendTransaction(encodedTransaction: String): Result { println("sending transaction on the blockchain => $encodedTransaction") - val response = makeRequest( - request = SendTransaction(encodedTransaction), - resultSerializer = JsonElement.serializer() - ) + val response = runCatching { + makeRequest( + request = SendTransaction(encodedTransaction), + resultSerializer = JsonElement.serializer() + ) + }.getOrElse { return Result.failure(it) } val error = response.error if (error != null) { return Result.failure(RpcException(error.code, error.message)) @@ -163,10 +173,12 @@ suspend fun Rpc20Driver.simulateTransaction( commitment: String = "confirmed", ): Result { println("simulating transaction on the blockchain => $encodedTransaction") - val response = makeRequest( - request = SimulateTransaction(encodedTransaction, commitment), - resultSerializer = JsonElement.serializer() - ) + val response = runCatching { + makeRequest( + request = SimulateTransaction(encodedTransaction, commitment), + resultSerializer = JsonElement.serializer() + ) + }.getOrElse { return Result.failure(it) } val error = response.error val errorDetails = response.result?.jsonObject?.get("err")?.toString() if (error != null || errorDetails != null) { diff --git a/libs/logging/src/main/kotlin/com/getcode/utils/ErrorUtils.kt b/libs/logging/src/main/kotlin/com/getcode/utils/ErrorUtils.kt index 230fa199a..28e94faab 100644 --- a/libs/logging/src/main/kotlin/com/getcode/utils/ErrorUtils.kt +++ b/libs/logging/src/main/kotlin/com/getcode/utils/ErrorUtils.kt @@ -10,8 +10,10 @@ import kotlinx.coroutines.CancellationException import kotlinx.coroutines.TimeoutCancellationException import timber.log.Timber import java.net.ConnectException +import java.net.SocketException import java.net.UnknownHostException import java.util.concurrent.TimeoutException +import javax.net.ssl.SSLException object ErrorUtils { private var isDisplayErrors = false @@ -30,6 +32,8 @@ object ErrorUtils { TimeoutCancellationException::class, CancellationException::class, ConnectException::class, + SSLException::class, + SocketException::class, ) fun handleError(throwable: Throwable) { @@ -76,7 +80,11 @@ object ErrorUtils { throwable is TimeoutException || throwable.cause is TimeoutException || throwable is UnknownHostException || - throwable.cause is UnknownHostException + throwable.cause is UnknownHostException || + throwable is SSLException || + throwable.cause is SSLException || + throwable is SocketException || + throwable.cause is SocketException private val gmsTransientMessages = setOf("SERVICE_NOT_AVAILABLE", "FIS_AUTH_ERROR") @@ -122,7 +130,9 @@ object ErrorUtils { fun Throwable.isNetworkError(): Boolean = this is UnknownHostException || cause is UnknownHostException || this is ConnectException || cause is ConnectException || - this is TimeoutException || cause is TimeoutException + this is TimeoutException || cause is TimeoutException || + this is SSLException || cause is SSLException || + this is SocketException || cause is SocketException data class SuppressibleException(override val message: String, override val cause: Throwable? = null) : Throwable(message, cause) { constructor(cause: Throwable) : this(cause.message.orEmpty(), cause)