zera-sdk 0.1.0

Rust SDK for ZERA transactions, validator APIs, and bridge workflows
Documentation
use zera_proto::zera_txn::InstrumentContract;

use crate::contract::shared::{
    validate_create_contract_options, validate_key_pair, validate_premint_wallets,
    BuildContractOptions, CreateContractOptions,
};
use crate::crypto::address::generate_address_from_public_key;
use crate::error::{Result, ZeraError};
use crate::fees::{FeeConfigHelper, UniversalFeeCalculator};
use crate::grpc::{submit_transaction, UnaryTransport, ValidatorApiClient};
use crate::sign::sign_with_key;
use crate::tx::{
    build_standard_base_txn, get_address_and_nonce_with_client, BuildStandardBaseTxnParams,
};
use crate::types::RpcConfig;

pub async fn build_contract_txn(options: BuildContractOptions) -> Result<InstrumentContract> {
    let client = ValidatorApiClient::new(options.grpc_config.clone().unwrap_or_default())?;
    build_contract_txn_with_client(options, &client).await
}

pub async fn build_contract_txn_with_client<T>(
    options: BuildContractOptions,
    client: &ValidatorApiClient<T>,
) -> Result<InstrumentContract>
where
    T: UnaryTransport,
{
    validate_create_contract_options(
        &options.contract_id,
        &options.symbol,
        &options.name,
        options.contract_version,
        Some(options.contract_type),
    )?;
    if options.public_key_base58_identifier.is_empty() {
        return Err(ZeraError::Validation(
            "Public key identifier is required".to_string(),
        ));
    }
    generate_address_from_public_key(&options.public_key_base58_identifier)?;
    validate_premint_wallets(options.contract_type, &options.premint_wallets)?;

    let nonce = if let Some(nonce) = options.nonce {
        nonce
    } else {
        get_address_and_nonce_with_client(&options.public_key_base58_identifier, client)
            .await?
            .1
    };

    let base = build_standard_base_txn(BuildStandardBaseTxnParams {
        public_key_id: options.public_key_base58_identifier.clone(),
        fee_id: options.fee_id.clone(),
        fee_amount_parts: options.fee_amount_parts.clone(),
        nonce,
        memo: options.memo.clone(),
    })?;

    let mut contract_txn = InstrumentContract {
        base: Some(base),
        contract_version: options.contract_version,
        symbol: options.symbol,
        name: options.name,
        governance: options.governance,
        restricted_keys: options.restricted_keys,
        max_supply: options.max_supply,
        contract_fees: options.contract_fees,
        premint_wallets: options.premint_wallets,
        coin_denomination: Some(options.coin_denomination),
        custom_parameters: options.custom_parameters,
        contract_id: options.contract_id,
        expense_ratio: options.expense_ratio,
        r#type: options.contract_type as i32,
        update_contract_fees: options.update_contract_fees.unwrap_or(false),
        update_expense_ratio: options.update_expense_ratio.unwrap_or(false),
        quash_threshold: options.quash_threshold,
        token_compliance: options.token_compliance,
        kyc_status: options.kyc_status.unwrap_or(false),
        immutable_kyc_status: options.immutable_kyc_status.unwrap_or(false),
        max_supply_release: options.max_supply_release,
    };

    contract_txn = UniversalFeeCalculator::calculate_fee_with_client(
        FeeConfigHelper {
            contract_id: None,
            proto_object: contract_txn,
            token_info_map: std::collections::HashMap::new(),
            base_fee_id: options.fee_id,
            base_fee: options.fee_amount_parts,
            contract_fee_id: None,
            contract_fee: None,
            interface_fee_id: None,
            interface_fee: None,
            interface_address: None,
            overestimate_percent: None,
            gas_fee_in_usd: None,
            grpc_config: None,
            needs_initialization: None,
        },
        client,
    )
    .await?;

    Ok(contract_txn)
}

pub async fn create_contract(options: CreateContractOptions) -> Result<InstrumentContract> {
    validate_key_pair(
        &options.public_key_base58_identifier,
        &options.private_key_base58,
    )?;

    let mut contract_txn = build_contract_txn(options.clone()).await?;
    sign_with_key(
        &mut contract_txn,
        &options.private_key_base58,
        &options.public_key_base58_identifier,
    )?;
    Ok(contract_txn)
}

pub async fn send_create_contract(
    contract: &InstrumentContract,
    grpc_config: Option<RpcConfig>,
) -> Result<String> {
    submit_transaction(contract, grpc_config.unwrap_or_default()).await
}