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
}