miden_lib/note/
mod.rs

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