use std::time::{SystemTime, UNIX_EPOCH};
use zera_proto::zera_txn::SmartContractExecuteTxn;
use crate::api::get_token_info_for_single_with_client;
use crate::contract::shared::validate_key_pair;
use crate::error::{Result, ZeraError};
use crate::grpc::{UnaryTransport, ValidatorApiClient};
use crate::sign::sign_with_key;
use crate::smart_contracts::{
build_smart_contract_execute_txn_with_client, BuildSmartContractExecuteOptions,
ExecuteParameter, ParameterType,
};
use crate::types::RpcConfig;
use crate::utils::amount::to_smallest_units;
use super::types::DexOptions;
pub const DEX_CONTRACT_NAME: &str = "zera_dex_proxy";
pub const DEX_INSTANCE: u32 = 1;
pub const DEFAULT_LOCK_DURATION: u64 = 60;
pub fn compute_lock_timestamp(duration_seconds: Option<u64>) -> String {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs();
(now + duration_seconds.unwrap_or(DEFAULT_LOCK_DURATION)).to_string()
}
pub async fn resolve_amount(
amount: &str,
contract_id: &str,
grpc_config: Option<RpcConfig>,
) -> Result<String> {
let client = ValidatorApiClient::new(grpc_config.unwrap_or_default())?;
resolve_amount_with_client(amount, contract_id, &client).await
}
pub async fn resolve_amount_with_client<T>(
amount: &str,
contract_id: &str,
client: &ValidatorApiClient<T>,
) -> Result<String>
where
T: UnaryTransport,
{
let token_info = get_token_info_for_single_with_client(contract_id, client).await?;
to_smallest_units(
amount,
contract_id,
Some(token_info.denomination.as_str()),
None,
)
}
pub(crate) fn fee_id_or_default(options: &DexOptions) -> String {
options
.fee_id
.clone()
.unwrap_or_else(|| "$ZRA+0000".to_string())
}
pub(crate) fn validate_signing_inputs(
public_key_base58_identifier: &str,
private_key_base58: &str,
) -> Result<()> {
if public_key_base58_identifier.is_empty() {
return Err(ZeraError::Validation(
"publicKeyBase58Identifier is required".to_string(),
));
}
if private_key_base58.is_empty() {
return Err(ZeraError::Validation(
"privateKeyBase58 is required".to_string(),
));
}
validate_key_pair(public_key_base58_identifier, private_key_base58)
}
pub(crate) async fn create_dex_transaction_with_client<T>(
action_name: &str,
parameter_value: String,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: DexOptions,
client: &ValidatorApiClient<T>,
) -> Result<SmartContractExecuteTxn>
where
T: UnaryTransport,
{
validate_signing_inputs(public_key_base58_identifier, private_key_base58)?;
let parameters = vec![
ExecuteParameter {
parameter_type: ParameterType::String.as_str().to_string(),
value: action_name.as_bytes().to_vec(),
},
ExecuteParameter {
parameter_type: ParameterType::String.as_str().to_string(),
value: parameter_value.into_bytes(),
},
];
let mut txn = build_smart_contract_execute_txn_with_client(
DEX_CONTRACT_NAME,
DEX_INSTANCE,
"execute",
¶meters,
public_key_base58_identifier,
BuildSmartContractExecuteOptions {
memo: options.memo.clone(),
grpc_config: None,
gas_fee_in_usd: options.gas_fee_in_usd,
overestimate_percent: options.overestimate_percent,
nonce: options.nonce,
fee_id: Some(fee_id_or_default(&options)),
fee_amount_parts: options.fee_amount_usd.clone(),
},
client,
)
.await?;
sign_with_key(&mut txn, private_key_base58, public_key_base58_identifier)?;
Ok(txn)
}