use zera_proto::zera_guardian::{
zera_payload, ZeraContractPayload, ZeraMintPayload, ZeraPayload, ZeraReleasePayload,
};
use zera_proto::zera_txn::SmartContractExecuteTxn;
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::{
CreateSolOptions, MintSolOptions, ReleaseZeraOptions,
};
use crate::smart_contracts::use_cases::bridge::zera::utils::create_bridge_transaction_with_client;
pub async fn release_zera(
to_zera_address: &str,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: ReleaseZeraOptions,
) -> Result<SmartContractExecuteTxn> {
let client = ValidatorApiClient::new(options.grpc_config.clone().unwrap_or_default())?;
release_zera_with_client(
to_zera_address,
public_key_base58_identifier,
private_key_base58,
options,
&client,
)
.await
}
pub async fn release_zera_with_client<T>(
to_zera_address: &str,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: ReleaseZeraOptions,
client: &ValidatorApiClient<T>,
) -> Result<SmartContractExecuteTxn>
where
T: UnaryTransport,
{
if to_zera_address.is_empty() {
return Err(ZeraError::Validation(
"toZeraAddress is required".to_string(),
));
}
let payload = options
.payload
.as_ref()
.ok_or_else(|| ZeraError::Validation("payload is required".to_string()))?;
let release_payload = expect_release_payload(payload)?;
let signatures = payload.signatures.join("|");
let guardian_keys = payload.public_keys.join("|");
let parameter_value = [
release_payload.zera_contract_id.as_str(),
release_payload.amount.as_str(),
to_zera_address,
release_payload.tx_signature.as_str(),
payload.signed_hash.as_str(),
signatures.as_str(),
guardian_keys.as_str(),
]
.join(",");
let fee_id = options
.fee_id
.clone()
.unwrap_or_else(|| release_payload.zera_contract_id.clone());
create_bridge_transaction_with_client(
"release_zera",
¶meter_value,
public_key_base58_identifier,
private_key_base58,
&fee_id,
options.into(),
client,
)
.await
}
pub async fn release_zera_and_send(
to_zera_address: &str,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: ReleaseZeraOptions,
) -> Result<String> {
let grpc_config = options.grpc_config.clone();
let transaction = release_zera(
to_zera_address,
public_key_base58_identifier,
private_key_base58,
options,
)
.await?;
send_smart_contract_execute_txn(&transaction, grpc_config).await
}
pub async fn mint_sol(
to_zera_address: &str,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: MintSolOptions,
) -> Result<SmartContractExecuteTxn> {
let client = ValidatorApiClient::new(options.grpc_config.clone().unwrap_or_default())?;
mint_sol_with_client(
to_zera_address,
public_key_base58_identifier,
private_key_base58,
options,
&client,
)
.await
}
pub async fn mint_sol_with_client<T>(
to_zera_address: &str,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: MintSolOptions,
client: &ValidatorApiClient<T>,
) -> Result<SmartContractExecuteTxn>
where
T: UnaryTransport,
{
if to_zera_address.is_empty() {
return Err(ZeraError::Validation(
"toZeraAddress is required".to_string(),
));
}
let payload = options
.payload
.as_ref()
.ok_or_else(|| ZeraError::Validation("payload is required".to_string()))?;
let mint_payload = expect_mint_payload(payload)?;
let signatures = payload.signatures.join("|");
let guardian_keys = payload.public_keys.join("|");
let parameter_value = [
mint_payload.solana_mint_address.as_str(),
mint_payload.amount.as_str(),
to_zera_address,
mint_payload.usd_price.as_str(),
mint_payload.tx_signature.as_str(),
payload.signed_hash.as_str(),
signatures.as_str(),
guardian_keys.as_str(),
]
.join(",");
let fee_id = options
.fee_id
.clone()
.unwrap_or_else(|| "$ZRA+0000".to_string());
create_bridge_transaction_with_client(
"mint_sol",
¶meter_value,
public_key_base58_identifier,
private_key_base58,
&fee_id,
options.into(),
client,
)
.await
}
pub async fn mint_sol_and_send(
to_zera_address: &str,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: MintSolOptions,
) -> Result<String> {
let grpc_config = options.grpc_config.clone();
let transaction = mint_sol(
to_zera_address,
public_key_base58_identifier,
private_key_base58,
options,
)
.await?;
send_smart_contract_execute_txn(&transaction, grpc_config).await
}
pub async fn create_sol(
to_zera_address: &str,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: CreateSolOptions,
) -> Result<SmartContractExecuteTxn> {
let client = ValidatorApiClient::new(options.grpc_config.clone().unwrap_or_default())?;
create_sol_with_client(
to_zera_address,
public_key_base58_identifier,
private_key_base58,
options,
&client,
)
.await
}
pub async fn create_sol_with_client<T>(
to_zera_address: &str,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: CreateSolOptions,
client: &ValidatorApiClient<T>,
) -> Result<SmartContractExecuteTxn>
where
T: UnaryTransport,
{
if to_zera_address.is_empty() {
return Err(ZeraError::Validation(
"toZeraAddress is required".to_string(),
));
}
let payload = options
.payload
.as_ref()
.ok_or_else(|| ZeraError::Validation("payload is required".to_string()))?;
let contract_payload = expect_contract_payload(payload)?;
let signatures = payload.signatures.join("|");
let guardian_keys = payload.public_keys.join("|");
let parameter_value = [
contract_payload.symbol.as_str(),
contract_payload.name.as_str(),
contract_payload.denomination.as_str(),
to_zera_address,
contract_payload.amount.as_str(),
contract_payload.solana_mint_address.as_str(),
contract_payload.uri.as_str(),
contract_payload.solana_authorized_address.as_str(),
contract_payload.tx_signature.as_str(),
payload.signed_hash.as_str(),
signatures.as_str(),
guardian_keys.as_str(),
contract_payload.usd_price.as_str(),
]
.join(",");
let fee_id = options
.fee_id
.clone()
.unwrap_or_else(|| "$ZRA+0000".to_string());
create_bridge_transaction_with_client(
"create_sol",
¶meter_value,
public_key_base58_identifier,
private_key_base58,
&fee_id,
options.into(),
client,
)
.await
}
pub async fn create_sol_and_send(
to_zera_address: &str,
public_key_base58_identifier: &str,
private_key_base58: &str,
options: CreateSolOptions,
) -> Result<String> {
let grpc_config = options.grpc_config.clone();
let transaction = create_sol(
to_zera_address,
public_key_base58_identifier,
private_key_base58,
options,
)
.await?;
send_smart_contract_execute_txn(&transaction, grpc_config).await
}
fn payload_case_name(payload: &ZeraPayload) -> &'static str {
match payload.payload {
None => "none",
Some(zera_payload::Payload::ContractPayload(_)) => "contractPayload",
Some(zera_payload::Payload::MintPayload(_)) => "mintPayload",
Some(zera_payload::Payload::ReleasePayload(_)) => "releasePayload",
}
}
fn expect_release_payload(payload: &ZeraPayload) -> Result<&ZeraReleasePayload> {
match payload.payload.as_ref() {
Some(zera_payload::Payload::ReleasePayload(release_payload)) => Ok(release_payload),
_ => Err(ZeraError::Validation(format!(
"Expected releasePayload, got: {}",
payload_case_name(payload)
))),
}
}
fn expect_mint_payload(payload: &ZeraPayload) -> Result<&ZeraMintPayload> {
match payload.payload.as_ref() {
Some(zera_payload::Payload::MintPayload(mint_payload)) => Ok(mint_payload),
_ => Err(ZeraError::Validation(format!(
"Expected mintPayload, got: {}",
payload_case_name(payload)
))),
}
}
fn expect_contract_payload(payload: &ZeraPayload) -> Result<&ZeraContractPayload> {
match payload.payload.as_ref() {
Some(zera_payload::Payload::ContractPayload(contract_payload)) => Ok(contract_payload),
_ => Err(ZeraError::Validation(format!(
"Expected contractPayload, got: {}",
payload_case_name(payload)
))),
}
}