1use miden_objects::{
2 Felt, NoteError, Word,
3 account::AccountId,
4 asset::Asset,
5 block::BlockNumber,
6 note::{NoteExecutionMode, NoteInputs, NoteRecipient, NoteTag, NoteType},
7};
8
9use super::well_known_note::WellKnownNote;
10
11pub fn build_p2id_recipient(
16 target: AccountId,
17 serial_num: Word,
18) -> Result<NoteRecipient, NoteError> {
19 let note_script = WellKnownNote::P2ID.script();
20 let note_inputs = NoteInputs::new(vec![target.suffix(), target.prefix().as_felt()])?;
21
22 Ok(NoteRecipient::new(serial_num, note_script, note_inputs))
23}
24
25pub fn build_p2ide_recipient(
30 target: AccountId,
31 reclaim_block_height: Option<BlockNumber>,
32 timelock_block_height: Option<BlockNumber>,
33 serial_num: Word,
34) -> Result<NoteRecipient, NoteError> {
35 let note_script = WellKnownNote::P2IDE.script();
36
37 let reclaim_height_u32 = reclaim_block_height.map_or(0, |bn| bn.as_u32());
38 let timelock_height_u32 = timelock_block_height.map_or(0, |bn| bn.as_u32());
39
40 let note_inputs = NoteInputs::new(vec![
41 target.suffix(),
42 target.prefix().into(),
43 Felt::new(reclaim_height_u32 as u64),
44 Felt::new(timelock_height_u32 as u64),
45 ])?;
46
47 Ok(NoteRecipient::new(serial_num, note_script, note_inputs))
48}
49
50pub fn build_swap_tag(
59 note_type: NoteType,
60 offered_asset: &Asset,
61 requested_asset: &Asset,
62) -> Result<NoteTag, NoteError> {
63 const SWAP_USE_CASE_ID: u16 = 0;
64
65 let offered_asset_id: u64 = offered_asset.faucet_id_prefix().into();
67 let offered_asset_tag = (offered_asset_id >> 56) as u8;
68
69 let requested_asset_id: u64 = requested_asset.faucet_id_prefix().into();
70 let requested_asset_tag = (requested_asset_id >> 56) as u8;
71
72 let payload = ((offered_asset_tag as u16) << 8) | (requested_asset_tag as u16);
73
74 let execution = NoteExecutionMode::Local;
75 match note_type {
76 NoteType::Public => NoteTag::for_public_use_case(SWAP_USE_CASE_ID, payload, execution),
77 _ => NoteTag::for_local_use_case(SWAP_USE_CASE_ID, payload),
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use miden_objects::{
84 self,
85 account::{AccountIdVersion, AccountStorageMode, AccountType},
86 asset::{FungibleAsset, NonFungibleAsset, NonFungibleAssetDetails},
87 };
88
89 use super::*;
90
91 #[test]
92 fn swap_tag() {
93 let mut fungible_faucet_id_bytes = [0; 15];
95 fungible_faucet_id_bytes[0] = 0xcd;
96 fungible_faucet_id_bytes[1] = 0xb1;
97
98 let mut non_fungible_faucet_id_bytes = [0; 15];
100 non_fungible_faucet_id_bytes[0] = 0xab;
101 non_fungible_faucet_id_bytes[1] = 0xec;
102
103 let offered_asset = Asset::Fungible(
104 FungibleAsset::new(
105 AccountId::dummy(
106 fungible_faucet_id_bytes,
107 AccountIdVersion::Version0,
108 AccountType::FungibleFaucet,
109 AccountStorageMode::Public,
110 ),
111 2500,
112 )
113 .unwrap(),
114 );
115
116 let requested_asset = Asset::NonFungible(
117 NonFungibleAsset::new(
118 &NonFungibleAssetDetails::new(
119 AccountId::dummy(
120 non_fungible_faucet_id_bytes,
121 AccountIdVersion::Version0,
122 AccountType::NonFungibleFaucet,
123 AccountStorageMode::Public,
124 )
125 .prefix(),
126 vec![0xaa, 0xbb, 0xcc, 0xdd],
127 )
128 .unwrap(),
129 )
130 .unwrap(),
131 );
132
133 let expected_tag_payload = 0xcdab;
137
138 let actual_tag =
139 build_swap_tag(NoteType::Public, &offered_asset, &requested_asset).unwrap();
140
141 let expected_tag =
143 NoteTag::for_public_use_case(0, expected_tag_payload, NoteExecutionMode::Local)
144 .unwrap();
145
146 assert_eq!(actual_tag, expected_tag);
147 }
148}