miden_lib/note/
utils.rs

1use miden_objects::{
2    NoteError, Word,
3    account::AccountId,
4    asset::Asset,
5    note::{NoteExecutionMode, NoteInputs, NoteRecipient, NoteTag, NoteType},
6};
7
8use super::well_known_note::WellKnownNote;
9
10/// Creates a [NoteRecipient] for the P2ID note.
11///
12/// Notes created with this recipient will be P2ID notes consumable by the specified target
13/// account.
14pub fn build_p2id_recipient(
15    target: AccountId,
16    serial_num: Word,
17) -> Result<NoteRecipient, NoteError> {
18    let note_script = WellKnownNote::P2ID.script();
19    let note_inputs = NoteInputs::new(vec![target.suffix(), target.prefix().as_felt()])?;
20
21    Ok(NoteRecipient::new(serial_num, note_script, note_inputs))
22}
23
24/// Returns a note tag for a swap note with the specified parameters.
25///
26/// Use case ID for the returned tag is set to 0.
27///
28/// Tag payload is constructed by taking asset tags (8 bits of each faucet ID) and concatenating
29/// them together as offered_asset_tag + requested_asset tag.
30///
31/// Network execution hint for the returned tag is set to `Local`.
32pub fn build_swap_tag(
33    note_type: NoteType,
34    offered_asset: &Asset,
35    requested_asset: &Asset,
36) -> Result<NoteTag, NoteError> {
37    const SWAP_USE_CASE_ID: u16 = 0;
38
39    // Get bits 0..8 from the faucet IDs of both assets which will form the tag payload.
40    let offered_asset_id: u64 = offered_asset.faucet_id_prefix().into();
41    let offered_asset_tag = (offered_asset_id >> 56) as u8;
42
43    let requested_asset_id: u64 = requested_asset.faucet_id_prefix().into();
44    let requested_asset_tag = (requested_asset_id >> 56) as u8;
45
46    let payload = ((offered_asset_tag as u16) << 8) | (requested_asset_tag as u16);
47
48    let execution = NoteExecutionMode::Local;
49    match note_type {
50        NoteType::Public => NoteTag::for_public_use_case(SWAP_USE_CASE_ID, payload, execution),
51        _ => NoteTag::for_local_use_case(SWAP_USE_CASE_ID, payload),
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use miden_objects::{
58        self,
59        account::{AccountIdVersion, AccountStorageMode, AccountType},
60        asset::{FungibleAsset, NonFungibleAsset, NonFungibleAssetDetails},
61    };
62
63    use super::*;
64
65    #[test]
66    fn swap_tag() {
67        // Construct an ID that starts with 0xcdb1.
68        let mut fungible_faucet_id_bytes = [0; 15];
69        fungible_faucet_id_bytes[0] = 0xcd;
70        fungible_faucet_id_bytes[1] = 0xb1;
71
72        // Construct an ID that starts with 0xabec.
73        let mut non_fungible_faucet_id_bytes = [0; 15];
74        non_fungible_faucet_id_bytes[0] = 0xab;
75        non_fungible_faucet_id_bytes[1] = 0xec;
76
77        let offered_asset = Asset::Fungible(
78            FungibleAsset::new(
79                AccountId::dummy(
80                    fungible_faucet_id_bytes,
81                    AccountIdVersion::Version0,
82                    AccountType::FungibleFaucet,
83                    AccountStorageMode::Public,
84                ),
85                2500,
86            )
87            .unwrap(),
88        );
89
90        let requested_asset = Asset::NonFungible(
91            NonFungibleAsset::new(
92                &NonFungibleAssetDetails::new(
93                    AccountId::dummy(
94                        non_fungible_faucet_id_bytes,
95                        AccountIdVersion::Version0,
96                        AccountType::NonFungibleFaucet,
97                        AccountStorageMode::Public,
98                    )
99                    .prefix(),
100                    vec![0xaa, 0xbb, 0xcc, 0xdd],
101                )
102                .unwrap(),
103            )
104            .unwrap(),
105        );
106
107        // The fungible ID starts with 0xcdb1.
108        // The non fungible ID starts with 0xabec.
109        // The expected tag payload is thus 0xcdab.
110        let expected_tag_payload = 0xcdab;
111
112        let actual_tag =
113            build_swap_tag(NoteType::Public, &offered_asset, &requested_asset).unwrap();
114
115        // 0 is the SWAP use case ID.
116        let expected_tag =
117            NoteTag::for_public_use_case(0, expected_tag_payload, NoteExecutionMode::Local)
118                .unwrap();
119
120        assert_eq!(actual_tag, expected_tag);
121    }
122}