use getset::Getters;
use serde::{Deserialize, Serialize};
use crate::{
client::{api::PreparedTransactionData, secret::SecretManage, ClientError},
types::block::{
address::Bech32Address,
output::{unlock_condition::AddressUnlockCondition, NftId, NftOutputBuilder, Output},
},
utils::ConvertTo,
wallet::{
operations::transaction::{TransactionOptions, TransactionWithMetadata},
Wallet, WalletError,
},
};
#[derive(Debug, Clone, Serialize, Deserialize, Getters)]
#[serde(rename_all = "camelCase")]
pub struct SendNftParams {
#[getset(get = "pub")]
address: Bech32Address,
#[getset(get = "pub")]
nft_id: NftId,
}
impl SendNftParams {
pub fn new(address: impl ConvertTo<Bech32Address>, nft_id: impl ConvertTo<NftId>) -> Result<Self, WalletError> {
Ok(Self {
address: address.convert()?,
nft_id: nft_id.convert()?,
})
}
}
impl<S: 'static + SecretManage> Wallet<S>
where
WalletError: From<S::Error>,
ClientError: From<S::Error>,
{
pub async fn send_nft<I: IntoIterator<Item = SendNftParams> + Send>(
&self,
params: I,
options: impl Into<Option<TransactionOptions>> + Send,
) -> Result<TransactionWithMetadata, WalletError>
where
I::IntoIter: Send,
{
let options = options.into();
let prepared_transaction = self.prepare_send_nft(params, options.clone()).await?;
self.sign_and_submit_transaction(prepared_transaction, options).await
}
pub async fn prepare_send_nft<I: IntoIterator<Item = SendNftParams> + Send>(
&self,
params: I,
options: impl Into<Option<TransactionOptions>> + Send,
) -> Result<PreparedTransactionData, WalletError>
where
I::IntoIter: Send,
{
log::debug!("[TRANSACTION] prepare_send_nft");
let mut outputs = Vec::new();
for SendNftParams { address, nft_id } in params {
self.client().bech32_hrp_matches(address.hrp()).await?;
if let Some(nft_output_data) = self.ledger().await.unspent_nft_output(&nft_id) {
if let Output::Nft(nft_output) = &nft_output_data.output {
let nft_builder = NftOutputBuilder::from(nft_output)
.with_nft_id(nft_id)
.with_unlock_conditions([AddressUnlockCondition::new(address)]);
outputs.push(nft_builder.finish_output()?);
}
} else {
return Err(WalletError::NftNotFoundInUnspentOutputs);
};
}
self.prepare_send_outputs(outputs, options).await
}
}