zera-sdk 0.1.0

Rust SDK for ZERA transactions, validator APIs, and bridge workflows
Documentation
use std::collections::{HashMap, HashSet};

use crate::api::{get_token_fee_info_with_client, GetTokenFeeInfoParams, TokenInfo};
use crate::error::Result;
use crate::grpc::{UnaryTransport, ValidatorApiClient};

pub(crate) fn normalize_contract_id(id: &str) -> String {
    if !id.starts_with('$') {
        return id.to_string();
    }

    if let Some((head, suffix)) = id[1..].rsplit_once('+') {
        if head.contains('-') && suffix.len() == 6 && suffix.chars().all(|c| c.is_ascii_digit()) {
            if let Some((chain, symbol)) = head.split_once('-') {
                return format!(
                    "${}-{}+{}",
                    chain.to_lowercase(),
                    symbol.to_uppercase(),
                    suffix
                );
            }
        }

        if !head.contains('-') && suffix.len() == 4 && suffix.chars().all(|c| c.is_ascii_digit()) {
            return format!("${}+{}", head.to_uppercase(), suffix);
        }
    }

    id.to_string()
}

pub(crate) async fn get_token_info_map_with_client<T>(
    contract_id: &str,
    additional_contract_ids: &[String],
    client: &ValidatorApiClient<T>,
) -> Result<HashMap<String, TokenInfo>>
where
    T: UnaryTransport,
{
    let mut contract_ids = HashSet::new();
    contract_ids.insert(normalize_contract_id(contract_id));
    for id in additional_contract_ids {
        if !id.is_empty() {
            contract_ids.insert(normalize_contract_id(id));
        }
    }

    let response = get_token_fee_info_with_client(
        GetTokenFeeInfoParams {
            contract_ids: contract_ids.iter().cloned().collect(),
        },
        client,
    )
    .await?;

    let mut map = HashMap::new();
    for token in response.tokens {
        let normalized = normalize_contract_id(&token.contract_id);
        let token_info = TokenInfo {
            contract_id: token.contract_id.clone(),
            denomination: token.denomination.clone(),
            rate: token.rate.clone(),
            authorized: token.authorized,
            allowed_fees: token.allowed_fees.clone(),
            used_fees: token.used_fees.clone(),
            contract_fees: token.contract_fees.clone(),
        };
        map.insert(token.contract_id.clone(), token_info.clone());
        map.insert(normalized, token_info);
    }

    Ok(map)
}