diff --git a/Cargo.lock b/Cargo.lock index 56f538d..4759fb8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1557,6 +1557,7 @@ dependencies = [ "serde", "serde_json", "solana-rpc-client", + "solana-rpc-client-api", "solana-rpc-client-nonce-utils", "solana-sdk", "solana-transaction-status", diff --git a/crates/by-chain/icepick-solana/Cargo.toml b/crates/by-chain/icepick-solana/Cargo.toml index f07f7a6..1d191ae 100644 --- a/crates/by-chain/icepick-solana/Cargo.toml +++ b/crates/by-chain/icepick-solana/Cargo.toml @@ -12,6 +12,7 @@ icepick-module = { version = "0.1.0", path = "../../icepick-module" } serde = { workspace = true, features = ["derive"] } serde_json.workspace = true solana-rpc-client = { version = "2.1.1", default-features = false } +solana-rpc-client-api = "2.1.7" solana-rpc-client-nonce-utils = "2.1.7" solana-sdk = { version = "2.1.1" } solana-transaction-status = "2.1.1" diff --git a/crates/by-chain/icepick-solana/src/lib.rs b/crates/by-chain/icepick-solana/src/lib.rs index 328926d..4740071 100644 --- a/crates/by-chain/icepick-solana/src/lib.rs +++ b/crates/by-chain/icepick-solana/src/lib.rs @@ -63,10 +63,13 @@ use icepick_module::{ Module, }; use serde::{Deserialize, Serialize}; +use solana_rpc_client::rpc_client::SerializableTransaction; +use solana_rpc_client_api::client_error::Result as ClientResult; use solana_sdk::{ pubkey::Pubkey, signer::{keypair::Keypair, Signer}, system_instruction, + transaction::TransactionError, }; use std::{collections::HashSet, str::FromStr}; @@ -1081,16 +1084,63 @@ impl Module for Solana { } }) } - Err(e) => { - serde_json::json!({ - "blob": { - "status": "send_and_confirm", - "error": e.to_string(), - } - }) + Err(_) => { + let signature = transaction.get_signature(); + let status = client.get_signature_status(signature); + blob_for_signature_status(status, signature, &cluster_suffix) } }) } } } } + +fn blob_for_signature_status( + status: ClientResult>>, + signature: &solana_sdk::signature::Signature, + cluster_suffix: &str, +) -> serde_json::Value { + match status { + Ok(Some(Ok(()))) => { + // transaction passed. + eprintln!("An error occurred while broadcasting the transaction, but the transaction was confirmed manually."); + serde_json::json!({ + "blob": { + "status": "send_and_confirm", + "succcess": signature.to_string(), + "url": format!("https://explorer.solana.com/tx/{signature}{cluster_suffix}"), + } + }) + } + Ok(Some(Err(e))) => { + // transaction failed on-cluster + eprintln!("The transaction failed on-chain: {e}"); + serde_json::json!({ + "blob": { + "status": "send_and_confirm", + "error": e.to_string(), + } + }) + } + Ok(None) => { + // transaction may not have been broadcast + eprintln!("The transaction was possibly not received by the cluster."); + serde_json::json!({ + "blob": { + "status": "send_and_confirm", + "error": format!("Transaction {signature} does not exist on-cluster"), + } + }) + } + Err(e) => { + // RPC request failed + eprintln!("An error occurred while interacting with the cluster: {e}"); + serde_json::json!({ + "blob": { + "status": "send_and_confirm", + "error": e.to_string(), + } + }) + } + } +}