use datalayer_driver::async_api::get_all_unspent_coins;
use datalayer_driver::wallet::{broadcast_spend_bundle};
use datalayer_driver::{Bytes32, Coin, DataStore, DataStoreInnerSpend, NetworkType, PublicKey, SecretKey, SpendBundle, SuccessResponse, admin_delegated_puzzle_from_key, connect_random, get_fee_estimate, get_header_hash, mint_store, oracle_delegated_puzzle, secret_key_to_public_key, select_coins, sign_coin_spends, synthetic_key_to_puzzle_hash, update_store_metadata, writer_delegated_puzzle_from_key, add_fee};
static MIN_HEIGHT: u32 = 5777842;
#[derive(Debug, Clone)]
pub struct MintParams<'mp> {
pub ssl_cert_path: &'mp str,
pub ssl_key_path: &'mp str,
pub root_hash: Bytes32,
pub owner_secret_key: SecretKey,
pub network: NetworkType,
pub previous_height: Option<u32>,
pub label: Option<String>,
pub description: Option<String>,
pub size_in_bytes: Option<u64>,
pub size_proof: Option<String>,
pub writer_public_synthetic_key: Option<PublicKey>,
pub admin_public_synthetic_key: Option<PublicKey>,
pub fee: Option<u64>,
}
pub async fn mint(params: MintParams<'_>) -> datalayer_driver::Result<DataStore> {
let peer = connect_random(params.network, params.ssl_cert_path, params.ssl_key_path).await?;
let owner_public_key = secret_key_to_public_key(¶ms.owner_secret_key);
let owner_puzzle_hash = synthetic_key_to_puzzle_hash(&owner_public_key);
let height = if let Some(specified_height) = params.previous_height {specified_height} else {MIN_HEIGHT};
let owner_previous_header_hash = get_header_hash(&peer, height).await?;
let mut delegated_puzzles = vec![oracle_delegated_puzzle(owner_puzzle_hash, 100_000)];
if let Some(key) = params.admin_public_synthetic_key {
delegated_puzzles.push(admin_delegated_puzzle_from_key(&key))
}
if let Some(key) = params.writer_public_synthetic_key {
delegated_puzzles.push(writer_delegated_puzzle_from_key(&key))
}
let fee = if let Some(specified_fee) = params.fee {
specified_fee
} else {
get_fee_estimate(&peer, 60).await?
};
let required_wallet_balance = fee + 1;
let unspent_coin_states = get_all_unspent_coins(
&peer,
owner_puzzle_hash,
Some(height),
owner_previous_header_hash,
)
.await?;
let unspent_coins = unspent_coin_states
.coin_states
.iter()
.map(|coin_state| coin_state.coin)
.collect::<Vec<Coin>>();
let selected_coins = select_coins(&unspent_coins, required_wallet_balance)?;
let SuccessResponse {
coin_spends,
new_datastore,
} = mint_store(
owner_public_key,
selected_coins,
params.root_hash,
params.label,
params.description,
params.size_in_bytes,
params.size_proof,
owner_puzzle_hash,
delegated_puzzles,
fee,
)?;
let sign_testnet = if params.network == NetworkType::Testnet11 {
true
} else {
false
};
let signature = sign_coin_spends(&coin_spends, &[params.owner_secret_key], sign_testnet)?;
let spend_bundle = SpendBundle::new(coin_spends, signature);
broadcast_spend_bundle(&peer, spend_bundle).await?;
Ok(new_datastore)
}
#[derive(Debug, Clone)]
pub struct UpdateParams<'up> {
pub ssl_cert_path: &'up str,
pub ssl_key_path: &'up str,
pub data_store: DataStore,
pub owner_secret_key: SecretKey,
pub new_root_hash: Bytes32,
pub network: NetworkType,
pub previous_height: Option<u32>,
pub new_label: Option<String>,
pub new_description: Option<String>,
pub new_size_in_bytes: Option<u64>,
pub new_size_proof: Option<String>,
pub admin_or_writer_public_key: Option<DataStoreInnerSpend>,
pub fee: Option<u64>,
}
pub async fn update(
params: UpdateParams<'_>,
) -> datalayer_driver::Result<DataStore> {
let peer = connect_random(params.network, params.ssl_cert_path, params.ssl_key_path).await?;
let owner_public_key = secret_key_to_public_key(¶ms.owner_secret_key);
let inner_spend = if let Some(key) = params.admin_or_writer_public_key {
key
} else {
DataStoreInnerSpend::Owner(owner_public_key)
};
let SuccessResponse {
coin_spends: update_store_coin_spends,
new_datastore: updated_datastore,
} = update_store_metadata(
params.data_store,
params.new_root_hash,
params.new_label,
params.new_description,
params.new_size_in_bytes,
params.new_size_proof,
inner_spend,
)?;
let fee = if let Some(specified_fee) = params.fee {
specified_fee
} else {
get_fee_estimate(&peer, 60).await?
};
let height = if let Some(specified_height) = params.previous_height {specified_height} else {MIN_HEIGHT};
let owner_puzzle_hash = synthetic_key_to_puzzle_hash(&owner_public_key);
let owner_previous_header_hash = get_header_hash(&peer, height).await?;
let unspent_coin_states = get_all_unspent_coins(
&peer,
owner_puzzle_hash,
Some(height),
owner_previous_header_hash,
)
.await?;
let unspent_coins = unspent_coin_states
.coin_states
.iter()
.map(|coin_state| coin_state.coin)
.collect::<Vec<Coin>>();
let selected_coins = select_coins(&unspent_coins, fee)?;
let coin_ids: Vec<Bytes32> = selected_coins.iter().map(|coin| coin.coin_id()).collect();
let mut coin_spends = add_fee(&owner_public_key, &selected_coins, &coin_ids, fee)?;
coin_spends.extend(update_store_coin_spends);
let sign_testnet = if params.network == NetworkType::Testnet11 {
true
} else {
false
};
let signature = sign_coin_spends(&coin_spends, &[params.owner_secret_key], sign_testnet)?;
let spend_bundle = SpendBundle::new(coin_spends, signature);
broadcast_spend_bundle(&peer, spend_bundle).await?;
Ok(updated_datastore)
}