use std::time::{SystemTime, UNIX_EPOCH};
use prost_types::Timestamp;
use zera_proto::zera_txn::{BaseTxn, PublicKey};
use crate::api::get_nonce_with_client;
use crate::crypto::address::{generate_address_from_public_key, get_public_key_bytes};
use crate::error::{Result, ZeraError};
use crate::grpc::{UnaryTransport, ValidatorApiClient};
use crate::types::RpcConfig;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BuildStandardBaseTxnParams {
pub public_key_id: String,
pub fee_id: Option<String>,
pub fee_amount_parts: Option<String>,
pub nonce: u64,
pub memo: Option<String>,
}
pub fn build_standard_base_txn(params: BuildStandardBaseTxnParams) -> Result<BaseTxn> {
let fee_id = params.fee_id.unwrap_or_else(|| "$ZRA+0000".to_string());
let fee_amount = params.fee_amount_parts.unwrap_or_else(|| "1".to_string());
if fee_amount.is_empty() || fee_amount == "0" {
return Err(ZeraError::Validation(
"Base fee must be provided and cannot be 0".to_string(),
));
}
let public_key = PublicKey {
single: get_public_key_bytes(¶ms.public_key_id)?,
..Default::default()
};
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|error| ZeraError::Serialization(format!("Invalid system time: {error}")))?;
Ok(BaseTxn {
public_key: Some(public_key),
timestamp: Some(Timestamp {
seconds: now.as_secs() as i64,
nanos: now.subsec_nanos() as i32,
}),
fee_amount,
fee_id,
memo: params.memo.filter(|memo| !memo.trim().is_empty()),
nonce: params.nonce,
..Default::default()
})
}
pub async fn get_address_and_nonce(
public_key_id: &str,
config: RpcConfig,
) -> Result<(String, u64)> {
let client = ValidatorApiClient::new(config)?;
get_address_and_nonce_with_client(public_key_id, &client).await
}
pub async fn get_address_and_nonce_with_client<T>(
public_key_id: &str,
client: &ValidatorApiClient<T>,
) -> Result<(String, u64)>
where
T: UnaryTransport,
{
let address = generate_address_from_public_key(public_key_id)?;
let nonce = get_nonce_with_client(&address, client).await?;
Ok((address, nonce))
}