miden_lib/note/
well_known_note.rs

1use miden_objects::{
2    Digest,
3    assembly::{ProcedureName, QualifiedProcedureName},
4    note::{Note, NoteScript},
5    utils::{Deserializable, sync::LazyLock},
6    vm::Program,
7};
8
9use crate::account::{
10    components::basic_wallet_library,
11    interface::{AccountComponentInterface, AccountInterface},
12};
13
14// WELL KNOWN NOTE SCRIPTS
15// ================================================================================================
16
17// Initialize the P2ID note script only once
18static P2ID_SCRIPT: LazyLock<NoteScript> = LazyLock::new(|| {
19    let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/P2ID.masb"));
20    let program = Program::read_from_bytes(bytes).expect("Shipped P2ID script is well-formed");
21    NoteScript::new(program)
22});
23
24// Initialize the P2IDR note script only once
25static P2IDR_SCRIPT: LazyLock<NoteScript> = LazyLock::new(|| {
26    let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/P2IDR.masb"));
27    let program = Program::read_from_bytes(bytes).expect("Shipped P2IDR script is well-formed");
28    NoteScript::new(program)
29});
30
31// Initialize the SWAP note script only once
32static SWAP_SCRIPT: LazyLock<NoteScript> = LazyLock::new(|| {
33    let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/SWAP.masb"));
34    let program = Program::read_from_bytes(bytes).expect("Shipped SWAP script is well-formed");
35    NoteScript::new(program)
36});
37
38/// Returns the P2ID (Pay-to-ID) note script.
39fn p2id() -> NoteScript {
40    P2ID_SCRIPT.clone()
41}
42
43/// Returns the P2ID (Pay-to-ID) note script root.
44fn p2id_root() -> Digest {
45    P2ID_SCRIPT.root()
46}
47
48/// Returns the P2IDR (Pay-to-ID with recall) note script.
49fn p2idr() -> NoteScript {
50    P2IDR_SCRIPT.clone()
51}
52
53/// Returns the P2IDR (Pay-to-ID with recall) note script root.
54fn p2idr_root() -> Digest {
55    P2IDR_SCRIPT.root()
56}
57
58/// Returns the SWAP (Swap note) note script.
59fn swap() -> NoteScript {
60    SWAP_SCRIPT.clone()
61}
62
63/// Returns the SWAP (Swap note) note script root.
64fn swap_root() -> Digest {
65    SWAP_SCRIPT.root()
66}
67
68// WELL KNOWN NOTE
69// ================================================================================================
70
71/// The enum holding the types of basic well-known notes provided by the `miden-lib`.
72pub enum WellKnownNote {
73    P2ID,
74    P2IDR,
75    SWAP,
76}
77
78impl WellKnownNote {
79    /// Returns a [WellKnownNote] instance based on the note script of the provided [Note]. Returns
80    /// `None` if the provided note is not a basic well-known note.
81    pub fn from_note(note: &Note) -> Option<Self> {
82        let note_script_root = note.script().root();
83
84        if note_script_root == p2id_root() {
85            return Some(Self::P2ID);
86        }
87        if note_script_root == p2idr_root() {
88            return Some(Self::P2IDR);
89        }
90        if note_script_root == swap_root() {
91            return Some(Self::SWAP);
92        }
93
94        None
95    }
96
97    /// Returns the note script of the current [WellKnownNote] instance.
98    pub fn script(&self) -> NoteScript {
99        match self {
100            Self::P2ID => p2id(),
101            Self::P2IDR => p2idr(),
102            Self::SWAP => swap(),
103        }
104    }
105
106    /// Returns the script root of the current [WellKnownNote] instance.
107    pub fn script_root(&self) -> Digest {
108        match self {
109            Self::P2ID => p2id_root(),
110            Self::P2IDR => p2idr_root(),
111            Self::SWAP => swap_root(),
112        }
113    }
114
115    /// Returns a boolean value indicating whether this [WellKnownNote] is compatible with the
116    /// provided [AccountInterface].
117    pub fn is_compatible_with(&self, account_interface: &AccountInterface) -> bool {
118        if account_interface.components().contains(&AccountComponentInterface::BasicWallet) {
119            return true;
120        }
121
122        let interface_proc_digests = account_interface.get_procedure_digests();
123        match self {
124            Self::P2ID | &Self::P2IDR => {
125                // Get the hash of the "receive_asset" procedure and check that this procedure is
126                // presented in the provided account interfaces. P2ID and P2IDR notes requires only
127                // this procedure to be consumed by the account.
128                let receive_asset_proc_name = QualifiedProcedureName::new(
129                    Default::default(),
130                    ProcedureName::new("receive_asset").unwrap(),
131                );
132                let node_id = basic_wallet_library().get_export_node_id(&receive_asset_proc_name);
133                let receive_asset_digest = basic_wallet_library().mast_forest()[node_id].digest();
134
135                interface_proc_digests.contains(&receive_asset_digest)
136            },
137            Self::SWAP => {
138                // Make sure that all procedures from the basic wallet library are presented in the
139                // provided account interfaces. SWAP note requires the whole basic wallet interface
140                // to be consumed by the account.
141                basic_wallet_library()
142                    .mast_forest()
143                    .procedure_digests()
144                    .all(|proc_digest| interface_proc_digests.contains(&proc_digest))
145            },
146        }
147    }
148}