miden_lib/note/
well_known_note.rs

1use miden_objects::Word;
2use miden_objects::note::{Note, NoteScript};
3use miden_objects::utils::Deserializable;
4use miden_objects::utils::sync::LazyLock;
5use miden_objects::vm::Program;
6
7use crate::account::interface::{AccountComponentInterface, AccountInterface};
8use crate::account::wallets::BasicWallet;
9
10// WELL KNOWN NOTE SCRIPTS
11// ================================================================================================
12
13// Initialize the P2ID note script only once
14static P2ID_SCRIPT: LazyLock<NoteScript> = LazyLock::new(|| {
15    let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/P2ID.masb"));
16    let program = Program::read_from_bytes(bytes).expect("Shipped P2ID script is well-formed");
17    NoteScript::new(program)
18});
19
20// Initialize the P2IDE note script only once
21static P2IDE_SCRIPT: LazyLock<NoteScript> = LazyLock::new(|| {
22    let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/P2IDE.masb"));
23    let program = Program::read_from_bytes(bytes).expect("Shipped P2IDE script is well-formed");
24    NoteScript::new(program)
25});
26
27// Initialize the SWAP note script only once
28static SWAP_SCRIPT: LazyLock<NoteScript> = LazyLock::new(|| {
29    let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/SWAP.masb"));
30    let program = Program::read_from_bytes(bytes).expect("Shipped SWAP script is well-formed");
31    NoteScript::new(program)
32});
33
34/// Returns the P2ID (Pay-to-ID) note script.
35fn p2id() -> NoteScript {
36    P2ID_SCRIPT.clone()
37}
38
39/// Returns the P2ID (Pay-to-ID) note script root.
40fn p2id_root() -> Word {
41    P2ID_SCRIPT.root()
42}
43
44/// Returns the P2IDE (Pay-to-ID with optional reclaim & timelock) note script.
45fn p2ide() -> NoteScript {
46    P2IDE_SCRIPT.clone()
47}
48
49/// Returns the P2IDE (Pay-to-ID with optional reclaim & timelock) note script root.
50fn p2ide_root() -> Word {
51    P2IDE_SCRIPT.root()
52}
53
54/// Returns the SWAP (Swap note) note script.
55fn swap() -> NoteScript {
56    SWAP_SCRIPT.clone()
57}
58
59/// Returns the SWAP (Swap note) note script root.
60fn swap_root() -> Word {
61    SWAP_SCRIPT.root()
62}
63
64// WELL KNOWN NOTE
65// ================================================================================================
66
67/// The enum holding the types of basic well-known notes provided by the `miden-lib`.
68pub enum WellKnownNote {
69    P2ID,
70    P2IDE,
71    SWAP,
72}
73
74impl WellKnownNote {
75    // CONSTANTS
76    // --------------------------------------------------------------------------------------------
77
78    /// Expected number of inputs of the P2ID note.
79    const P2ID_NUM_INPUTS: usize = 2;
80
81    /// Expected number of inputs of the P2IDE note.
82    const P2IDE_NUM_INPUTS: usize = 4;
83
84    /// Expected number of inputs of the SWAP note.
85    const SWAP_NUM_INPUTS: usize = 10;
86
87    // CONSTRUCTOR
88    // --------------------------------------------------------------------------------------------
89
90    /// Returns a [WellKnownNote] instance based on the note script of the provided [Note]. Returns
91    /// `None` if the provided note is not a basic well-known note.
92    pub fn from_note(note: &Note) -> Option<Self> {
93        let note_script_root = note.script().root();
94
95        if note_script_root == p2id_root() {
96            return Some(Self::P2ID);
97        }
98        if note_script_root == p2ide_root() {
99            return Some(Self::P2IDE);
100        }
101        if note_script_root == swap_root() {
102            return Some(Self::SWAP);
103        }
104
105        None
106    }
107
108    // PUBLIC ACCESSORS
109    // --------------------------------------------------------------------------------------------
110
111    /// Returns the expected inputs number of the current note.
112    pub fn num_expected_inputs(&self) -> usize {
113        match self {
114            Self::P2ID => Self::P2ID_NUM_INPUTS,
115            Self::P2IDE => Self::P2IDE_NUM_INPUTS,
116            Self::SWAP => Self::SWAP_NUM_INPUTS,
117        }
118    }
119
120    /// Returns the note script of the current [WellKnownNote] instance.
121    pub fn script(&self) -> NoteScript {
122        match self {
123            Self::P2ID => p2id(),
124            Self::P2IDE => p2ide(),
125            Self::SWAP => swap(),
126        }
127    }
128
129    /// Returns the script root of the current [WellKnownNote] instance.
130    pub fn script_root(&self) -> Word {
131        match self {
132            Self::P2ID => p2id_root(),
133            Self::P2IDE => p2ide_root(),
134            Self::SWAP => swap_root(),
135        }
136    }
137
138    /// Returns a boolean value indicating whether this [WellKnownNote] is compatible with the
139    /// provided [AccountInterface].
140    pub fn is_compatible_with(&self, account_interface: &AccountInterface) -> bool {
141        if account_interface.components().contains(&AccountComponentInterface::BasicWallet) {
142            return true;
143        }
144
145        let interface_proc_digests = account_interface.get_procedure_digests();
146        match self {
147            Self::P2ID | &Self::P2IDE => {
148                // To consume P2ID and P2IDE notes, the `receive_asset` procedure must be present in
149                // the provided account interface.
150                interface_proc_digests.contains(&BasicWallet::receive_asset_digest())
151            },
152            Self::SWAP => {
153                // To consume SWAP note, the `receive_asset` and `move_asset_to_note` procedures
154                // must be present in the provided account interface.
155                interface_proc_digests.contains(&BasicWallet::receive_asset_digest())
156                    && interface_proc_digests.contains(&BasicWallet::move_asset_to_note_digest())
157            },
158        }
159    }
160}