use getset::Getters;
use serde::{Deserialize, Serialize};
use crate::{
client::{api::PreparedTransactionData, secret::SecretManage},
types::block::{
address::Bech32Address,
output::{
feature::{IssuerFeature, MetadataFeature, SenderFeature, TagFeature},
unlock_condition::AddressUnlockCondition,
NftId, NftOutputBuilder,
},
ConvertTo,
},
wallet::{
account::{operations::transaction::Transaction, Account, TransactionOptions},
Error as WalletError,
},
};
#[derive(Debug, Clone, Serialize, Deserialize, Default, Getters)]
#[serde(rename_all = "camelCase")]
pub struct MintNftParams {
#[getset(get = "pub")]
address: Option<Bech32Address>,
#[getset(get = "pub")]
sender: Option<Bech32Address>,
#[getset(get = "pub")]
#[serde(default, with = "crate::utils::serde::option_prefix_hex_bytes")]
metadata: Option<Vec<u8>>,
#[getset(get = "pub")]
#[serde(default, with = "crate::utils::serde::option_prefix_hex_bytes")]
tag: Option<Vec<u8>>,
#[getset(get = "pub")]
issuer: Option<Bech32Address>,
#[getset(get = "pub")]
#[serde(default, with = "crate::utils::serde::option_prefix_hex_bytes")]
immutable_metadata: Option<Vec<u8>>,
}
impl MintNftParams {
pub fn new() -> Self {
Self::default()
}
pub fn try_with_address(mut self, address: impl ConvertTo<Bech32Address>) -> crate::wallet::Result<Self> {
self.address = Some(address.convert()?);
Ok(self)
}
pub fn with_address(mut self, address: impl Into<Option<Bech32Address>>) -> Self {
self.address = address.into();
self
}
pub fn try_with_sender(mut self, sender: impl ConvertTo<Bech32Address>) -> crate::wallet::Result<Self> {
self.sender = Some(sender.convert()?);
Ok(self)
}
pub fn with_sender(mut self, sender: impl Into<Option<Bech32Address>>) -> Self {
self.sender = sender.into();
self
}
pub fn with_metadata(mut self, metadata: impl Into<Option<Vec<u8>>>) -> Self {
self.metadata = metadata.into();
self
}
pub fn with_tag(mut self, tag: impl Into<Option<Vec<u8>>>) -> Self {
self.tag = tag.into();
self
}
pub fn try_with_issuer(mut self, issuer: impl ConvertTo<Bech32Address>) -> crate::wallet::Result<Self> {
self.issuer = Some(issuer.convert()?);
Ok(self)
}
pub fn with_issuer(mut self, issuer: impl Into<Option<Bech32Address>>) -> Self {
self.issuer = issuer.into();
self
}
pub fn with_immutable_metadata(mut self, immutable_metadata: impl Into<Option<Vec<u8>>>) -> Self {
self.immutable_metadata = immutable_metadata.into();
self
}
}
impl<S: 'static + SecretManage> Account<S>
where
crate::wallet::Error: From<S::Error>,
{
pub async fn mint_nfts<I: IntoIterator<Item = MintNftParams> + Send>(
&self,
params: I,
options: impl Into<Option<TransactionOptions>> + Send,
) -> crate::wallet::Result<Transaction>
where
I::IntoIter: Send,
{
let options = options.into();
let prepared_transaction = self.prepare_mint_nfts(params, options.clone()).await?;
self.sign_and_submit_transaction(prepared_transaction, options).await
}
pub async fn prepare_mint_nfts<I: IntoIterator<Item = MintNftParams> + Send>(
&self,
params: I,
options: impl Into<Option<TransactionOptions>> + Send,
) -> crate::wallet::Result<PreparedTransactionData>
where
I::IntoIter: Send,
{
log::debug!("[TRANSACTION] prepare_mint_nfts");
let rent_structure = self.client().get_rent_structure().await?;
let token_supply = self.client().get_token_supply().await?;
let account_addresses = self.addresses().await?;
let mut outputs = Vec::new();
for MintNftParams {
address,
sender,
metadata,
tag,
issuer,
immutable_metadata,
} in params
{
let address = match address {
Some(address) => {
self.client().bech32_hrp_matches(address.hrp()).await?;
address
}
None => {
account_addresses
.first()
.ok_or(WalletError::FailedToGetRemainder)?
.address
}
};
let mut nft_builder = NftOutputBuilder::new_with_minimum_storage_deposit(rent_structure, NftId::null())
.add_unlock_condition(AddressUnlockCondition::new(address));
if let Some(sender) = sender {
nft_builder = nft_builder.add_feature(SenderFeature::new(sender));
}
if let Some(metadata) = metadata {
nft_builder = nft_builder.add_feature(MetadataFeature::new(metadata)?);
}
if let Some(tag) = tag {
nft_builder = nft_builder.add_feature(TagFeature::new(tag)?);
}
if let Some(issuer) = issuer {
nft_builder = nft_builder.add_immutable_feature(IssuerFeature::new(issuer));
}
if let Some(immutable_metadata) = immutable_metadata {
nft_builder = nft_builder.add_immutable_feature(MetadataFeature::new(immutable_metadata)?);
}
outputs.push(nft_builder.finish_output(token_supply)?);
}
self.prepare_transaction(outputs, options).await
}
}