use chia_bls::PublicKey;
use chia_protocol::{Bytes32, CoinSpend};
use chia_puzzle_types::standard::StandardArgs;
use chia_sdk_driver::{Cat, SpendContext, StandardLayer};
use chia_sdk_types::Conditions;
use crate::error::WalletError;
#[derive(Clone, Debug)]
pub struct IssueCatResponse {
pub coin_spends: Vec<CoinSpend>,
pub asset_id: Bytes32,
pub cat_coins: Vec<chia_protocol::Coin>,
}
pub fn issue_cat(
issuer_synthetic_key: PublicKey,
selected_coins: Vec<chia_protocol::Coin>,
amount: u64,
fee: u64,
) -> Result<IssueCatResponse, WalletError> {
if selected_coins.is_empty() {
return Err(WalletError::Parse("selected_coins is empty".to_string()));
}
let issuer_puzzle_hash: Bytes32 = StandardArgs::curry_tree_hash(issuer_synthetic_key).into();
let total_amount_from_coins: u64 = selected_coins.iter().map(|c| c.amount).sum();
let reserved = amount + fee;
if total_amount_from_coins < reserved {
return Err(WalletError::Parse(
"selected coins do not cover amount + fee".to_string(),
));
}
let mut ctx = SpendContext::new();
let p2 = StandardLayer::new(issuer_synthetic_key);
let lead_coin = selected_coins[0];
let lead_coin_name = lead_coin.coin_id();
for coin in selected_coins.into_iter().skip(1) {
p2.spend(
&mut ctx,
coin,
Conditions::new().assert_concurrent_spend(lead_coin_name),
)?;
}
let issuer_hint = ctx.hint(issuer_puzzle_hash)?;
let (issue_conditions, cats) = Cat::single_issuance(
&mut ctx,
lead_coin_name,
None,
amount,
Conditions::new().create_coin(issuer_puzzle_hash, amount, issuer_hint),
)?;
let mut lead_conditions = issue_conditions;
if fee > 0 {
lead_conditions = lead_conditions.reserve_fee(fee);
}
if total_amount_from_coins > reserved {
lead_conditions = lead_conditions.create_coin(
issuer_puzzle_hash,
total_amount_from_coins - reserved,
issuer_hint,
);
}
p2.spend(&mut ctx, lead_coin, lead_conditions)?;
let asset_id = cats
.first()
.map(|c| c.info.asset_id)
.ok_or_else(|| WalletError::Parse("CAT issuance produced no coins".to_string()))?;
Ok(IssueCatResponse {
coin_spends: ctx.take(),
asset_id,
cat_coins: cats.iter().map(|c| c.coin).collect(),
})
}