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, NoteInputs, NoteMetadata, NoteRecipient,
11        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);
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 P2IDE note - Pay-to-ID note with optional reclaim after a certain block height and
53/// optional timelock.
54///
55/// This script enables the transfer of assets from the `sender` account to the `target`
56/// account by specifying the target's account ID. It adds the optional possibility for the
57/// sender to reclaiming the assets if the note has not been consumed by the target within the
58/// specified timeframe and the optional possibility to add a timelock to the asset transfer.
59///
60/// The passed-in `rng` is used to generate a serial number for the note. The returned note's tag
61/// is set to the target's account ID.
62///
63/// # Errors
64/// Returns an error if deserialization or compilation of the `P2ID` script fails.
65pub fn create_p2ide_note<R: FeltRng>(
66    sender: AccountId,
67    target: AccountId,
68    assets: Vec<Asset>,
69    reclaim_height: Option<BlockNumber>,
70    timelock_height: Option<BlockNumber>,
71    note_type: NoteType,
72    aux: Felt,
73    rng: &mut R,
74) -> Result<Note, NoteError> {
75    let serial_num = rng.draw_word();
76    let recipient =
77        utils::build_p2ide_recipient(target, reclaim_height, timelock_height, serial_num)?;
78    let tag = NoteTag::from_account_id(target);
79
80    let execution_hint = match timelock_height {
81        Some(height) => NoteExecutionHint::after_block(height)?,
82        None => NoteExecutionHint::always(),
83    };
84
85    let metadata = NoteMetadata::new(sender, note_type, tag, execution_hint, aux)?;
86    let vault = NoteAssets::new(assets)?;
87
88    Ok(Note::new(vault, metadata, recipient))
89}
90
91/// Generates a SWAP note - swap of assets between two accounts - and returns the note as well as
92/// [NoteDetails] for the payback note.
93///
94/// This script enables a swap of 2 assets between the `sender` account and any other account that
95/// is willing to consume the note. The consumer will receive the `offered_asset` and will create a
96/// new P2ID note with `sender` as target, containing the `requested_asset`.
97///
98/// # Errors
99/// Returns an error if deserialization or compilation of the `SWAP` script fails.
100pub fn create_swap_note<R: FeltRng>(
101    sender: AccountId,
102    offered_asset: Asset,
103    requested_asset: Asset,
104    note_type: NoteType,
105    aux: Felt,
106    rng: &mut R,
107) -> Result<(Note, NoteDetails), NoteError> {
108    let note_script = WellKnownNote::SWAP.script();
109
110    let payback_serial_num = rng.draw_word();
111    let payback_recipient = utils::build_p2id_recipient(sender, payback_serial_num)?;
112
113    let payback_recipient_word: Word = payback_recipient.digest().into();
114    let requested_asset_word: Word = requested_asset.into();
115    let payback_tag = NoteTag::from_account_id(sender);
116
117    let inputs = NoteInputs::new(vec![
118        payback_recipient_word[0],
119        payback_recipient_word[1],
120        payback_recipient_word[2],
121        payback_recipient_word[3],
122        requested_asset_word[0],
123        requested_asset_word[1],
124        requested_asset_word[2],
125        requested_asset_word[3],
126        payback_tag.as_u32().into(),
127        NoteExecutionHint::always().into(),
128    ])?;
129
130    // build the tag for the SWAP use case
131    let tag = build_swap_tag(note_type, &offered_asset, &requested_asset)?;
132    let serial_num = rng.draw_word();
133
134    // build the outgoing note
135    let metadata = NoteMetadata::new(sender, note_type, tag, NoteExecutionHint::always(), aux)?;
136    let assets = NoteAssets::new(vec![offered_asset])?;
137    let recipient = NoteRecipient::new(serial_num, note_script, inputs);
138    let note = Note::new(assets, metadata, recipient);
139
140    // build the payback note details
141    let payback_assets = NoteAssets::new(vec![requested_asset])?;
142    let payback_note = NoteDetails::new(payback_assets, payback_recipient);
143
144    Ok((note, payback_note))
145}