use zera_proto::zera_txn::SmartContractExecuteTxn;
use crate::api::get_token_info_for_single_with_client;
use crate::error::{Result, ZeraError};
use crate::grpc::{UnaryTransport, ValidatorApiClient};
use crate::smart_contracts::send_smart_contract_execute_txn;
use crate::smart_contracts::use_cases::bridge::zera::types::{BridgeZeraOptions, BurnSolOptions};
use crate::smart_contracts::use_cases::bridge::zera::utils::create_bridge_transaction_with_client;
use crate::utils::amount::to_smallest_units;
pub async fn lock_zera(
contract_id: &str,
amount: &str,
to_solana_address: &str,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: BridgeZeraOptions,
) -> Result<SmartContractExecuteTxn> {
let client = ValidatorApiClient::new(options.grpc_config.clone().unwrap_or_default())?;
lock_zera_with_client(
contract_id,
amount,
to_solana_address,
public_key_base58_identifier,
private_key_base58,
options,
&client,
)
.await
}
pub async fn lock_zera_with_client<T>(
contract_id: &str,
amount: &str,
to_solana_address: &str,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: BridgeZeraOptions,
client: &ValidatorApiClient<T>,
) -> Result<SmartContractExecuteTxn>
where
T: UnaryTransport,
{
if contract_id.is_empty() {
return Err(ZeraError::Validation("contractId is required".to_string()));
}
if amount.is_empty() {
return Err(ZeraError::Validation("amount is required".to_string()));
}
if to_solana_address.is_empty() {
return Err(ZeraError::Validation(
"toSolanaAddress is required".to_string(),
));
}
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(),
));
}
let token_info = get_token_info_for_single_with_client(contract_id, client).await?;
let amount_in_parts =
to_smallest_units(amount, contract_id, Some(&token_info.denomination), None)?;
let parameter_value = format!("{contract_id},{amount_in_parts},{to_solana_address}");
let fee_id = options
.fee_id
.clone()
.unwrap_or_else(|| contract_id.to_string());
create_bridge_transaction_with_client(
"lock_zera",
¶meter_value,
public_key_base58_identifier,
private_key_base58,
&fee_id,
options,
client,
)
.await
}
pub async fn lock_zera_and_send(
contract_id: &str,
amount: &str,
to_solana_address: &str,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: BridgeZeraOptions,
) -> Result<String> {
let grpc_config = options.grpc_config.clone();
let transaction = lock_zera(
contract_id,
amount,
to_solana_address,
public_key_base58_identifier,
private_key_base58,
options,
)
.await?;
send_smart_contract_execute_txn(&transaction, grpc_config).await
}
pub use lock_zera as bridge_zera_to_sol;
pub use lock_zera_and_send as bridge_zera_to_sol_and_send;
pub async fn burn_sol(
contract_id: &str,
amount: &str,
to_solana_address: &str,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: BurnSolOptions,
) -> Result<SmartContractExecuteTxn> {
let bridge_options: BridgeZeraOptions = options.clone().into();
let client = ValidatorApiClient::new(bridge_options.grpc_config.clone().unwrap_or_default())?;
burn_sol_with_client(
contract_id,
amount,
to_solana_address,
public_key_base58_identifier,
private_key_base58,
options,
&client,
)
.await
}
pub async fn burn_sol_with_client<T>(
contract_id: &str,
amount: &str,
to_solana_address: &str,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: BurnSolOptions,
client: &ValidatorApiClient<T>,
) -> Result<SmartContractExecuteTxn>
where
T: UnaryTransport,
{
if contract_id.is_empty() {
return Err(ZeraError::Validation("contractId is required".to_string()));
}
if amount.is_empty() {
return Err(ZeraError::Validation("amount is required".to_string()));
}
if to_solana_address.is_empty() {
return Err(ZeraError::Validation(
"toSolanaAddress is required".to_string(),
));
}
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(),
));
}
let amount_in_parts = if let Some(denomination) = options.denomination.as_deref() {
to_smallest_units(amount, contract_id, Some(denomination), None)?
} else {
let token_info = get_token_info_for_single_with_client(contract_id, client).await?;
to_smallest_units(amount, contract_id, Some(&token_info.denomination), None)?
};
let parameter_value = format!("{contract_id},{amount_in_parts},{to_solana_address}");
let fee_id = options
.fee_id
.clone()
.unwrap_or_else(|| contract_id.to_string());
create_bridge_transaction_with_client(
"burn_sol",
¶meter_value,
public_key_base58_identifier,
private_key_base58,
&fee_id,
options.into(),
client,
)
.await
}
pub async fn burn_sol_and_send(
contract_id: &str,
amount: &str,
to_solana_address: &str,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: BurnSolOptions,
) -> Result<String> {
let grpc_config = options.grpc_config.clone();
let transaction = burn_sol(
contract_id,
amount,
to_solana_address,
public_key_base58_identifier,
private_key_base58,
options,
)
.await?;
send_smart_contract_execute_txn(&transaction, grpc_config).await
}