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