zera-sdk 0.1.0

Rust SDK for ZERA transactions, validator APIs, and bridge workflows
Documentation
use prost::Message;
use zera_proto::zera_txn::{CoinTxn, TransferAuthentication};

use crate::error::{Result, ZeraError};
use crate::sign::signer::{create_transaction_hash, sign_transaction_data, ZeraSigner};
use crate::tx::BaseTxnAccess;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CoinTxnKeyPair {
    pub public_key: String,
    pub private_key: String,
}

pub async fn sign_and_finalize<T>(txn: &mut T, signer: &dyn ZeraSigner) -> Result<()>
where
    T: Message + BaseTxnAccess,
{
    let bytes = txn.encode_to_vec();
    let signature = signer.sign(&bytes).await?;
    {
        let base = txn
            .base_mut()
            .ok_or_else(|| ZeraError::Validation("Transaction is missing base data".to_string()))?;
        base.signature = Some(signature);
    }

    let signed_bytes = txn.encode_to_vec();
    let hash = create_transaction_hash(&signed_bytes);
    let base = txn
        .base_mut()
        .ok_or_else(|| ZeraError::Validation("Transaction is missing base data".to_string()))?;
    base.hash = Some(hash);
    Ok(())
}

pub fn sign_with_key<T>(txn: &mut T, private_key: &str, public_key_id: &str) -> Result<()>
where
    T: Message + BaseTxnAccess,
{
    let bytes = txn.encode_to_vec();
    let signature = sign_transaction_data(&bytes, private_key, public_key_id)?;
    {
        let base = txn
            .base_mut()
            .ok_or_else(|| ZeraError::Validation("Transaction is missing base data".to_string()))?;
        base.signature = Some(signature);
    }

    let signed_bytes = txn.encode_to_vec();
    let hash = create_transaction_hash(&signed_bytes);
    let base = txn
        .base_mut()
        .ok_or_else(|| ZeraError::Validation("Transaction is missing base data".to_string()))?;
    base.hash = Some(hash);
    Ok(())
}

pub async fn sign_coin_txn(txn: &mut CoinTxn, signers: &[&dyn ZeraSigner]) -> Result<()> {
    if signers.is_empty() {
        return Err(ZeraError::Validation(
            "At least one signer is required".to_string(),
        ));
    }

    let txn_bytes = txn.encode_to_vec();
    let auth = txn.auth.get_or_insert_with(TransferAuthentication::default);
    for signer in signers {
        auth.signature.push(signer.sign(&txn_bytes).await?);
    }

    let signed_bytes = txn.encode_to_vec();
    let hash = create_transaction_hash(&signed_bytes);
    let base = txn
        .base
        .as_mut()
        .ok_or_else(|| ZeraError::Validation("CoinTXN is missing base data".to_string()))?;
    base.hash = Some(hash);
    Ok(())
}

pub fn sign_coin_txn_with_keys(txn: &mut CoinTxn, keys: &[CoinTxnKeyPair]) -> Result<()> {
    if keys.is_empty() {
        return Err(ZeraError::Validation(
            "At least one key pair is required".to_string(),
        ));
    }

    let txn_bytes = txn.encode_to_vec();
    let auth = txn.auth.get_or_insert_with(TransferAuthentication::default);
    for key in keys {
        if key.public_key.is_empty() || key.private_key.is_empty() {
            return Err(ZeraError::Validation(
                "Key pair is missing privateKey or publicKey".to_string(),
            ));
        }
        auth.signature.push(sign_transaction_data(
            &txn_bytes,
            &key.private_key,
            &key.public_key,
        )?);
    }

    let signed_bytes = txn.encode_to_vec();
    let hash = create_transaction_hash(&signed_bytes);
    let base = txn
        .base
        .as_mut()
        .ok_or_else(|| ZeraError::Validation("CoinTXN is missing base data".to_string()))?;
    base.hash = Some(hash);
    Ok(())
}