diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 581eb8ad..c0751bb8 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest env: SQLX_OFFLINE: true - SIMPLEX_COMMIT: 1945d11b47fff8838c3e99c210133519a9522324 + SIMPLEX_VERSION: 0.0.9 steps: - name: Checkout @@ -45,7 +45,7 @@ jobs: BASE_DIR="${XDG_CONFIG_HOME:-$HOME}" SIMPLEX_DIR="${SIMPLEX_DIR:-$BASE_DIR/.simplex}" SIMPLEX_BIN_DIR="$SIMPLEX_DIR/bin" - "$SIMPLEX_BIN_DIR/simplexup" --commit "$SIMPLEX_COMMIT" + "$SIMPLEX_BIN_DIR/simplexup" --install "$SIMPLEX_VERSION" echo "$SIMPLEX_BIN_DIR" >> "$GITHUB_PATH" "$SIMPLEX_BIN_DIR/simplex" --version @@ -53,6 +53,7 @@ jobs: shell: bash run: | cd crates/contracts + simplex install simplex build test -f src/artifacts/mod.rs diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f7c6db15..b8a55972 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,7 @@ env: SQLX_VERSION: 0.8.0 SQLX_FEATURES: "rustls,postgres" SQLX_FEATURES_KEY: "rustls-postgres" - SIMPLEX_COMMIT: 1945d11b47fff8838c3e99c210133519a9522324 + SIMPLEX_VERSION: 0.0.9 APP_USER: app APP_USER_PWD: secret APP_DB_NAME: lending-indexer @@ -84,7 +84,7 @@ jobs: BASE_DIR="${XDG_CONFIG_HOME:-$HOME}" SIMPLEX_DIR="${SIMPLEX_DIR:-$BASE_DIR/.simplex}" SIMPLEX_BIN_DIR="$SIMPLEX_DIR/bin" - "$SIMPLEX_BIN_DIR/simplexup" --commit "$SIMPLEX_COMMIT" + "$SIMPLEX_BIN_DIR/simplexup" --install "$SIMPLEX_VERSION" echo "$SIMPLEX_BIN_DIR" >> "$GITHUB_PATH" "$SIMPLEX_BIN_DIR/simplex" --version @@ -92,6 +92,7 @@ jobs: shell: bash run: | cd crates/contracts + simplex install simplex build test -f src/artifacts/mod.rs @@ -120,8 +121,31 @@ jobs: - name: Run simplex tests shell: bash run: | + set -euo pipefail cd crates/contracts - simplex test + + # `simplex test` wraps `cargo nextest` but currently swallows the + # child's non-zero exit code, so a failing test run still exits 0 + # and CI reports success. Until that is fixed upstream, guard the + # step two ways: + # 1. Capture the real exit code of `simplex test` via + # ${PIPESTATUS[0]} — `tee` would otherwise mask it, since a + # pipeline's exit status is the last command's. + # 2. Grep the captured log for nextest's own failure markers, in + # case the wrapper ever exits 0 while nextest reported FAILs + # (belt-and-braces; becomes redundant once the wrapper is + # fixed, but harmless). + # `set +e` around the pipeline is required so the script does not + # abort before we can read $rc. + + set +e + simplex test --test-threads 2 2>&1 | tee simplex.log + rc=${PIPESTATUS[0]} + set -e + if [ "$rc" -ne 0 ] || grep -Eq '^(error: test run failed|Exit Status: [1-9]|[[:space:]]*FAIL[[:space:]]*\[)' simplex.log; then + echo "::error::simplex test failed (rc=$rc)" + exit 1 + fi - name: Check that queries are fresh run: cargo sqlx prepare --workspace --check -- --all-targets diff --git a/crates/contracts/.gitignore b/crates/contracts/.gitignore index cbd40b05..74d515f3 100644 --- a/crates/contracts/.gitignore +++ b/crates/contracts/.gitignore @@ -1 +1,2 @@ -src/artifacts \ No newline at end of file +src/artifacts +deps/ \ No newline at end of file diff --git a/crates/contracts/Simplex.toml b/crates/contracts/Simplex.toml index 31ec9fb1..c0dd0456 100644 --- a/crates/contracts/Simplex.toml +++ b/crates/contracts/Simplex.toml @@ -5,17 +5,27 @@ # simf_files = ["*.simf"] # out_dir = "./src/artifacts" +[dependencies] +std = { git = "https://github.com/BlockstreamResearch/simplicityhl-std.git" } + # [regtest] # mnemonic = "exist carry drive collect lend cereal occur much tiger just involve mean" +# bitcoins = 10_000_000 +# rpc_port = 18443 +# esplora_port = 3000 +# rpc_user = "user" +# rpc_password = "password" # [test] # mnemonic = "exist carry drive collect lend cereal occur much tiger just involve mean" +# bitcoins = 10_000_000 +# verbosity = 0 # 0 - none, 1 - debug, 2 - trace # [test.esplora] # url = "" # network = "" - +# # [test.rpc] # url = "" # username = "" -# password = "" \ No newline at end of file +# password = "" diff --git a/crates/contracts/simf/asset_auth.simf b/crates/contracts/simf/asset_auth.simf index 6abb6f5a..72b4269f 100644 --- a/crates/contracts/simf/asset_auth.simf +++ b/crates/contracts/simf/asset_auth.simf @@ -1,39 +1,19 @@ -fn get_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)), - }; - 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_is_op_return(index: u32) { - match jet::output_null_datum(index, 0) { - Some(entry: Option>>) => (), - None => panic!(), - } -} +use std::lib::op_return::assert_output_is_op_return; -fn ensure_asset_and_amount_eq(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); - assert!(jet::eq_256(asset_bits, expected_asset_bits)); - assert!(jet::eq_64(amount, expected_amount)); -} +use crate::checks::{ensure_input_asset_and_amount, ensure_output_asset_and_amount}; fn auth_with_burn_check(input_asset_index: u32, output_asset_index: u32) { - ensure_asset_and_amount_eq(input_asset_index, true, param::ASSET_ID, param::ASSET_AMOUNT); - ensure_asset_and_amount_eq(output_asset_index, false, param::ASSET_ID, param::ASSET_AMOUNT); + ensure_input_asset_and_amount(input_asset_index, param::ASSET_ID, param::ASSET_AMOUNT); + ensure_output_asset_and_amount(output_asset_index, param::ASSET_ID, param::ASSET_AMOUNT); match param::WITH_ASSET_BURN { true => { - ensure_output_is_op_return(output_asset_index); + assert_output_is_op_return(output_asset_index); }, - false => {}, + false => {} } } fn main() { auth_with_burn_check(witness::INPUT_ASSET_INDEX, witness::OUTPUT_ASSET_INDEX); -} \ No newline at end of file +} diff --git a/crates/contracts/simf/asset_auth_vault.simf b/crates/contracts/simf/asset_auth_vault.simf index 8191f348..58f004b2 100644 --- a/crates/contracts/simf/asset_auth_vault.simf +++ b/crates/contracts/simf/asset_auth_vault.simf @@ -1,95 +1,44 @@ -// Helper getters - -fn get_script_hash(index: u32, is_input_index: bool) -> u256 { - let script_hash: u256 = match is_input_index { - true => unwrap(jet::input_script_hash(index)), - false => unwrap(jet::output_script_hash(index)), - }; - - script_hash -} - -fn get_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)), - }; - 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 is_op_return(output_index: u32) -> bool { - match jet::output_null_datum(output_index, 0) { - Some(entry: Option>>) => true, - None => false, - } -} - -// Math helpers - -fn safe_add_64(first: u64, second: u64) -> u64 { - let (carry, result): (bool, u64) = jet::add_64(first, second); - - result -} +use std::lib::binary::not; +use std::lib::op_return::is_output_op_return; +use std::lib::u64::safe_sub_64; + +use crate::helper::{ + get_explicit_asset_and_amount, + check_asset_amounts_eq, + check_assets_eq, + check_flags_eq +}; + +use crate::checks::{ + ensure_input_asset_and_amount_ge, + ensure_output_asset_and_amount_ge, + ensure_output_script_hash, + ensure_asset_transition_with_additional_amount +}; // Check helpers -fn check_asset_amounts_eq(asset_amount_1: u64, asset_amount_2: u64) { - assert!(jet::eq_64(asset_amount_1, asset_amount_2)); -} - -fn check_assets_eq(asset_bits_1: u256, asset_bits_2: u256) { - assert!(jet::eq_256(asset_bits_1, asset_bits_2)); -} - -fn check_script_hashes_eq(script_1: u256, script_2: u256) { - assert!(jet::eq_256(script_1, script_2)); -} - -fn check_flags_eq(flag_1: bool, flag_2: bool) { - assert!(jet::eq_1(::into(flag_1), ::into(flag_2))); -} - -fn ensure_output_is_op_return(index: u32) { - check_flags_eq(is_op_return(index), true); -} - -fn ensure_output_is_not_an_op_return(index: u32) { - check_flags_eq(is_op_return(index), false); -} - -fn ensure_asset_and_amount_ge(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); - assert!(jet::eq_256(asset_bits, expected_asset_bits)); - assert!(jet::le_64(expected_amount, amount)); -} - fn ensure_active_status(expected_status: bool) { - assert!(jet::eq_1(::into(expected_status), ::into(param::IS_ACTIVE))); -} - -fn ensure_output_script_hash(index: u32, expected_script_hash: u256) { - check_script_hashes_eq(get_script_hash(index, false), expected_script_hash); + check_flags_eq(expected_status, param::IS_ACTIVE); } fn ensure_vault_asset(index: u32, is_input_index: bool) -> u64 { - let (vault_asset_id, vault_amount): (u256, u64) = get_asset_and_amount(index, is_input_index); + let ( + vault_asset_id, + vault_amount + ): (u256, u64) = get_explicit_asset_and_amount(index, is_input_index); check_assets_eq(vault_asset_id, param::VAULT_ASSET_ID); vault_amount } -fn ensure_vault_amount_after_supplying(vault_output_index: u32, amount_to_supply: u64) { - let vault_amount: u64 = ensure_vault_asset(jet::current_index(), true); - let output_vault_amount: u64 = ensure_vault_asset(vault_output_index, false); - - let expected_output_vault_amount: u64 = safe_add_64(vault_amount, amount_to_supply); +fn ensure_input_vault_asset(input_index: u32) -> u64 { + ensure_vault_asset(input_index, true) +} - check_asset_amounts_eq(output_vault_amount, expected_output_vault_amount); +fn ensure_output_vault_asset(output_index: u32) -> u64 { + ensure_vault_asset(output_index, false) } // Auth logic @@ -101,16 +50,24 @@ fn auth_with_burn_check( expected_minimal_asset_amount: u64, with_asset_burn: bool ) { - ensure_asset_and_amount_ge(input_asset_index, true, expected_asset_id, expected_minimal_asset_amount); - ensure_asset_and_amount_ge(output_asset_index, false, expected_asset_id, expected_minimal_asset_amount); + ensure_input_asset_and_amount_ge( + input_asset_index, + expected_asset_id, + expected_minimal_asset_amount + ); + ensure_output_asset_and_amount_ge( + output_asset_index, + expected_asset_id, + expected_minimal_asset_amount + ); match with_asset_burn { true => { - ensure_output_is_op_return(output_asset_index); + assert!(is_output_op_return(output_asset_index)); }, false => { - ensure_output_is_not_an_op_return(output_asset_index) - }, + assert!(not(is_output_op_return(output_asset_index))); + } } } @@ -127,10 +84,15 @@ fn withdraw_all(input_keeper_index: u32, output_keeper_index: u32) { param::WITH_KEEPER_ASSET_BURN ); - let vault_amount: u64 = ensure_vault_asset(jet::current_index(), true); + let _: u64 = ensure_input_vault_asset(jet::current_index()); } -fn withdraw_part(input_keeper_index: u32, output_keeper_index: u32, vault_output_index: u32, amount_to_withdraw: u64) { +fn withdraw_part( + input_keeper_index: u32, + output_keeper_index: u32, + vault_output_index: u32, + amount_to_withdraw: u64 +) { ensure_active_status(true); auth_with_burn_check( @@ -143,17 +105,22 @@ fn withdraw_part(input_keeper_index: u32, output_keeper_index: u32, vault_output ensure_output_script_hash(vault_output_index, jet::current_script_hash()); - let vault_amount: u64 = ensure_vault_asset(jet::current_index(), true); - let output_vault_amount: u64 = ensure_vault_asset(vault_output_index, false); + let vault_amount: u64 = ensure_input_vault_asset(jet::current_index()); + let output_vault_amount: u64 = ensure_output_vault_asset(vault_output_index); assert!(jet::lt_64(amount_to_withdraw, vault_amount)); - let (carry, vault_change): (bool, u64) = jet::subtract_64(vault_amount, amount_to_withdraw); + let vault_change: u64 = safe_sub_64(vault_amount, amount_to_withdraw); check_asset_amounts_eq(output_vault_amount, vault_change); } -fn supply(input_supplier_index: u32, output_supplier_index: u32, vault_output_index: u32, amount_to_supply: u64) { +fn supply( + input_supplier_index: u32, + output_supplier_index: u32, + vault_output_index: u32, + amount_to_supply: u64 +) { ensure_active_status(true); auth_with_burn_check( @@ -166,7 +133,12 @@ fn supply(input_supplier_index: u32, output_supplier_index: u32, vault_output_in ensure_output_script_hash(vault_output_index, jet::current_script_hash()); - ensure_vault_amount_after_supplying(vault_output_index, amount_to_supply); + ensure_asset_transition_with_additional_amount( + jet::current_index(), + vault_output_index, + param::VAULT_ASSET_ID, + amount_to_supply + ); } // TODO: Add goal logic to finalization flow @@ -188,7 +160,12 @@ fn final_supply( ensure_output_script_hash(finalized_vault_output_index, param::FINALIZED_VAULT_COV_HASH); - ensure_vault_amount_after_supplying(finalized_vault_output_index, amount_to_supply); + ensure_asset_transition_with_additional_amount( + jet::current_index(), + finalized_vault_output_index, + param::VAULT_ASSET_ID, + amount_to_supply + ); } fn main() { @@ -205,11 +182,16 @@ fn main() { input_keeper_index, output_keeper_index, vault_output_index, - amount_to_withdraw, + amount_to_withdraw ): (u32, u32, u32, u64) = withdraw_part_params; - withdraw_part(input_keeper_index, output_keeper_index, vault_output_index, amount_to_withdraw); - }, + withdraw_part( + input_keeper_index, + output_keeper_index, + vault_output_index, + amount_to_withdraw + ); + } } }, Right(supply_params: Either<(u32, u32, u32, u64), (u32, u32, u32, u64)>) => { @@ -219,17 +201,22 @@ fn main() { input_supplier_index, output_supplier_index, vault_output_index, - amount_to_supply, + amount_to_supply ): (u32, u32, u32, u64) = supply_params; - supply(input_supplier_index, output_supplier_index, vault_output_index, amount_to_supply); + supply( + input_supplier_index, + output_supplier_index, + vault_output_index, + amount_to_supply + ); }, Right(final_supply_params: (u32, u32, u32, u64)) => { let ( input_supplier_index, output_supplier_index, finalized_vault_output_index, - amount_to_supply, + amount_to_supply ): (u32, u32, u32, u64) = final_supply_params; final_supply( @@ -240,6 +227,6 @@ fn main() { ); } } - }, + } } -} \ No newline at end of file +} diff --git a/crates/contracts/simf/checks.simf b/crates/contracts/simf/checks.simf new file mode 100644 index 00000000..96d825f4 --- /dev/null +++ b/crates/contracts/simf/checks.simf @@ -0,0 +1,161 @@ +use std::lib::op_return::assert_output_is_op_return; +use std::lib::u64::{ge_64, safe_add_64}; + +use crate::helper::{ + get_input_explicit_asset_and_amount, + get_output_explicit_asset_and_amount, + get_input_script_hash, + get_output_script_hash, + check_asset_amounts_eq, + check_assets_eq, + check_script_hashes_eq +}; + +// Amount checks + +pub fn ensure_non_zero_amount(amount: u64) { + assert!(jet::some_64(amount)); +} + +// Script hash checks + +pub fn ensure_input_script_hash( + input_index: u32, + expected_script_hash: u256 +) { + check_script_hashes_eq(get_input_script_hash(input_index), expected_script_hash); +} + +pub fn ensure_output_script_hash(output_index: u32, expected_script_hash: u256) { + check_script_hashes_eq(get_output_script_hash(output_index), expected_script_hash); +} + +pub fn ensure_io_script_hashes_eq(input_index: u32, output_index: u32) { + check_script_hashes_eq( + get_input_script_hash(input_index), + get_output_script_hash(output_index) + ); +} + +pub fn ensure_script_hash_transition( + input_index: u32, + output_index: u32, + expected_input_script_hash: u256, + expected_output_script_hash: u256 +) { + ensure_input_script_hash(input_index, expected_input_script_hash); + ensure_output_script_hash(output_index, expected_output_script_hash); +} + +// Asset and amount checks + +pub fn ensure_input_asset_and_amount( + input_index: u32, + expected_asset_bits: u256, + expected_amount: u64 +) { + let (asset_bits, amount): (u256, u64) = get_input_explicit_asset_and_amount(input_index); + + check_assets_eq(asset_bits, expected_asset_bits); + check_asset_amounts_eq(amount, expected_amount); +} + +pub fn ensure_output_asset_and_amount( + output_index: u32, + expected_asset_bits: u256, + expected_amount: u64 +) { + let (asset_bits, amount): (u256, u64) = get_output_explicit_asset_and_amount(output_index); + + check_assets_eq(asset_bits, expected_asset_bits); + check_asset_amounts_eq(amount, expected_amount); +} + +pub fn ensure_input_asset_and_amount_ge( + input_index: u32, + expected_asset_bits: u256, + minimal_amount: u64 +) { + let (asset_bits, amount): (u256, u64) = get_input_explicit_asset_and_amount(input_index); + + check_assets_eq(asset_bits, expected_asset_bits); + assert!(ge_64(amount, minimal_amount)); +} + +pub fn ensure_output_asset_and_amount_ge( + output_index: u32, + expected_asset_bits: u256, + minimal_amount: u64 +) { + let (asset_bits, amount): (u256, u64) = get_output_explicit_asset_and_amount(output_index); + + check_assets_eq(asset_bits, expected_asset_bits); + assert!(ge_64(amount, minimal_amount)); +} + +pub 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_input_explicit_asset_and_amount(input_index); + let ( + output_asset_bits, + output_amount + ): (u256, u64) = get_output_explicit_asset_and_amount(output_index); + + check_assets_eq(input_asset_bits, expected_asset_bits); + check_assets_eq(input_asset_bits, output_asset_bits); + + (input_amount, output_amount) +} + +pub 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_asset_amounts_eq(input_amount, expected_amount); + check_asset_amounts_eq(input_amount, output_amount); +} + +pub 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 + ); + + assert_output_is_op_return(output_index); +} + +pub fn ensure_asset_transition_with_additional_amount( + input_index: u32, + output_index: u32, + expected_asset_bits: u256, + additional_amount: u64 +) { + let ( + input_amount, + output_amount + ): (u64, u64) = ensure_io_asset_eq(input_index, output_index, expected_asset_bits); + + let new_asset_amount: u64 = safe_add_64(input_amount, additional_amount); + + check_asset_amounts_eq(output_amount, new_asset_amount); +} diff --git a/crates/contracts/simf/helper.simf b/crates/contracts/simf/helper.simf new file mode 100644 index 00000000..8bdfb0d7 --- /dev/null +++ b/crates/contracts/simf/helper.simf @@ -0,0 +1,75 @@ +use std::lib::asserts::{ + assert_eq_1, + assert_eq_64, + assert_eq_256 +}; + +// Helper getters + +pub 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)) + } + }; + + 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) +} + +pub fn get_input_explicit_asset_and_amount(input_index: u32) -> (u256, u64) { + get_explicit_asset_and_amount(input_index, true) +} + +pub fn get_output_explicit_asset_and_amount(output_index: u32) -> (u256, u64) { + get_explicit_asset_and_amount(output_index, false) +} + +pub fn get_script_hash(index: u32, is_input_index: bool) -> u256 { + match is_input_index { + true => { + unwrap(jet::input_script_hash(index)) + }, + false => { + unwrap(jet::output_script_hash(index)) + } + } +} + +pub fn get_input_script_hash(input_index: u32) -> u256 { + get_script_hash(input_index, true) +} + +pub fn get_output_script_hash(output_index: u32) -> u256 { + get_script_hash(output_index, false) +} + +// Check helpers + +pub fn check_asset_amounts_eq(asset_amount_1: u64, asset_amount_2: u64) { + assert_eq_64(asset_amount_1, asset_amount_2); +} + +pub fn check_assets_eq(asset_bits_1: u256, asset_bits_2: u256) { + assert_eq_256(asset_bits_1, asset_bits_2); +} + +pub fn check_script_hashes_eq(script_1: u256, script_2: u256) { + assert_eq_256(script_1, script_2); +} + +// TODO(std): use `assert_eq_bool` when it becomes available +pub fn check_flags_eq( + flag_1: bool, + flag_2: bool +) { + assert_eq_1(::into(flag_1), ::into(flag_2)); +} diff --git a/crates/contracts/simf/issuance_factory.simf b/crates/contracts/simf/issuance_factory.simf index 8a2fc922..815e8049 100644 --- a/crates/contracts/simf/issuance_factory.simf +++ b/crates/contracts/simf/issuance_factory.simf @@ -1,124 +1,20 @@ -// Helper getters +use std::lib::asserts::assert_eq_32; +use std::lib::u32::safe_add_32; -fn get_script_hash(index: u32, is_input_index: bool) -> u256 { - let script_hash: u256 = match is_input_index { - true => unwrap(jet::input_script_hash(index)), - false => unwrap(jet::output_script_hash(index)), - }; +use crate::helper::check_asset_amounts_eq; - script_hash -} +use crate::checks::{ + ensure_non_zero_amount, + ensure_io_script_hashes_eq, + ensure_output_asset_and_amount, + ensure_io_asset_and_amount_eq, + ensure_input_asset_and_amount_burn +}; -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)), - }; - 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) -} +// Helper getters 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>>) => true, - None => false, - } -} - -// Check helpers - -fn check_asset_amounts_eq(asset_amount_1: u64, asset_amount_2: u64) { - assert!(jet::eq_64(asset_amount_1, asset_amount_2)); -} - -fn check_assets_eq(asset_bits_1: u256, asset_bits_2: u256) { - assert!(jet::eq_256(asset_bits_1, asset_bits_2)); -} - -fn check_script_hashes_eq(script_1: u256, script_2: u256) { - assert!(jet::eq_256(script_1, script_2)); -} - -fn check_flags_eq(flag_1: bool, flag_2: bool) { - assert!(jet::eq_1(::into(flag_1), ::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_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_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, expected_asset_bits); - check_assets_eq(input_asset_bits, output_asset_bits); - - (input_amount, output_amount) -} - -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_asset_amounts_eq(input_amount, expected_amount); - check_asset_amounts_eq(input_amount, output_amount); -} - -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(::into(bit), 0)); } - -// Math helpers - -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 + unwrap_right::<(u1, u256)>(jet::current_asset()) } // Main paths helpers @@ -159,7 +55,9 @@ fn verify_issuance(input_index: u32, output_index: u32, reissuance_flag: bool) { fn verify_issuance_step(acc: (), start_output_index: u32, i: u8) -> Either<(), ()> { match jet::le_8(param::ISSUING_UTXOS_COUNT, i) { - true => Left(()), + true => { + Left(()) + }, false => { let step_index: u32 = <(u16, u16)>::into((0, <(u8, u8)>::into((0, i)))); @@ -175,7 +73,10 @@ fn verify_issuance_step(acc: (), start_output_index: u32, i: u8) -> Either<(), ( // Assets issuance flow -fn get_asset_issuance_issuance_factory_indexes(start_input_index: u32, start_output_index: u32) -> (u32, u32) { +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)) } @@ -188,36 +89,60 @@ fn issue_new_assets(output_index: u32) { 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); + ): (u32, u32) = get_asset_issuance_issuance_factory_indexes( + auth_nft_input_index, + auth_nft_output_index + ); - assert!(jet::eq_32(issuance_factory_input_index, jet::current_index())); + assert_eq_32(issuance_factory_input_index, jet::current_index()); 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_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); + let issued_outputs_start_index: u32 = get_asset_issuance_start_issued_output_index( + auth_nft_output_index + ); unwrap_left::<()>(for_while::((), issued_outputs_start_index)); } // Factory removing flow -fn get_removing_auth_nft_indexes(start_input_index: u32, start_output_index: u32) -> (u32, u32) { +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)) } fn remove_factory(output_index: u32) { - let (issuance_factory_input_index, issuance_factory_output_index): (u32, u32) = (0, output_index); + 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); + ): (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())); + assert_eq_32(issuance_factory_input_index, jet::current_index()); let current_asset_bits: u256 = get_current_explicit_asset(); @@ -227,7 +152,12 @@ fn remove_factory(output_index: u32) { current_asset_bits, 1 ); - ensure_input_asset_and_amount_burn(auth_nft_input_index, auth_nft_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() { @@ -239,4 +169,4 @@ fn main() { remove_factory(output_index); } } -} \ No newline at end of file +} diff --git a/crates/contracts/simf/lending.simf b/crates/contracts/simf/lending.simf index ea649371..bb357199 100644 --- a/crates/contracts/simf/lending.simf +++ b/crates/contracts/simf/lending.simf @@ -1,183 +1,42 @@ -// Helper getters - -fn get_script_hash(index: u32, is_input_index: bool) -> u256 { - let script_hash: u256 = match is_input_index { - true => unwrap(jet::input_script_hash(index)), - false => unwrap(jet::output_script_hash(index)), - }; - - script_hash -} - -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)), - }; - 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 is_op_return(output_index: u32) -> bool { - match jet::output_null_datum(output_index, 0) { - Some(entry: Option>>) => true, - None => false, - } -} - -// Check helpers - -fn check_asset_amounts_eq(asset_amount_1: u64, asset_amount_2: u64) { - assert!(jet::eq_64(asset_amount_1, asset_amount_2)); -} - -fn check_assets_eq(asset_bits_1: u256, asset_bits_2: u256) { - assert!(jet::eq_256(asset_bits_1, asset_bits_2)); -} - -fn check_script_hashes_eq(script_1: u256, script_2: u256) { - assert!(jet::eq_256(script_1, script_2)); -} - -fn check_flags_eq(flag_1: bool, flag_2: bool) { - assert!(jet::eq_1(::into(flag_1), ::into(flag_2))); -} +use std::lib::asserts::{assert_eq_32, assert_eq_64}; +use std::lib::u64::{safe_add_64, safe_div_64, safe_sub_64, u64_into_u256}; +use std::lib::u32::safe_add_32; + +use crate::helper::{get_input_explicit_asset_and_amount, check_asset_amounts_eq, check_assets_eq}; + +use crate::checks::{ + ensure_non_zero_amount, + ensure_input_script_hash, + ensure_output_script_hash, + ensure_script_hash_transition, + ensure_input_asset_and_amount, + ensure_output_asset_and_amount, + ensure_io_asset_and_amount_eq, + ensure_input_asset_and_amount_burn, + ensure_asset_transition_with_additional_amount +}; // Math helpers -fn safe_add_64(first: u64, second: u64) -> u64 { - let (carry, result): (bool, u64) = jet::add_64(first, second); - - check_flags_eq(carry, false); - - result -} - -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 -} - -fn safe_sub_64(first: u64, second: u64) -> u64 { - let (carry, result): (bool, u64) = jet::subtract_64(first, second); - - check_flags_eq(carry, false); - - result -} - fn min_64(first: u64, second: u64) -> u64 { match jet::lt_64(first, second) { - true => first, - false => second, + true => { + first + }, + false => { + second + } } } -// Ensure functions - -fn ensure_output_is_op_return(index: u32) { - check_flags_eq(is_op_return(index), true); -} - -fn ensure_input_script_hash(input_index: u32, expected_script_hash: u256) { - let script_hash: u256 = get_script_hash(input_index, true); - - check_script_hashes_eq(script_hash, expected_script_hash); -} - -fn ensure_output_script_hash(output_index: u32, expected_script_hash: u256) { - let script_hash: u256 = get_script_hash(output_index, false); - - check_script_hashes_eq(script_hash, expected_script_hash); -} - -fn ensure_script_hash_transition( - input_index: u32, - output_index: u32, - expected_input_script_hash: u256, - expected_output_script_hash: u256 -) { - ensure_input_script_hash(input_index, expected_input_script_hash); - ensure_output_script_hash(output_index, expected_output_script_hash); -} - -fn ensure_input_asset_and_amount(input_index: u32, expected_asset_bits: u256, expected_amount: u64) { - let (asset_bits, amount): (u256, u64) = get_explicit_asset_and_amount(input_index, true); - - check_assets_eq(asset_bits, expected_asset_bits); - check_asset_amounts_eq(amount, expected_amount); -} - -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_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, expected_asset_bits); - check_assets_eq(input_asset_bits, output_asset_bits); - - (input_amount, output_amount) -} - -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_asset_amounts_eq(input_amount, expected_amount); - check_asset_amounts_eq(input_amount, output_amount); -} - -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_asset_transition_with_additional_amount( - input_index: u32, - output_index: u32, - expected_asset_bits: u256, - additional_amount: u64 -) { - let (input_amount, output_amount): (u64, u64) = ensure_io_asset_eq(input_index, output_index, expected_asset_bits); - - let new_asset_amount: u64 = safe_add_64(input_amount, additional_amount); - - check_asset_amounts_eq(output_amount, new_asset_amount); -} - -// Math helpers - fn mul_div(x: u64, y: u64, denominator: u64) -> u64 { let product: u128 = jet::multiply_64(x, y); // TODO: Handle case when hi > 0 let (hi, lo): (u64, u64) = ::into(product); - check_asset_amounts_eq(hi, 0); - - let result: u64 = jet::divide_64(lo, denominator); + assert_eq_64(hi, 0); - result + safe_div_64(lo, denominator) } // Basis points math @@ -193,8 +52,7 @@ fn apply_basis_points(amount: u64, bps: u64) -> u64 { // Storage helpers fn get_is_active_slot_leaf(is_active: bool) -> u256 { - let is_active_num: u64 = jet::left_pad_low_1_64(::into(is_active)); - let is_active_num: u256 = <(u128, u128)>::into((0, <(u64, u64)>::into((0, is_active_num)))); + let is_active_num: u256 = u64_into_u256(jet::left_pad_low_1_64(::into(is_active))); let state_ctx1: Ctx8 = jet::tapdata_init(); let state_ctx2: Ctx8 = jet::sha_256_ctx_8_add_32(state_ctx1, is_active_num); @@ -203,7 +61,7 @@ fn get_is_active_slot_leaf(is_active: bool) -> u256 { } fn get_borrower_debt_slot_leaf(borrower_debt: u64) -> u256 { - let borrower_debt: u256 = <(u128, u128)>::into((0, <(u64, u64)>::into((0, borrower_debt)))); + let borrower_debt: u256 = u64_into_u256(borrower_debt); let state_ctx1: Ctx8 = jet::tapdata_init(); let state_ctx2: Ctx8 = jet::sha_256_ctx_8_add_32(state_ctx1, borrower_debt); @@ -260,11 +118,17 @@ fn split_repayment_by_fees(fee_left: u64, amount_to_repay: u64) -> (u64, u64) { } fn validate_collateral_input(input_index: u32, current_debt: u64) -> u64 { - let (asset_bits, current_collateral_amount): (u256, u64) = get_explicit_asset_and_amount(input_index, true); + let ( + asset_bits, + current_collateral_amount + ): (u256, u64) = get_input_explicit_asset_and_amount(input_index); let already_paid_debt: u64 = safe_sub_64(get_total_amount_to_repay(), current_debt); let already_unlocked_collateral: u64 = get_collateral_for_principal(already_paid_debt); - let total_collateral_amount: u64 = safe_add_64(current_collateral_amount, already_unlocked_collateral); + let total_collateral_amount: u64 = safe_add_64( + current_collateral_amount, + already_unlocked_collateral + ); check_assets_eq(asset_bits, param::COLLATERAL_ASSET_ID); check_asset_amounts_eq(total_collateral_amount, param::COLLATERAL_AMOUNT); @@ -280,7 +144,10 @@ fn validate_vaults( ) { let total_fee_amount: u64 = get_total_fee_amount(); - let already_repaid_amount: u64 = safe_sub_64(get_total_amount_to_repay(), current_borrower_debt); + let already_repaid_amount: u64 = safe_sub_64( + get_total_amount_to_repay(), + current_borrower_debt + ); let ( already_repaid_fee, @@ -289,24 +156,44 @@ fn validate_vaults( let fee_left: u64 = safe_sub_64(total_fee_amount, already_repaid_fee); - let (fee_repaid, protocol_fee_repaid): (u64, u64) = split_repayment_by_fees(fee_left, amount_to_repay); + let ( + fee_repaid, + protocol_fee_repaid + ): (u64, u64) = split_repayment_by_fees(fee_left, amount_to_repay); - let total_repaid_protocol_fee: u64 = safe_add_64(already_repaid_protocol_fee, protocol_fee_repaid); + let total_repaid_protocol_fee: u64 = safe_add_64( + already_repaid_protocol_fee, + protocol_fee_repaid + ); let additional_lender_vault_amount: u64 = safe_sub_64(amount_to_repay, protocol_fee_repaid); let total_protocol_fee: u64 = get_protocol_fee_amount(total_fee_amount); let lender_vault_output_hash: u256 = match jet::eq_64(current_borrower_debt, amount_to_repay) { - true => param::FINALIZED_LENDER_VAULT_COV_HASH, - false => param::LENDER_VAULT_COV_HASH, + true => { + param::FINALIZED_LENDER_VAULT_COV_HASH + }, + false => { + param::LENDER_VAULT_COV_HASH + } }; - let protocol_fee_vault_output_hash: u256 = match jet::eq_64(total_repaid_protocol_fee, total_protocol_fee) { - true => param::FINALIZED_PROTOCOL_FEE_VAULT_COV_HASH, - false => param::PROTOCOL_FEE_VAULT_COV_HASH, + let protocol_fee_vault_output_hash: u256 = match jet::eq_64( + total_repaid_protocol_fee, + total_protocol_fee + ) { + true => { + param::FINALIZED_PROTOCOL_FEE_VAULT_COV_HASH + }, + false => { + param::PROTOCOL_FEE_VAULT_COV_HASH + } }; let (lender_vault_input_index, lender_vault_output_index): (u32, u32) = lender_vault_indexes; - let (protocol_fee_vault_input_index, protocol_fee_vault_output_index): (u32, u32) = protocol_fee_vault_indexes; + let ( + protocol_fee_vault_input_index, + protocol_fee_vault_output_index + ): (u32, u32) = protocol_fee_vault_indexes; match jet::some_64(already_repaid_amount) { true => { @@ -338,7 +225,7 @@ fn validate_vaults( protocol_fee_vault_output_hash ); }, - false => {}, + false => {} }; }, false => { @@ -354,22 +241,34 @@ fn validate_vaults( param::PRINCIPAL_ASSET_ID, protocol_fee_repaid ); - ensure_output_script_hash(protocol_fee_vault_output_index, protocol_fee_vault_output_hash); - }, + ensure_output_script_hash( + protocol_fee_vault_output_index, + protocol_fee_vault_output_hash + ); + } }; } // Partial repayment flow -fn get_partial_repayment_offer_indexes(start_input_index: u32, start_output_index: u32) -> (u32, u32) { +fn get_partial_repayment_offer_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_partial_repayment_lender_vault_indexes(start_input_index: u32, start_output_index: u32) -> (u32, u32) { +fn get_partial_repayment_lender_vault_indexes( + start_input_index: u32, + start_output_index: u32 +) -> (u32, u32) { (safe_add_32(start_input_index, 2), safe_add_32(start_output_index, 2)) } -fn get_partial_repayment_protocol_fee_vault_indexes(start_input_index: u32, start_output_index: u32) -> (u32, u32) { +fn get_partial_repayment_protocol_fee_vault_indexes( + start_input_index: u32, + start_output_index: u32 +) -> (u32, u32) { (safe_add_32(start_input_index, 3), safe_add_32(start_output_index, 3)) } @@ -378,21 +277,28 @@ fn partial_repay_offer(current_debt: u64, amount_to_repay: u64) { let ( offer_input_index, offer_output_index - ): (u32, u32) = get_partial_repayment_offer_indexes(borrower_nft_input_index, borrower_nft_output_index); + ): (u32, u32) = get_partial_repayment_offer_indexes( + borrower_nft_input_index, + borrower_nft_output_index + ); - assert!(jet::eq_32(jet::current_index(), offer_input_index)); + assert_eq_32(jet::current_index(), offer_input_index); let current_script_hash: u256 = get_script_hash_for_storage(true, current_debt); ensure_input_script_hash(offer_input_index, current_script_hash); - assert!(jet::some_64(amount_to_repay)); + ensure_non_zero_amount(amount_to_repay); assert!(jet::lt_64(amount_to_repay, current_debt)); let current_collateral_amount: u64 = validate_collateral_input(offer_input_index, current_debt); let collateral_to_unlock: u64 = get_collateral_for_principal(amount_to_repay); let new_collateral_amount: u64 = safe_sub_64(current_collateral_amount, collateral_to_unlock); - ensure_output_asset_and_amount(offer_output_index, param::COLLATERAL_ASSET_ID, new_collateral_amount); + ensure_output_asset_and_amount( + offer_output_index, + param::COLLATERAL_ASSET_ID, + new_collateral_amount + ); let new_debt: u64 = safe_sub_64(current_debt, amount_to_repay); let new_offer_script_hash: u256 = get_script_hash_for_storage(true, new_debt); @@ -407,8 +313,14 @@ fn partial_repay_offer(current_debt: u64, amount_to_repay: u64) { ); validate_vaults( - get_partial_repayment_lender_vault_indexes(borrower_nft_input_index, borrower_nft_output_index), - get_partial_repayment_protocol_fee_vault_indexes(borrower_nft_input_index, borrower_nft_output_index), + get_partial_repayment_lender_vault_indexes( + borrower_nft_input_index, + borrower_nft_output_index + ), + get_partial_repayment_protocol_fee_vault_indexes( + borrower_nft_input_index, + borrower_nft_output_index + ), current_debt, amount_to_repay ); @@ -420,11 +332,17 @@ fn get_full_repayment_offer_input_index(start_input_index: u32) -> u32 { safe_add_32(start_input_index, 1) } -fn get_full_repayment_lender_vault_indexes(start_input_index: u32, start_output_index: u32) -> (u32, u32) { +fn get_full_repayment_lender_vault_indexes( + start_input_index: u32, + start_output_index: u32 +) -> (u32, u32) { (safe_add_32(start_input_index, 2), safe_add_32(start_output_index, 1)) } -fn get_full_repayment_protocol_fee_vault_indexes(start_input_index: u32, start_output_index: u32) -> (u32, u32) { +fn get_full_repayment_protocol_fee_vault_indexes( + start_input_index: u32, + start_output_index: u32 +) -> (u32, u32) { (safe_add_32(start_input_index, 3), safe_add_32(start_output_index, 2)) } @@ -432,7 +350,7 @@ fn full_repay_offer(current_debt: u64) { let (borrower_nft_input_index, borrower_nft_output_index): (u32, u32) = (0, 0); let offer_input_index: u32 = get_full_repayment_offer_input_index(borrower_nft_input_index); - assert!(jet::eq_32(jet::current_index(), offer_input_index)); + assert_eq_32(jet::current_index(), offer_input_index); let current_script_hash: u256 = get_script_hash_for_storage(true, current_debt); ensure_input_script_hash(offer_input_index, current_script_hash); @@ -447,8 +365,14 @@ fn full_repay_offer(current_debt: u64) { ); validate_vaults( - get_full_repayment_lender_vault_indexes(borrower_nft_input_index, borrower_nft_output_index), - get_full_repayment_protocol_fee_vault_indexes(borrower_nft_input_index, borrower_nft_output_index), + get_full_repayment_lender_vault_indexes( + borrower_nft_input_index, + borrower_nft_output_index + ), + get_full_repayment_protocol_fee_vault_indexes( + borrower_nft_input_index, + borrower_nft_output_index + ), current_debt, current_debt ); @@ -456,7 +380,10 @@ fn full_repay_offer(current_debt: u64) { // Liquidation flow -fn get_liquidation_lender_nft_indexes(start_input_index: u32, start_output_index: u32) -> (u32, u32) { +fn get_liquidation_lender_nft_indexes( + start_input_index: u32, + start_output_index: u32 +) -> (u32, u32) { (safe_add_32(start_input_index, 1), start_output_index) } @@ -467,7 +394,7 @@ fn liquidate_offer(current_debt: u64) { lender_nft_output_index ): (u32, u32) = get_liquidation_lender_nft_indexes(lending_input_index, lending_output_index); - assert!(jet::eq_32(lending_input_index, 0)); + assert!(jet::is_zero_32(lending_input_index)); let current_script_hash: u256 = get_script_hash_for_storage(true, current_debt); ensure_input_script_hash(lending_input_index, current_script_hash); @@ -476,16 +403,26 @@ fn liquidate_offer(current_debt: u64) { let _: u64 = validate_collateral_input(lending_input_index, current_debt); - ensure_input_asset_and_amount_burn(lender_nft_input_index, lender_nft_output_index, param::LENDER_NFT_ASSET_ID, 1); + ensure_input_asset_and_amount_burn( + lender_nft_input_index, + lender_nft_output_index, + param::LENDER_NFT_ASSET_ID, + 1 + ); } // Offer acceptance flow -fn get_acceptance_principal_output_index(start_output_index: u32) -> u32 { +fn get_acceptance_principal_output_index( + start_output_index: u32 +) -> u32 { safe_add_32(start_output_index, 1) } -fn get_acceptance_lender_nft_indexes(start_input_index: u32, start_output_index: u32) -> (u32, u32) { +fn get_acceptance_lender_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, 2)) } @@ -497,7 +434,7 @@ fn accept_offer() { ): (u32, u32) = get_acceptance_lender_nft_indexes(lending_input_index, lending_output_index); let principal_output_index: u32 = get_acceptance_principal_output_index(lending_output_index); - assert!(jet::eq_32(lending_input_index, 0)); + assert!(jet::is_zero_32(lending_input_index)); let total_amount_to_repay: u64 = get_total_amount_to_repay(); let current_script_hash: u256 = get_script_hash_for_storage(false, total_amount_to_repay); @@ -516,19 +453,34 @@ fn accept_offer() { active_offer_script_hash ); - ensure_io_asset_and_amount_eq(lender_nft_input_index, lender_nft_output_index, param::LENDER_NFT_ASSET_ID, 1); + ensure_io_asset_and_amount_eq( + lender_nft_input_index, + lender_nft_output_index, + param::LENDER_NFT_ASSET_ID, + 1 + ); - ensure_output_asset_and_amount(principal_output_index, param::PRINCIPAL_ASSET_ID, param::PRINCIPAL_AMOUNT); + ensure_output_asset_and_amount( + principal_output_index, + param::PRINCIPAL_ASSET_ID, + param::PRINCIPAL_AMOUNT + ); ensure_output_script_hash(principal_output_index, param::PRINCIPAL_OUTPUT_SCRIPT_HASH); } // Offer cancellation flow -fn get_cancellation_lender_nft_indexes(start_input_index: u32, start_output_index: u32) -> (u32, u32) { +fn get_cancellation_lender_nft_indexes( + start_input_index: u32, + start_output_index: u32 +) -> (u32, u32) { (safe_add_32(start_input_index, 1), start_output_index) } -fn get_cancellation_borrower_nft_indexes(start_input_index: u32, start_output_index: u32) -> (u32, u32) { +fn get_cancellation_borrower_nft_indexes( + start_input_index: u32, + start_output_index: u32 +) -> (u32, u32) { (safe_add_32(start_input_index, 2), safe_add_32(start_output_index, 1)) } @@ -543,12 +495,16 @@ fn cancel_offer() { borrower_nft_output_index ): (u32, u32) = get_cancellation_borrower_nft_indexes(lending_input_index, 0); - assert!(jet::eq_32(lending_input_index, 0)); + assert!(jet::is_zero_32(lending_input_index)); let current_script_hash: u256 = get_script_hash_for_storage(false, get_total_amount_to_repay()); ensure_input_script_hash(lending_input_index, current_script_hash); - ensure_input_asset_and_amount(lending_input_index, param::COLLATERAL_ASSET_ID, param::COLLATERAL_AMOUNT); + ensure_input_asset_and_amount( + lending_input_index, + param::COLLATERAL_ASSET_ID, + param::COLLATERAL_AMOUNT + ); ensure_input_asset_and_amount_burn( borrower_nft_input_index, @@ -573,7 +529,7 @@ fn main() { }, Right(params: ()) => { cancel_offer(); - }, + } } }, Right(active_offer_params: Either, u64>) => { @@ -581,19 +537,22 @@ fn main() { Left(repayment_params: Either<(u64, u64), u64>) => { match repayment_params { Left(partial_repayment_params: (u64, u64)) => { - let (current_debt, amount_to_repay): (u64, u64) = partial_repayment_params; + let ( + current_debt, + amount_to_repay + ): (u64, u64) = partial_repayment_params; partial_repay_offer(current_debt, amount_to_repay); }, Right(current_debt: u64) => { full_repay_offer(current_debt); - }, + } } }, Right(current_debt: u64) => { liquidate_offer(current_debt); } } - }, + } } -} \ No newline at end of file +} diff --git a/crates/contracts/simf/script_auth.simf b/crates/contracts/simf/script_auth.simf index 35566f99..c214f451 100644 --- a/crates/contracts/simf/script_auth.simf +++ b/crates/contracts/simf/script_auth.simf @@ -1,7 +1,9 @@ +use std::lib::asserts::assert_eq_256; + fn ensure_input_script_hash(input_script_index: u32, expected_script_hash: u256) { let actual_script_hash: u256 = unwrap(jet::input_script_hash(input_script_index)); - assert!(jet::eq_256(actual_script_hash, expected_script_hash)); + assert_eq_256(actual_script_hash, expected_script_hash); } fn script_auth_check(input_script_index: u32) { @@ -10,4 +12,4 @@ fn script_auth_check(input_script_index: u32) { fn main() { script_auth_check(witness::INPUT_SCRIPT_INDEX); -} \ No newline at end of file +}