miden_lib/note/
mod.rs

1use alloc::vec::Vec;
2
3use miden_objects::{
4    account::AccountId,
5    asset::Asset,
6    block::BlockNumber,
7    crypto::rand::FeltRng,
8    note::{
9        Note, NoteAssets, NoteDetails, NoteExecutionHint, NoteExecutionMode, NoteInputs,
10        NoteMetadata, NoteRecipient, NoteTag, NoteType,
11    },
12    Felt, NoteError, Word,
13};
14use utils::build_swap_tag;
15
16pub mod scripts;
17pub mod utils;
18
19// STANDARDIZED SCRIPTS
20// ================================================================================================
21
22/// Generates a P2ID note - pay to id note.
23///
24/// This script enables the transfer of assets from the `sender` account to the `target` account
25/// by specifying the target's account ID.
26///
27/// The passed-in `rng` is used to generate a serial number for the note. The returned note's tag
28/// is set to the target's account ID.
29///
30/// # Errors
31/// Returns an error if deserialization or compilation of the `P2ID` script fails.
32pub fn create_p2id_note<R: FeltRng>(
33    sender: AccountId,
34    target: AccountId,
35    assets: Vec<Asset>,
36    note_type: NoteType,
37    aux: Felt,
38    rng: &mut R,
39) -> Result<Note, NoteError> {
40    let serial_num = rng.draw_word();
41    let recipient = utils::build_p2id_recipient(target, serial_num)?;
42
43    let tag = NoteTag::from_account_id(target, NoteExecutionMode::Local)?;
44
45    let metadata = NoteMetadata::new(sender, note_type, tag, NoteExecutionHint::always(), aux)?;
46    let vault = NoteAssets::new(assets)?;
47
48    Ok(Note::new(vault, metadata, recipient))
49}
50
51/// Generates a P2IDR note - pay to id with recall after a certain block height.
52///
53/// This script enables the transfer of assets from the sender `sender` account to the `target`
54/// account by specifying the target's account ID. Additionally it adds the possibility for the
55/// sender to reclaiming the assets if the note has not been consumed by the target within the
56/// specified timeframe.
57///
58/// The passed-in `rng` is used to generate a serial number for the note. The returned note's tag
59/// is set to the target's account ID.
60///
61/// # Errors
62/// Returns an error if deserialization or compilation of the `P2IDR` script fails.
63pub fn create_p2idr_note<R: FeltRng>(
64    sender: AccountId,
65    target: AccountId,
66    assets: Vec<Asset>,
67    note_type: NoteType,
68    aux: Felt,
69    recall_height: BlockNumber,
70    rng: &mut R,
71) -> Result<Note, NoteError> {
72    let note_script = scripts::p2idr();
73
74    let inputs =
75        NoteInputs::new(vec![target.suffix(), target.prefix().as_felt(), recall_height.into()])?;
76    let tag = NoteTag::from_account_id(target, NoteExecutionMode::Local)?;
77    let serial_num = rng.draw_word();
78
79    let vault = NoteAssets::new(assets)?;
80    let metadata = NoteMetadata::new(sender, note_type, tag, NoteExecutionHint::always(), aux)?;
81    let recipient = NoteRecipient::new(serial_num, note_script, inputs);
82    Ok(Note::new(vault, metadata, recipient))
83}
84
85/// Generates a SWAP note - swap of assets between two accounts - and returns the note as well as
86/// [NoteDetails] for the payback note.
87///
88/// This script enables a swap of 2 assets between the `sender` account and any other account that
89/// is willing to consume the note. The consumer will receive the `offered_asset` and will create a
90/// new P2ID note with `sender` as target, containing the `requested_asset`.
91///
92/// # Errors
93/// Returns an error if deserialization or compilation of the `SWAP` script fails.
94pub fn create_swap_note<R: FeltRng>(
95    sender: AccountId,
96    offered_asset: Asset,
97    requested_asset: Asset,
98    note_type: NoteType,
99    aux: Felt,
100    rng: &mut R,
101) -> Result<(Note, NoteDetails), NoteError> {
102    let note_script = scripts::swap();
103
104    let payback_serial_num = rng.draw_word();
105    let payback_recipient = utils::build_p2id_recipient(sender, payback_serial_num)?;
106
107    let payback_recipient_word: Word = payback_recipient.digest().into();
108    let requested_asset_word: Word = requested_asset.into();
109    let payback_tag = NoteTag::from_account_id(sender, NoteExecutionMode::Local)?;
110
111    let inputs = NoteInputs::new(vec![
112        payback_recipient_word[0],
113        payback_recipient_word[1],
114        payback_recipient_word[2],
115        payback_recipient_word[3],
116        requested_asset_word[0],
117        requested_asset_word[1],
118        requested_asset_word[2],
119        requested_asset_word[3],
120        payback_tag.inner().into(),
121        NoteExecutionHint::always().into(),
122    ])?;
123
124    // build the tag for the SWAP use case
125    let tag = build_swap_tag(note_type, &offered_asset, &requested_asset)?;
126    let serial_num = rng.draw_word();
127
128    // build the outgoing note
129    let metadata = NoteMetadata::new(sender, note_type, tag, NoteExecutionHint::always(), aux)?;
130    let assets = NoteAssets::new(vec![offered_asset])?;
131    let recipient = NoteRecipient::new(serial_num, note_script, inputs);
132    let note = Note::new(assets, metadata, recipient);
133
134    // build the payback note details
135    let payback_assets = NoteAssets::new(vec![requested_asset])?;
136    let payback_note = NoteDetails::new(payback_assets, payback_recipient);
137
138    Ok((note, payback_note))
139}