-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathsend_nft.rs
114 lines (103 loc) · 3.82 KB
/
send_nft.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Copyright 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
use getset::Getters;
use serde::{Deserialize, Serialize};
use crate::{
client::{api::PreparedTransactionData, secret::SecretManage},
types::block::{
address::Bech32Address,
output::{unlock_condition::AddressUnlockCondition, NftId, NftOutputBuilder, Output},
},
utils::ConvertTo,
wallet::{
operations::transaction::{TransactionOptions, TransactionWithMetadata},
Wallet,
},
};
/// Params for `send_nft()`
#[derive(Debug, Clone, Serialize, Deserialize, Getters)]
#[serde(rename_all = "camelCase")]
pub struct SendNftParams {
/// Bech32 encoded address
#[getset(get = "pub")]
address: Bech32Address,
/// Nft id
#[getset(get = "pub")]
nft_id: NftId,
}
impl SendNftParams {
/// Creates a new instance of [`SendNftParams`]
pub fn new(
address: impl ConvertTo<Bech32Address>,
nft_id: impl ConvertTo<NftId>,
) -> Result<Self, crate::wallet::Error> {
Ok(Self {
address: address.convert()?,
nft_id: nft_id.convert()?,
})
}
}
impl<S: 'static + SecretManage> Wallet<S>
where
crate::wallet::Error: From<S::Error>,
crate::client::Error: From<S::Error>,
{
/// Sends an NFT to the provided address.
/// Calls [Wallet::prepare_transaction()](crate::wallet::Wallet::prepare_transaction) internally. The
/// options may define the remainder value strategy. Note that custom inputs will be replaced with the required
/// nft inputs and addresses need to be bech32-encoded.
/// ```ignore
/// let params = [SendNftParams::new(
/// "rms1qpszqzadsym6wpppd6z037dvlejmjuke7s24hm95s9fg9vpua7vluaw60xu",
/// "0xe645042a8a082957cb4bec4927936699ee8e56048834b090379da64213ce231b",
/// )?];
///
/// let transaction = account.send_nft(params, None).await?;
///
/// println!(
/// "Transaction sent: {}/transaction/{}",
/// std::env::var("EXPLORER_URL").unwrap(),
/// transaction.transaction_id
/// );
/// ```
pub async fn send_nft<I: IntoIterator<Item = SendNftParams> + Send>(
&self,
params: I,
options: impl Into<Option<TransactionOptions>> + Send,
) -> crate::wallet::Result<TransactionWithMetadata>
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
}
/// Prepares the transaction for [Wallet::send_nft()].
pub async fn prepare_send_nft<I: IntoIterator<Item = SendNftParams> + Send>(
&self,
params: I,
options: impl Into<Option<TransactionOptions>> + Send,
) -> crate::wallet::Result<PreparedTransactionData>
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?;
// Find nft output from the inputs
if let Some(nft_output_data) = self.ledger().await.unspent_nft_output(&nft_id) {
if let Output::Nft(nft_output) = &nft_output_data.output {
// Set the nft id and new address unlock condition
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(crate::wallet::Error::NftNotFoundInUnspentOutputs);
};
}
self.prepare_transaction(outputs, None, options).await
}
}