use alloc::vec::Vec;
use miden_protocol::asset::Asset;
use miden_protocol::errors::NoteError;
use miden_protocol::note::{
Note,
NoteAssets,
NoteAttachment,
NoteMetadata,
NoteRecipient,
PartialNote,
};
use super::{RawOutputNote, Word};
use crate::errors::TransactionKernelError;
#[derive(Debug, Clone)]
pub struct OutputNoteBuilder {
metadata: NoteMetadata,
assets: Vec<Asset>,
recipient_digest: Word,
recipient: Option<NoteRecipient>,
}
impl OutputNoteBuilder {
pub fn from_recipient_digest(
metadata: NoteMetadata,
recipient_digest: Word,
) -> Result<Self, TransactionKernelError> {
if !metadata.is_private() {
return Err(TransactionKernelError::PublicNoteMissingDetails(
metadata,
recipient_digest,
));
}
Ok(Self {
metadata,
recipient_digest,
recipient: None,
assets: Vec::new(),
})
}
pub fn from_recipient(metadata: NoteMetadata, recipient: NoteRecipient) -> Self {
Self {
metadata,
recipient_digest: recipient.digest(),
recipient: Some(recipient),
assets: Vec::new(),
}
}
pub fn add_asset(&mut self, asset: Asset) -> Result<(), TransactionKernelError> {
if let Some(own_asset) = self.assets.iter_mut().find(|a| a.is_same(&asset)) {
match own_asset {
Asset::Fungible(f_own_asset) => {
let new_asset = f_own_asset
.add(asset.unwrap_fungible())
.map_err(NoteError::AddFungibleAssetBalanceError)
.map_err(TransactionKernelError::FailedToAddAssetToNote)?;
*own_asset = Asset::Fungible(new_asset);
},
Asset::NonFungible(nf_asset) => {
return Err(TransactionKernelError::FailedToAddAssetToNote(
NoteError::DuplicateNonFungibleAsset(*nf_asset),
));
},
}
} else {
self.assets.push(asset);
if self.assets.len() > NoteAssets::MAX_NUM_ASSETS {
return Err(TransactionKernelError::FailedToAddAssetToNote(
NoteError::TooManyAssets(self.assets.len()),
));
}
}
Ok(())
}
pub fn set_attachment(&mut self, attachment: NoteAttachment) {
self.metadata.set_attachment(attachment);
}
pub fn build(self) -> RawOutputNote {
let assets = NoteAssets::new(self.assets)
.expect("assets should be valid since add_asset validates them");
match self.recipient {
Some(recipient) => {
let note = Note::new(assets, self.metadata, recipient);
RawOutputNote::Full(note)
},
None => {
let note = PartialNote::new(self.metadata, self.recipient_digest, assets);
RawOutputNote::Partial(note)
},
}
}
}