use std::str::FromStr;
#[cfg(not(target_arch = "wasm32"))]
use crate::rpc::{request_airdrop_with_confirmation, wait_for_confirmation};
use crate::{
error::{Result, RialoError},
generated::{rpc_client::RpcClient, types::AccountInfo},
keyring::Keyring,
rpc::types::{Pubkey, Signature},
ClientContext,
};
#[derive(Clone)]
pub struct RialoConfig {
pub rpc_url: String,
pub keyring: Keyring,
}
impl RialoConfig {
pub fn new(rpc_url: String, keyring: Keyring) -> Self {
Self { rpc_url, keyring }
}
#[deprecated(since = "0.2.0", note = "Use new() with a Keyring instead")]
pub fn with_wallet(rpc_url: String, wallet: Keyring) -> Self {
Self::new(rpc_url, wallet)
}
}
pub struct Rialo {
client_context: ClientContext,
keyring: Keyring,
}
impl Rialo {
pub fn new(config: RialoConfig) -> Self {
let client_context = ClientContext::new(config.rpc_url);
Self {
client_context,
keyring: config.keyring,
}
}
pub fn pubkey(&self) -> Pubkey {
self.keyring.pubkey()
}
pub fn keyring(&self) -> &Keyring {
&self.keyring
}
#[deprecated(since = "0.2.0", note = "Use keyring() instead")]
pub fn wallet(&self) -> &Keyring {
&self.keyring
}
pub fn client_context(&self) -> &ClientContext {
&self.client_context
}
pub async fn get_account_balance(&self, address: Option<Pubkey>) -> Result<f64> {
let addr = address.unwrap_or_else(|| self.pubkey());
let kelvin = self.client_context.get_balance(&addr).await?;
Ok(kelvin_to_rlo(kelvin))
}
pub async fn get_account(&self, address: Option<Pubkey>) -> Result<AccountInfo> {
let addr = address.unwrap_or_else(|| self.pubkey());
self.client_context.get_account_info(&addr).await
}
#[cfg(not(target_arch = "wasm32"))]
pub async fn airdrop(&self, amount: f64, address: Option<Pubkey>) -> Result<Signature> {
let addr = address.unwrap_or_else(|| self.pubkey());
let kelvin = rlo_to_kelvin(amount);
request_airdrop_with_confirmation(&self.client_context, &addr, kelvin, None).await
}
pub async fn get_rent_exemption(&self, data_size: Option<usize>) -> Result<u64> {
let size = data_size.unwrap_or(0) as u64;
self.client_context
.get_minimum_balance_for_rent_exemption(size)
.await
}
#[cfg(feature = "bincode")]
pub async fn transfer(&self, recipient: Pubkey, amount: f64) -> Result<Signature> {
use crate::transaction::TransactionBuilder;
let kelvin = rlo_to_kelvin(amount);
let sender = self.pubkey();
let valid_from = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.expect("Time went backwards")
.as_millis() as i64;
let config_hash_prefix = self.client_context.get_config_hash_prefix().await?;
let signed_tx = TransactionBuilder::new(sender, valid_from, config_hash_prefix)
.add_transfer_instruction(&sender, &recipient, kelvin)
.sign_with_keypair(&self.keyring, 0)?;
let signature = self
.client_context
.send_transaction(&signed_tx, None)
.await?;
#[cfg(not(target_arch = "wasm32"))]
wait_for_confirmation(&self.client_context, &signature, None).await?;
Ok(signature)
}
pub async fn get_transaction(&self, signature: &str) -> Result<serde_json::Value> {
let sig = Signature::from_str(signature)
.map_err(|e| RialoError::InvalidInput(format!("Invalid signature: {}", e)))?;
let tx_response = self.client_context.get_transaction(&sig).await?;
Ok(serde_json::to_value(tx_response)?)
}
#[cfg(feature = "bincode")]
pub async fn deploy_program(&self, program_path: &str) -> Result<Pubkey> {
use crate::program::{FileProgramDataSource, ProgramDeployment};
let data_source = FileProgramDataSource::new(program_path);
let mut deployment = ProgramDeployment::new(data_source);
deployment.deploy(&self.client_context, &self.keyring).await
}
#[cfg(feature = "bincode")]
pub async fn set_number(&self, _program_id: Pubkey, _number: u32) -> Result<Option<Signature>> {
Err(RialoError::InvalidInput(
"set_number requires program-specific implementation".to_string(),
))
}
}
pub fn create_client_config(rpc_url: &str, keyring: Keyring) -> RialoConfig {
RialoConfig::new(rpc_url.to_string(), keyring)
}
fn rlo_to_kelvin(rlo: f64) -> u64 {
(rlo * 1_000_000_000.0) as u64
}
fn kelvin_to_rlo(kelvin: u64) -> f64 {
kelvin as f64 / 1_000_000_000.0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rlo_kelvin_conversion() {
assert_eq!(rlo_to_kelvin(1.0), 1_000_000_000);
assert_eq!(rlo_to_kelvin(0.5), 500_000_000);
assert_eq!(rlo_to_kelvin(0.001), 1_000_000);
assert_eq!(kelvin_to_rlo(1_000_000_000), 1.0);
assert_eq!(kelvin_to_rlo(500_000_000), 0.5);
assert_eq!(kelvin_to_rlo(1_000_000), 0.001);
}
#[test]
fn test_config_creation() {
let keypair = ed25519_dalek::SigningKey::generate(&mut rand::thread_rng());
let keyring = Keyring::new("test".to_string(), keypair, None, None);
let config = create_client_config("http://127.0.0.1:4104", keyring);
assert_eq!(config.rpc_url, "http://127.0.0.1:4104");
}
}