/*
* Simple Storage Program for Liquid
*
* Only the owner of the storage can modify the value.
*
* ==== IMPORTANT ====
*
* Based on the following resources:
* https://github.com/ElementsProject/elements/blob/master/src/consensus/amount.h
* https://github.com/ElementsProject/rust-elements/blob/f6ffc7800df14b81c0f5ae1c94368a78b99612b9/src/blind.rs#L471
*
* The maximum allowed amount is 2,100,000,000,000,000
* (i.e., 21,000,000 × 10^8), which is approximately 51 bits.
*/
fn checksig(pk: Pubkey, sig: Signature) {
let msg: u256 = jet::sig_all_hash();
jet::bip_0340_verify((pk, msg), sig);
}
fn ensure_current_index_eq(expected_index: u32){
assert!(jet::eq_32(jet::current_index(), expected_index));
}
fn ensure_input_and_output_script_hash_eq(index: u32) {
assert!(jet::eq_256(unwrap(jet::input_script_hash(index)), unwrap(jet::output_script_hash(index))));
}
fn ensure_output_is_op_return(index: u32) {
match jet::output_null_datum(index, 0) {
Some(entry: Option<Either<(u2, u256), Either<u1, u4>>>) => (),
None => panic!(),
}
}
fn get_output_explicit_asset_amount(index: u32) -> (u256, u64) {
let pair: (Asset1, Amount1) = unwrap(jet::output_amount(index));
let (asset, amount): (Asset1, Amount1) = pair;
let asset_bits: u256 = unwrap_right::<(u1, u256)>(asset);
let amount: u64 = unwrap_right::<(u1, u256)>(amount);
(asset_bits, amount)
}
fn get_input_explicit_asset_amount(index: u32) -> (u256, u64) {
let pair: (Asset1, Amount1) = unwrap(jet::input_amount(index));
let (asset, amount): (Asset1, Amount1) = pair;
let asset_bits: u256 = unwrap_right::<(u1, u256)>(asset);
let amount: u64 = unwrap_right::<(u1, u256)>(amount);
(asset_bits, amount)
}
fn ensure_output_asset_with_amount_eq(index: u32, expected_bits: u256, expected_amount: u64) {
let (asset, amount): (u256, u64) = dbg!(get_output_explicit_asset_amount(index));
assert!(jet::eq_256(asset, expected_bits));
assert!(jet::eq_64(amount, expected_amount));
}
fn ensure_one_bit(bit: bool) { assert!(jet::eq_1(<bool>::into(bit), 1)); }
fn ensure_zero_bit(bit: bool) { assert!(jet::eq_1(<bool>::into(bit), 0)); }
fn increment_by(index: u32, amount: u32) -> u32 {
let (carry, result): (bool, u32) = jet::add_32(index, amount);
ensure_zero_bit(carry);
result
}
fn enforce_stage_checks(index: u32, new_value: u64) {
ensure_input_and_output_script_hash_eq(index);
let (asset_bits, old_value): (u256, u64) = get_input_explicit_asset_amount(index);
assert!(jet::eq_256(asset_bits, param::SLOT_ID));
ensure_output_asset_with_amount_eq(index, param::SLOT_ID, new_value);
match jet::lt_64(new_value, old_value) {
// burn
true => {
let burn_output_index: u32 = increment_by(index, 1);
let (carry, amount_to_burn): (bool, u64) = jet::subtract_64(old_value, new_value);
ensure_zero_bit(carry);
ensure_output_is_op_return(burn_output_index);
ensure_output_asset_with_amount_eq(burn_output_index, param::SLOT_ID, amount_to_burn);
},
// mint
false => {
let reissuance_output_index: u32 = increment_by(index, 1);
ensure_input_and_output_script_hash_eq(reissuance_output_index);
},
};
}
fn main() {
let index: u32 = 0;
enforce_stage_checks(index, witness::NEW_VALUE);
checksig(param::USER, witness::USER_SIGNATURE)
}