use alloc::vec::Vec;
use miden_objects::{
accounts::AccountId,
assets::Asset,
crypto::rand::FeltRng,
notes::{
Note, NoteAssets, NoteDetails, NoteExecutionHint, NoteExecutionMode, NoteInputs,
NoteMetadata, NoteRecipient, NoteScript, NoteTag, NoteType,
},
utils::Deserializable,
vm::Program,
Felt, NoteError, Word,
};
pub mod utils;
pub fn create_p2id_note<R: FeltRng>(
sender: AccountId,
target: AccountId,
assets: Vec<Asset>,
note_type: NoteType,
aux: Felt,
rng: &mut R,
) -> Result<Note, NoteError> {
let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/P2ID.masb"));
let program =
Program::read_from_bytes(bytes).map_err(NoteError::NoteScriptDeserializationError)?;
let note_script = NoteScript::new(program);
let inputs = NoteInputs::new(vec![target.into()])?;
let tag = NoteTag::from_account_id(target, NoteExecutionMode::Local)?;
let serial_num = rng.draw_word();
let metadata = NoteMetadata::new(sender, note_type, tag, NoteExecutionHint::always(), aux)?;
let vault = NoteAssets::new(assets)?;
let recipient = NoteRecipient::new(serial_num, note_script, inputs);
Ok(Note::new(vault, metadata, recipient))
}
pub fn create_p2idr_note<R: FeltRng>(
sender: AccountId,
target: AccountId,
assets: Vec<Asset>,
note_type: NoteType,
aux: Felt,
recall_height: u32,
rng: &mut R,
) -> Result<Note, NoteError> {
let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/P2IDR.masb"));
let program =
Program::read_from_bytes(bytes).map_err(NoteError::NoteScriptDeserializationError)?;
let note_script = NoteScript::new(program);
let inputs = NoteInputs::new(vec![target.into(), recall_height.into()])?;
let tag = NoteTag::from_account_id(target, NoteExecutionMode::Local)?;
let serial_num = rng.draw_word();
let vault = NoteAssets::new(assets)?;
let metadata = NoteMetadata::new(sender, note_type, tag, NoteExecutionHint::always(), aux)?;
let recipient = NoteRecipient::new(serial_num, note_script, inputs);
Ok(Note::new(vault, metadata, recipient))
}
pub fn create_swap_note<R: FeltRng>(
sender: AccountId,
offered_asset: Asset,
requested_asset: Asset,
note_type: NoteType,
aux: Felt,
rng: &mut R,
) -> Result<(Note, NoteDetails), NoteError> {
let bytes = include_bytes!(concat!(env!("OUT_DIR"), "/assets/note_scripts/SWAP.masb"));
let program =
Program::read_from_bytes(bytes).map_err(NoteError::NoteScriptDeserializationError)?;
let note_script = NoteScript::new(program);
let payback_serial_num = rng.draw_word();
let payback_recipient = utils::build_p2id_recipient(sender, payback_serial_num)?;
let payback_recipient_word: Word = payback_recipient.digest().into();
let requested_asset_word: Word = requested_asset.into();
let payback_tag = NoteTag::from_account_id(sender, NoteExecutionMode::Local)?;
let inputs = NoteInputs::new(vec![
payback_recipient_word[0],
payback_recipient_word[1],
payback_recipient_word[2],
payback_recipient_word[3],
requested_asset_word[0],
requested_asset_word[1],
requested_asset_word[2],
requested_asset_word[3],
payback_tag.inner().into(),
NoteExecutionHint::always().into(),
])?;
let tag = build_swap_tag(note_type, &offered_asset, &requested_asset)?;
let serial_num = rng.draw_word();
let metadata = NoteMetadata::new(sender, note_type, tag, NoteExecutionHint::always(), aux)?;
let assets = NoteAssets::new(vec![offered_asset])?;
let recipient = NoteRecipient::new(serial_num, note_script, inputs);
let note = Note::new(assets, metadata, recipient);
let payback_assets = NoteAssets::new(vec![requested_asset])?;
let payback_note = NoteDetails::new(payback_assets, payback_recipient);
Ok((note, payback_note))
}
pub fn build_swap_tag(
note_type: NoteType,
offered_asset: &Asset,
requested_asset: &Asset,
) -> Result<NoteTag, NoteError> {
const SWAP_USE_CASE_ID: u16 = 0;
let offered_asset_id: u64 = offered_asset.faucet_id().into();
let offered_asset_tag = (offered_asset_id >> 52) as u8;
let requested_asset_id: u64 = requested_asset.faucet_id().into();
let requested_asset_tag = (requested_asset_id >> 52) as u8;
let payload = ((offered_asset_tag as u16) << 8) | (requested_asset_tag as u16);
let execution = NoteExecutionMode::Local;
match note_type {
NoteType::Public => NoteTag::for_public_use_case(SWAP_USE_CASE_ID, payload, execution),
_ => NoteTag::for_local_use_case(SWAP_USE_CASE_ID, payload),
}
}