Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 112 additions & 41 deletions crates/contracts/simf/issuance_factory.simf
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ fn get_script_hash(index: u32, is_input_index: bool) -> u256 {
script_hash
}

fn get_asset_and_amount(index: u32, is_input_index: bool) -> (u256, u64) {
fn get_explicit_asset_and_amount(index: u32, is_input_index: bool) -> (u256, u64) {
let pair: (Asset1, Amount1) = match is_input_index {
true => unwrap(jet::input_amount(index)),
false => unwrap(jet::output_amount(index)),
Expand All @@ -20,6 +20,20 @@ fn get_asset_and_amount(index: u32, is_input_index: bool) -> (u256, u64) {
(asset_bits, amount)
}

fn get_current_explicit_asset() -> u256 {
let asset: Asset1 = jet::current_asset();
let asset_bits: u256 = unwrap_right::<(u1, u256)>(asset);

asset_bits
}

fn is_op_return(output_index: u32) -> bool {
match jet::output_null_datum(output_index, 0) {
Some(entry: Option<Either<(u2, u256), Either<u1, u4>>>) => true,
None => false,
}
}

// Check helpers

fn check_asset_amounts_eq(asset_amount_1: u64, asset_amount_2: u64) {
Expand All @@ -38,37 +52,61 @@ fn check_flags_eq(flag_1: bool, flag_2: bool) {
assert!(jet::eq_1(<bool>::into(flag_1), <bool>::into(flag_2)));
}

// Ensure functions

fn ensure_output_is_op_return(index: u32) {
check_flags_eq(is_op_return(index), true);
}

fn ensure_io_script_hashes_eq(input_index: u32, output_index: u32) {
let input_script_hash: u256 = get_script_hash(input_index, true);
let output_script_hash: u256 = get_script_hash(output_index, false);

check_script_hashes_eq(input_script_hash, output_script_hash);
}

fn ensure_non_zero_amount(amount: u64) {
assert!(jet::some_64(amount));
}

fn ensure_asset_with_amount(index: u32, is_input_index: bool, expected_asset_bits: u256, expected_amount: u64) {
let (asset_bits, amount): (u256, u64) = get_asset_and_amount(index, is_input_index);
fn ensure_output_asset_and_amount(output_index: u32, expected_asset_bits: u256, expected_amount: u64) {
let (asset_bits, amount): (u256, u64) = get_explicit_asset_and_amount(output_index, false);

check_assets_eq(asset_bits, expected_asset_bits);
check_asset_amounts_eq(amount, expected_amount);
}

fn ensure_input_and_output_eq(input_index: u32, output_index: u32) {
let (input_asset_bits, input_amount): (u256, u64) = get_asset_and_amount(input_index, true);
let (output_asset_bits, output_amount): (u256, u64) = get_asset_and_amount(output_index, false);
fn ensure_io_asset_eq(input_index: u32, output_index: u32, expected_asset_bits: u256) -> (u64, u64) {
let (input_asset_bits, input_amount): (u256, u64) = get_explicit_asset_and_amount(input_index, true);
let (output_asset_bits, output_amount): (u256, u64) = get_explicit_asset_and_amount(output_index, false);

check_assets_eq(input_asset_bits, input_asset_bits);
check_asset_amounts_eq(input_amount, output_amount);
check_assets_eq(input_asset_bits, expected_asset_bits);
check_assets_eq(input_asset_bits, output_asset_bits);

(input_amount, output_amount)
}

fn ensure_input_and_output_script_hashes_eq(input_index: u32, output_index: u32) {
let input_script_hash: u256 = get_script_hash(input_index, true);
let output_script_hash: u256 = get_script_hash(output_index, false);
fn ensure_io_asset_and_amount_eq(
input_index: u32,
output_index: u32,
expected_asset_bits: u256,
expected_amount: u64
) {
let (input_amount, output_amount): (u64, u64) = ensure_io_asset_eq(input_index, output_index, expected_asset_bits);

check_script_hashes_eq(input_script_hash, output_script_hash);
check_asset_amounts_eq(input_amount, expected_amount);
check_asset_amounts_eq(input_amount, output_amount);
}

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 ensure_input_asset_and_amount_burn(
input_index: u32,
output_index: u32,
expected_asset_bits: u256,
expected_asset_amount: u64
) {
ensure_io_asset_and_amount_eq(input_index, output_index, expected_asset_bits, expected_asset_amount);

ensure_output_is_op_return(output_index);
}

fn ensure_zero_bit(bit: bool) { assert!(jet::eq_1(<bool>::into(bit), 0)); }
Expand All @@ -78,10 +116,12 @@ fn ensure_zero_bit(bit: bool) { assert!(jet::eq_1(<bool>::into(bit), 0)); }
fn safe_add_32(first: u32, second: u32) -> u32 {
let (carry, result): (bool, u32) = jet::add_32(first, second);

check_flags_eq(carry, false);

result
}

// Main paths logic
// Main paths helpers

fn get_reissuance_flag(index: u8) -> bool {
let shifted: u64 = jet::right_shift_64(index, param::REISSUANCE_FLAGS);
Expand All @@ -95,7 +135,9 @@ fn verify_issuance(input_index: u32, output_index: u32, reissuance_flag: bool) {
let outpoint: Outpoint = unwrap(jet::input_prev_outpoint(input_index));
let issuance_entropy: u256 = jet::calculate_issuance_entropy(outpoint, contract_hash);

let explicit_reissuance_tokens_amount: u64 = unwrap_right::<(u1, u256)>(unwrap(unwrap(jet::issuance_token_amount(input_index))));
let explicit_reissuance_tokens_amount: u64 = unwrap_right::<(u1, u256)>(unwrap(unwrap(
jet::issuance_token_amount(input_index)
)));

match reissuance_flag {
// TODO: Add confidential reissuance tokens verification
Expand All @@ -112,7 +154,7 @@ fn verify_issuance(input_index: u32, output_index: u32, reissuance_flag: bool) {

let issuance_amount: u64 = unwrap_right::<(u1, u256)>(issuance_amount);

ensure_asset_with_amount(output_index, false, issuance_asset, issuance_amount);
ensure_output_asset_and_amount(output_index, issuance_asset, issuance_amount);
}

fn verify_issuance_step(acc: (), start_output_index: u32, i: u8) -> Either<(), ()> {
Expand All @@ -131,41 +173,70 @@ fn verify_issuance_step(acc: (), start_output_index: u32, i: u8) -> Either<(), (
}
}

fn issue_new_assets(output_index: u32, owner_sig: Signature) {
let current_index: u32 = jet::current_index();
// Assets issuance flow

fn get_asset_issuance_issuance_factory_indexes(start_input_index: u32, start_output_index: u32) -> (u32, u32) {
(safe_add_32(start_input_index, 1), safe_add_32(start_output_index, 1))
}

fn get_asset_issuance_start_issued_output_index(start_output_index: u32) -> u32 {
safe_add_32(start_output_index, 2)
}

assert!(jet::eq_32(current_index, 0));
jet::bip_0340_verify((param::FACTORY_OWNER_PUBKEY, jet::sig_all_hash()), owner_sig);
fn issue_new_assets(output_index: u32) {
let (auth_nft_input_index, auth_nft_output_index): (u32, u32) = (0, output_index);
let (
issuance_factory_input_index,
issuance_factory_output_index
): (u32, u32) = get_asset_issuance_issuance_factory_indexes(auth_nft_input_index, auth_nft_output_index);

ensure_input_and_output_script_hashes_eq(current_index, output_index);
assert!(jet::eq_32(issuance_factory_input_index, jet::current_index()));

let (carry, issued_outputs_start_index): (bool, u32) = jet::add_32(output_index, 1);
ensure_zero_bit(carry);
let current_asset_bits: u256 = get_current_explicit_asset();

ensure_io_asset_and_amount_eq(auth_nft_input_index, auth_nft_output_index, current_asset_bits, 1);
ensure_io_asset_and_amount_eq(issuance_factory_input_index, issuance_factory_output_index, current_asset_bits, 1);

ensure_io_script_hashes_eq(issuance_factory_input_index, issuance_factory_output_index);

let issued_outputs_start_index: u32 = get_asset_issuance_start_issued_output_index(auth_nft_output_index);

unwrap_left::<()>(for_while::<verify_issuance_step>((), issued_outputs_start_index));
}

fn remove_factory(output_index: u32, owner_sig: Signature) {
let current_index: u32 = jet::current_index();
// Factory removing flow

assert!(jet::eq_32(current_index, 0));
jet::bip_0340_verify((param::FACTORY_OWNER_PUBKEY, jet::sig_all_hash()), owner_sig);
fn get_removing_auth_nft_indexes(start_input_index: u32, start_output_index: u32) -> (u32, u32) {
(safe_add_32(start_input_index, 1), safe_add_32(start_output_index, 1))
}

ensure_output_is_op_return(output_index);
ensure_input_and_output_eq(current_index, output_index);
fn remove_factory(output_index: u32) {
let (issuance_factory_input_index, issuance_factory_output_index): (u32, u32) = (0, output_index);
let (
auth_nft_input_index,
auth_nft_output_index
): (u32, u32) = get_removing_auth_nft_indexes(issuance_factory_input_index, issuance_factory_output_index);

assert!(jet::eq_32(issuance_factory_input_index, jet::current_index()));

let current_asset_bits: u256 = get_current_explicit_asset();

ensure_input_asset_and_amount_burn(
issuance_factory_input_index,
issuance_factory_output_index,
current_asset_bits,
1
);
ensure_input_asset_and_amount_burn(auth_nft_input_index, auth_nft_output_index, current_asset_bits, 1);
}

fn main() {
match witness::PATH {
Left(params: (u32, Signature)) => {
let (output_index, owner_sig): (u32, Signature) = params;

issue_new_assets(output_index, owner_sig);
Left(output_index: u32) => {
issue_new_assets(output_index);
},
Right(params: (u32, Signature)) => {
let (output_index, owner_sig): (u32, Signature) = params;

remove_factory(output_index, owner_sig);
Right(output_index: u32) => {
remove_factory(output_index);
}
}
}
32 changes: 20 additions & 12 deletions crates/contracts/src/programs/issuance_factory/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::programs::issuance_factory::{
use crate::programs::program::{MetadataProgram, SimplexProgram};
use crate::utils::op_return_payload;

const CREATION_METADATA_OUTPUT_INDEX: usize = 1;
const CREATION_METADATA_OUTPUT_INDEX: usize = 2;

pub struct IssuanceFactory {
program: IssuanceFactoryProgram,
Expand Down Expand Up @@ -50,7 +50,6 @@ impl IssuanceFactory {
let issuance_factory_parameters = IssuanceFactoryParameters {
issuing_utxos_count: creation_metadata.issuing_utxos_count,
reissuance_flags: creation_metadata.reissuance_flags,
owner_pubkey: creation_metadata.owner_pubkey,
network: *provider.get_network(),
};

Expand All @@ -74,36 +73,39 @@ impl IssuanceFactory {
ft.add_output(PartialOutput::new_metadata(&op_return_data));
}

pub fn attach_assets_issuing(
pub fn attach_assets_issuance(
&self,
ft: &mut FinalTransaction,
program_utxo: UTXO,
program_issuance_input: IssuanceInput,
) -> IssuanceDetails {
let issuance_factory_amount = program_utxo.explicit_amount();
let issuance_factory_asset = program_utxo.explicit_asset();
assert!(
ft.n_inputs() > 0,
"Assets issuance cant't be first attachment in transaction"
);

let issuance_factory_output_index = ft.n_outputs() as u32;
let auth_nft_output_index = ft.n_outputs() as u32 - 1;

let issuance_factory_asset = program_utxo.explicit_asset();

let issuance_factory_witness_branch = IssuanceFactoryWitnessBranch::IssueAssets {
output_index: issuance_factory_output_index,
output_index: auth_nft_output_index,
};

let issuance_details = self.add_program_issuance_input_with_signature(
ft,
program_utxo,
program_issuance_input,
issuance_factory_witness_branch.build_witness(),
RequiredSignature::witness_with_path("PATH", &["Left", "1"]),
RequiredSignature::None,
);

self.add_program_output(ft, issuance_factory_asset, issuance_factory_amount);
self.add_program_output(ft, issuance_factory_asset, 1);

issuance_details
}

pub fn attach_factory_removing(&self, ft: &mut FinalTransaction, program_utxo: UTXO) {
let issuance_factory_amount = program_utxo.explicit_amount();
let issuance_factory_asset = program_utxo.explicit_asset();

let issuance_factory_output_index = ft.n_outputs() as u32;
Expand All @@ -116,12 +118,18 @@ impl IssuanceFactory {
ft,
program_utxo,
issuance_factory_witness_branch.build_witness(),
RequiredSignature::witness_with_path("PATH", &["Right", "1"]),
RequiredSignature::None,
);

ft.add_output(PartialOutput::new(
Script::new_op_return(b"burn"),
issuance_factory_amount,
1,
issuance_factory_asset,
));

ft.add_output(PartialOutput::new(
Script::new_op_return(b"burn"),
1,
issuance_factory_asset,
));
}
Expand Down
Loading
Loading