smplx-std 0.0.5

A blazingly-fast, ux-first simplicity development framework
Documentation
/*
 * 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)
}