From 37ad50f58004736307322087dcc96e7dba713b52 Mon Sep 17 00:00:00 2001 From: phroi <90913182+phroi@users.noreply.github.com> Date: Sat, 26 Sep 2026 15:15:26 +0200 Subject: [PATCH 01/13] test: name the shannons-per-CKB constant CKB The suite wrote CKB amounts as `1_000 * SHANNONS`, which reads as 1,000 shannons although it means 1,000 CKB in shannons. The constant is now CKB, so the same amount reads `1_000 * CKB`. No value or behavior changes. --- scripts/tests/src/tests.rs | 2 +- scripts/tests/src/tests/fixtures.rs | 4 +- .../src/tests/ickb_logic/deposit_bounds.rs | 16 ++-- .../tests/ickb_logic/economic_precision.rs | 20 ++--- .../ickb_logic/mixed_flow_composition.rs | 14 ++-- .../ickb_logic/multi_quantity_receipts.rs | 6 +- .../src/tests/ickb_logic/phase2_headers.rs | 12 +-- .../ickb_logic/phase2_recipient_binding.rs | 12 +-- .../phase2_sibling_classification.rs | 18 ++--- .../ickb_logic/phase2_xudt_output_data.rs | 6 +- .../src/tests/ickb_logic/receipt_encoding.rs | 12 +-- .../src/tests/ickb_logic/receipt_matching.rs | 14 ++-- .../receiptless_deposit_blind_spot.rs | 22 ++--- .../tests/src/tests/ickb_logic/soft_cap.rs | 14 ++-- .../tests/ickb_logic/xudt_amount_limits.rs | 4 +- .../ickb_logic/xudt_owner_witness_fallback.rs | 2 +- .../tests/limit_order/crosswire_blockers.rs | 48 +++++------ .../tests/limit_order/crosswire_live_match.rs | 26 +++--- .../limit_order/crosswire_mint_creation.rs | 20 ++--- .../tests/limit_order/fake_match_lineage.rs | 18 ++--- .../tests/src/tests/limit_order/fulfilled.rs | 8 +- .../src/tests/limit_order/lock_only_shapes.rs | 14 ++-- .../src/tests/limit_order/master_admission.rs | 12 +-- .../tests/limit_order/match_progression.rs | 80 +++++++++---------- .../limit_order/mint_shape_validation.rs | 10 +-- .../src/tests/limit_order/phantom_lineage.rs | 34 ++++---- .../tests/src/tests/limit_order/poisoning.rs | 26 +++--- .../src/tests/limit_order/real_lineage.rs | 16 ++-- scripts/tests/src/tests/limit_order/remint.rs | 4 +- .../src/tests/limit_order/same_master.rs | 16 ++-- .../src/tests/owned_owner/dao_crosswiring.rs | 18 ++--- .../foreign_owner_lock_boundaries.rs | 8 +- .../tests/owned_owner/live_claim_rotation.rs | 4 +- .../owned_owner/mixed_asset_crosswiring.rs | 2 +- .../owned_owner/owner_distance_encoding.rs | 6 +- .../src/tests/owned_owner/pair_formation.rs | 6 +- .../src/tests/owned_owner/phase1_poisoning.rs | 8 +- .../owned_owner/positive_distance_claims.rs | 4 +- .../src/tests/owned_owner/script_misuse.rs | 16 ++-- .../owned_owner/weak_lock_output_rebinding.rs | 12 +-- .../withdrawal_amount_and_headers.rs | 20 ++--- scripts/tests/src/tests/replay_helpers.rs | 2 +- 42 files changed, 308 insertions(+), 308 deletions(-) diff --git a/scripts/tests/src/tests.rs b/scripts/tests/src/tests.rs index f7ba15f..f031d74 100644 --- a/scripts/tests/src/tests.rs +++ b/scripts/tests/src/tests.rs @@ -28,7 +28,7 @@ use signing::*; // Shared test constants and on-chain error codes. const MAX_CYCLES: u64 = 10_000_000; -const SHANNONS: u64 = 100_000_000; +const CKB: u64 = 100_000_000; const GENESIS_AR: u64 = 10_000_000_000_000_000; const SIGNATURE_SIZE: usize = 65; const SYNTHETIC_DEPOSIT_AR: u64 = GENESIS_AR; diff --git a/scripts/tests/src/tests/fixtures.rs b/scripts/tests/src/tests/fixtures.rs index 336650b..1f99a86 100644 --- a/scripts/tests/src/tests/fixtures.rs +++ b/scripts/tests/src/tests/fixtures.rs @@ -147,7 +147,7 @@ pub(super) fn owned_owner_script(context: &mut Context) -> Script { // Capacity and DAO accounting helpers. pub(super) fn capacity_for_data(data_len: u64) -> u64 { - 100 * SHANNONS + data_len + 100 * CKB + data_len } pub(super) fn deposit_capacity(lock: &Script, type_: &Script, data_len: usize, unused_capacity: u64) -> u64 { @@ -321,7 +321,7 @@ pub(super) fn build_real_limit_order_and_master( owner_lock: Script, helper_type: Script, ) -> (OutPoint, OutPoint) { - build_real_limit_order_and_master_with_capacity(context, owner_lock, helper_type, 1_500 * SHANNONS) + build_real_limit_order_and_master_with_capacity(context, owner_lock, helper_type, 1_500 * CKB) } pub(super) fn build_real_limit_order_and_master_with_capacity( diff --git a/scripts/tests/src/tests/ickb_logic/deposit_bounds.rs b/scripts/tests/src/tests/ickb_logic/deposit_bounds.rs index 93183d9..68f6093 100644 --- a/scripts/tests/src/tests/ickb_logic/deposit_bounds.rs +++ b/scripts/tests/src/tests/ickb_logic/deposit_bounds.rs @@ -8,13 +8,13 @@ fn deposit_below_minimum_is_rejected() { let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), ); - let amount = 999 * SHANNONS; + let amount = 999 * CKB; let deposit_output = CellOutput::new_builder() .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount).pack()) .lock(ickb_logic.clone()) @@ -45,13 +45,13 @@ fn deposit_at_minimum_is_accepted() { let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), ); - let amount = 1_000 * SHANNONS; + let amount = 1_000 * CKB; let deposit_output = CellOutput::new_builder() .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount).pack()) .lock(ickb_logic.clone()) @@ -83,13 +83,13 @@ fn deposit_above_maximum_is_rejected() { let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((1_100_000 * SHANNONS).pack()) + .capacity((1_100_000 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), ); - let amount = 1_000_001 * SHANNONS; + let amount = 1_000_001 * CKB; let deposit_output = CellOutput::new_builder() .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount).pack()) .lock(ickb_logic.clone()) @@ -120,13 +120,13 @@ fn deposit_at_maximum_is_accepted() { let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((1_100_000 * SHANNONS).pack()) + .capacity((1_100_000 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), ); - let amount = 1_000_000 * SHANNONS; + let amount = 1_000_000 * CKB; let deposit_output = CellOutput::new_builder() .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount).pack()) .lock(ickb_logic.clone()) diff --git a/scripts/tests/src/tests/ickb_logic/economic_precision.rs b/scripts/tests/src/tests/ickb_logic/economic_precision.rs index d421185..5a303c0 100644 --- a/scripts/tests/src/tests/ickb_logic/economic_precision.rs +++ b/scripts/tests/src/tests/ickb_logic/economic_precision.rs @@ -8,12 +8,12 @@ fn reported_rounding_claim_is_blocked_by_actual_shannon_precision() { let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); let ar = 11_509_953_685_250_771u64; - let amount_1152 = 1_152u64 * SHANNONS; - let amount_1151 = 1_151u64 * SHANNONS; + let amount_1152 = 1_152u64 * CKB; + let amount_1151 = 1_151u64 * CKB; let exact_ickb_1152 = u128::from(amount_1152) * u128::from(GENESIS_AR) / u128::from(ar); let exact_ickb_1151 = u128::from(amount_1151) * u128::from(GENESIS_AR) / u128::from(ar); - assert!(exact_ickb_1152 > 1_000 * SHANNONS as u128); + assert!(exact_ickb_1152 > 1_000 * CKB as u128); assert!(exact_ickb_1151 < exact_ickb_1152); let receipt_1152 = context.create_cell( @@ -35,7 +35,7 @@ fn reported_rounding_claim_is_blocked_by_actual_shannon_precision() { .type_(Some(xudt.clone()).pack()) .build(), ) - .output_data(udt_data(1_000 * SHANNONS as u128).pack()) + .output_data(udt_data(1_000 * CKB as u128).pack()) .header_dep(receipt_1152_header.hash()) .build(); let mint_claimed_1000_tx = context.complete_tx(mint_claimed_1000_tx); @@ -96,8 +96,8 @@ fn reported_rounding_withdrawal_claim_is_blocked_by_actual_shannon_precision() { let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); let ar = 11_509_953_685_250_771u64; - let amount_1152 = 1_152u64 * SHANNONS; - let amount_1151 = 1_151u64 * SHANNONS; + let amount_1152 = 1_152u64 * CKB; + let amount_1151 = 1_151u64 * CKB; let exact_ickb_1152 = u128::from(amount_1152) * u128::from(GENESIS_AR) / u128::from(ar); let header = gen_header(1554, ar, 35, 1000, 1000); @@ -118,7 +118,7 @@ fn reported_rounding_withdrawal_claim_is_blocked_by_actual_shannon_precision() { .lock(user_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), - udt_data(1_000 * SHANNONS as u128), + udt_data(1_000 * CKB as u128), ); let tx = TransactionBuilder::default() @@ -326,9 +326,9 @@ fn withdrawal_burn_matches_later_protocol_value_within_one_shannon_across_header burned_ickb }; - let older_deposit_burn = run_case(1_000 * SHANNONS, 1554, GENESIS_AR as u64); - let newer_deposit_burn = run_case(1_000 * SHANNONS, 1555, 11_000_000_000_000_000u64); - let oversized_deposit_burn = run_case(150_000 * SHANNONS, 1556, 11_000_000_000_000_000u64); + let older_deposit_burn = run_case(1_000 * CKB, 1554, GENESIS_AR as u64); + let newer_deposit_burn = run_case(1_000 * CKB, 1555, 11_000_000_000_000_000u64); + let oversized_deposit_burn = run_case(150_000 * CKB, 1556, 11_000_000_000_000_000u64); assert!( older_deposit_burn > newer_deposit_burn, diff --git a/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs b/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs index ad857ba..ac992dc 100644 --- a/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs +++ b/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs @@ -7,7 +7,7 @@ fn mixed_flow_cannot_overmint_by_combining_new_deposit_with_phase2_receipt() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -20,7 +20,7 @@ fn mixed_flow_cannot_overmint_by_combining_new_deposit_with_phase2_receipt() { let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -72,7 +72,7 @@ fn mixed_flow_cannot_overmint_when_deposit_phase1_phase2_and_withdrawal_share_on let xudt = xudt_script(&mut context, &ickb_logic); let dao = dao_script(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -104,7 +104,7 @@ fn mixed_flow_cannot_overmint_when_deposit_phase1_phase2_and_withdrawal_share_on ); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(user_lock.clone()) .build(), Bytes::new(), @@ -174,7 +174,7 @@ fn all_three_scripts_can_compose_in_one_live_state_transition() { let owned_owner = owned_owner_script(&mut context); let dao = dao_script(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let receipt_input = context.create_cell( @@ -203,7 +203,7 @@ fn all_three_scripts_can_compose_in_one_live_state_transition() { .input(CellInput::new_builder().previous_output(real_order_out_point).build()) .outputs(vec![ CellOutput::new_builder() - .capacity((1_400 * SHANNONS).pack()) + .capacity((1_400 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -220,7 +220,7 @@ fn all_three_scripts_can_compose_in_one_live_state_transition() { ]) .outputs_data( vec![ - order_data_match(100 * SHANNONS as u128, &real_master_out_point, (1, 1)), + order_data_match(100 * CKB as u128, &real_master_out_point, (1, 1)), withdrawal_request_data(1554), owner_distance_data(-1), ] diff --git a/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs b/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs index 211504a..4c25312 100644 --- a/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs +++ b/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs @@ -8,13 +8,13 @@ fn repeated_deposit_bucket_can_be_matched_by_one_multi_quantity_receipt() { let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((3_000 * SHANNONS).pack()) + .capacity((3_000 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), ); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let deposit_data = dao_deposit_data(); let deposit_output = || { CellOutput::new_builder() @@ -48,7 +48,7 @@ fn multi_quantity_receipt_can_be_converted_in_phase2() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) diff --git a/scripts/tests/src/tests/ickb_logic/phase2_headers.rs b/scripts/tests/src/tests/ickb_logic/phase2_headers.rs index 11ef71a..12ed90a 100644 --- a/scripts/tests/src/tests/ickb_logic/phase2_headers.rs +++ b/scripts/tests/src/tests/ickb_logic/phase2_headers.rs @@ -7,7 +7,7 @@ fn phase2_conversion_without_receipt_header_dep_is_rejected() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -42,8 +42,8 @@ fn phase2_conversion_with_two_receipts_from_distinct_headers_passes() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let first_amount = 1_000 * SHANNONS; - let second_amount = 1_200 * SHANNONS; + let first_amount = 1_000 * CKB; + let second_amount = 1_200 * CKB; let first_receipt = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -95,8 +95,8 @@ fn phase2_conversion_with_one_missing_receipt_header_dep_is_rejected() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let first_amount = 1_000 * SHANNONS; - let second_amount = 1_200 * SHANNONS; + let first_amount = 1_000 * CKB; + let second_amount = 1_200 * CKB; let first_receipt = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -144,7 +144,7 @@ fn phase2_conversion_with_zero_accumulated_rate_header_is_rejected() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) diff --git a/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs b/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs index 9fa67f0..164de1e 100644 --- a/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs +++ b/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs @@ -8,7 +8,7 @@ fn weak_lock_receipt_can_reassign_phase2_mint_recipient() { let attacker_lock = named_always_success_lock(&mut context, b"attacker"); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (receipt_out_point, receipt_header) = create_receipt_input( &mut context, weak_lock, @@ -49,7 +49,7 @@ fn sighash_lock_binds_phase2_mint_outputs_to_the_signed_transaction() { let attacker_lock = named_always_success_lock(&mut context, b"attacker"); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -103,8 +103,8 @@ fn mixed_sighash_and_weak_receipts_bind_all_phase2_outputs_once_signed() { let attacker_lock = named_always_success_lock(&mut context, b"attacker"); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let amount1 = 1_000 * SHANNONS; - let amount2 = 1_200 * SHANNONS; + let amount1 = 1_000 * CKB; + let amount2 = 1_200 * CKB; let receipt1 = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -173,8 +173,8 @@ fn two_weak_receipts_can_reassign_combined_phase2_mint_recipient() { let attacker_lock = named_always_success_lock(&mut context, b"attacker"); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let amount1 = 1_000 * SHANNONS; - let amount2 = 1_200 * SHANNONS; + let amount1 = 1_000 * CKB; + let amount2 = 1_200 * CKB; let receipt1 = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) diff --git a/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs b/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs index 3e8b5af..bfd01a9 100644 --- a/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs +++ b/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs @@ -8,7 +8,7 @@ fn unrelated_non_empty_args_output_lock_poisons_phase2() { let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); let poisoned_lock = data1_script(&mut context, "ickb_logic", Bytes::from(vec![1])); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -56,7 +56,7 @@ fn ickb_xudt_shaped_output_lock_poisons_phase2() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -104,7 +104,7 @@ fn dao_deposit_shaped_output_lock_poisons_phase2() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -154,7 +154,7 @@ fn foreign_xudt_output_lock_is_ignored() { let foreign_owner = named_always_success_lock(&mut context, b"foreign-owner"); let foreign_xudt = xudt_script(&mut context, &foreign_owner); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -205,7 +205,7 @@ fn foreign_xudt_type_output_is_ignored() { let foreign_owner = named_always_success_lock(&mut context, b"foreign-owner"); let foreign_xudt = xudt_script(&mut context, &foreign_owner); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -255,7 +255,7 @@ fn withdrawal_request_shaped_dao_output_lock_is_ignored() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -307,7 +307,7 @@ fn deposit_shaped_non_empty_args_output_poisons_phase2() { let xudt = xudt_script(&mut context, &ickb_logic); let dao = dao_script(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -319,7 +319,7 @@ fn deposit_shaped_non_empty_args_output_poisons_phase2() { let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let extra_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -358,7 +358,7 @@ fn non_empty_args_receipt_sibling_poisons_phase2() { let poisoned_receipt_type = data1_script(&mut context, "ickb_logic", Bytes::from(vec![1])); let xudt = xudt_script(&mut context, &ickb_logic); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) diff --git a/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs b/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs index 79e2cae..893d5e8 100644 --- a/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs +++ b/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs @@ -7,7 +7,7 @@ fn phase2_mint_accepts_xudt_data_with_trailing_bytes() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -46,7 +46,7 @@ fn phase2_mint_rejects_short_xudt_output_data() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -82,7 +82,7 @@ fn phase2_mint_rejects_zero_length_xudt_output_data() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) diff --git a/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs b/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs index cf3ca21..1cb327d 100644 --- a/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs +++ b/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs @@ -8,13 +8,13 @@ fn receipt_trailing_bytes_do_not_change_creation_accounting() { let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), ); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let deposit_data = dao_deposit_data(); let deposit_output = CellOutput::new_builder() .capacity(deposit_capacity(&ickb_logic, &dao, deposit_data.len(), deposit_amount).pack()) @@ -51,7 +51,7 @@ fn receipt_trailing_bytes_do_not_change_phase2_conversion() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (receipt_out_point, receipt_header) = create_receipt_input( &mut context, funding_lock.clone(), @@ -88,13 +88,13 @@ fn truncated_receipt_output_with_small_amount_is_rejected() { let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), ); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let deposit_data = dao_deposit_data(); let deposit_output = CellOutput::new_builder() .capacity(deposit_capacity(&ickb_logic, &dao, deposit_data.len(), deposit_amount).pack()) @@ -126,7 +126,7 @@ fn truncated_receipt_input_with_small_amount_is_rejected() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (receipt_out_point, receipt_header) = create_receipt_input( &mut context, funding_lock.clone(), diff --git a/scripts/tests/src/tests/ickb_logic/receipt_matching.rs b/scripts/tests/src/tests/ickb_logic/receipt_matching.rs index 2227d00..9dd81ab 100644 --- a/scripts/tests/src/tests/ickb_logic/receipt_matching.rs +++ b/scripts/tests/src/tests/ickb_logic/receipt_matching.rs @@ -8,13 +8,13 @@ fn zero_quantity_receipt_is_rejected() { let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), ); - let amount = 1_000 * SHANNONS; + let amount = 1_000 * CKB; let deposit_output = CellOutput::new_builder() .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount).pack()) .lock(ickb_logic.clone()) @@ -45,13 +45,13 @@ fn forged_receipt_quantity_without_enough_deposits_is_rejected() { let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), ); - let amount = 1_000 * SHANNONS; + let amount = 1_000 * CKB; let deposit_output = CellOutput::new_builder() .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount).pack()) .lock(ickb_logic.clone()) @@ -82,14 +82,14 @@ fn receipt_for_unmatched_deposit_amount_is_rejected() { let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), ); let deposit_output = CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, 8, 1_000 * SHANNONS).pack()) + .capacity(deposit_capacity(&ickb_logic, &dao, 8, 1_000 * CKB).pack()) .lock(ickb_logic.clone()) .type_(Some(dao).pack()) .build(); @@ -102,7 +102,7 @@ fn receipt_for_unmatched_deposit_amount_is_rejected() { let tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![deposit_output, receipt_output]) - .outputs_data(vec![dao_deposit_data(), receipt_data(1, 1_001 * SHANNONS)].pack()) + .outputs_data(vec![dao_deposit_data(), receipt_data(1, 1_001 * CKB)].pack()) .build(); let tx = context.complete_tx(tx); diff --git a/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs b/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs index a781120..2db6000 100644 --- a/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs +++ b/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs @@ -7,7 +7,7 @@ fn receiptless_dao_shaped_output_is_accepted_as_deposit() { let user_lock = always_success_lock(&mut context); let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_500 * SHANNONS; + let deposit_amount = 1_500 * CKB; let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, deposit_amount); let funding_input = context.create_cell( CellOutput::new_builder() @@ -81,16 +81,16 @@ fn split_receipt_against_receiptless_aggregate_mints_only_spread() { let user_lock = always_success_lock(&mut context); let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); - let split_amount = 100_000 * SHANNONS; + let split_amount = 100_000 * CKB; let aggregate_amount = 2 * split_amount; - let soft_cap = u128::from(100_000 * SHANNONS); + let soft_cap = u128::from(100_000 * CKB); let aggregate_ickb = u128::from(aggregate_amount); let aggregate_deposit_value = aggregate_ickb - (aggregate_ickb - soft_cap) / 10; let split_receipt_value = 2u128 * u128::from(split_amount); let delta = split_receipt_value - aggregate_deposit_value; let aggregate_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, aggregate_amount); - assert_eq!(delta, u128::from(10_000 * SHANNONS)); + assert_eq!(delta, u128::from(10_000 * CKB)); let funding_input = context.create_cell( CellOutput::new_builder() @@ -177,10 +177,10 @@ fn spread_path_keeps_self_funded_principal_claimable() { let user_lock = always_success_lock(&mut context); let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); - let split_amount = 100_000 * SHANNONS; + let split_amount = 100_000 * CKB; let aggregate_amount = 2 * split_amount; let aggregate_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, aggregate_amount); - let delta = 10_000 * SHANNONS as u128; + let delta = 10_000 * CKB as u128; let deposit_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); @@ -299,9 +299,9 @@ fn receiptless_aggregate_alone_cannot_mint_spread() { let user_lock = always_success_lock(&mut context); let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); - let aggregate_amount = 2 * 100_000 * SHANNONS; + let aggregate_amount = 2 * 100_000 * CKB; let aggregate_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, aggregate_amount); - let delta = u128::from(10_000 * SHANNONS); + let delta = u128::from(10_000 * CKB); let deposit_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); let receiptless_aggregate_deposit = context.create_cell( @@ -344,13 +344,13 @@ fn oversized_receiptless_aggregate_realizes_larger_spread() { let user_lock = always_success_lock(&mut context); let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); - let split_amount = 100_000 * SHANNONS; + let split_amount = 100_000 * CKB; let quantity = 20u32; let aggregate_amount = u64::from(quantity) * split_amount; let aggregate_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, aggregate_amount); let delta = u128::from(quantity) * u128::from(split_amount) - soft_capped_ickb(aggregate_amount, GENESIS_AR); - assert_eq!(aggregate_amount, 2_000_000 * SHANNONS); - assert_eq!(delta, u128::from(190_000 * SHANNONS)); + assert_eq!(aggregate_amount, 2_000_000 * CKB); + assert_eq!(delta, u128::from(190_000 * CKB)); let funding_input = context.create_cell( CellOutput::new_builder() diff --git a/scripts/tests/src/tests/ickb_logic/soft_cap.rs b/scripts/tests/src/tests/ickb_logic/soft_cap.rs index 92269f3..b85a2b5 100644 --- a/scripts/tests/src/tests/ickb_logic/soft_cap.rs +++ b/scripts/tests/src/tests/ickb_logic/soft_cap.rs @@ -7,7 +7,7 @@ fn phase2_mint_applies_soft_cap_discount_above_boundary() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let amount = 100_001 * SHANNONS; + let amount = 100_001 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() .capacity(capacity_for_data(12).pack()) @@ -59,7 +59,7 @@ fn phase2_mint_does_not_discount_at_soft_cap_boundary() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let amount = 100_000 * SHANNONS; + let amount = 100_000 * CKB; assert_eq!(soft_capped_ickb(amount, GENESIS_AR), u128::from(amount)); let receipt_out_point = context.create_cell( @@ -98,7 +98,7 @@ fn multi_quantity_phase2_mint_applies_soft_cap_per_deposit() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let amount = 100_001 * SHANNONS; + let amount = 100_001 * CKB; let quantity = 2u32; let receipt_out_point = context.create_cell( CellOutput::new_builder() @@ -111,7 +111,7 @@ fn multi_quantity_phase2_mint_applies_soft_cap_per_deposit() { let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let exact = u128::from(quantity) * soft_capped_ickb(amount, GENESIS_AR); let total_raw = u128::from(quantity) * u128::from(amount); - let soft_cap = u128::from(100_000 * SHANNONS); + let soft_cap = u128::from(100_000 * CKB); let naive_aggregate = total_raw - (total_raw - soft_cap) / 10; assert!(exact > naive_aggregate); @@ -156,7 +156,7 @@ fn mixed_phase1_phase2_still_apply_soft_cap_per_receipt() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); - let amount = 100_001 * SHANNONS; + let amount = 100_001 * CKB; let quantity = 2u32; let deposit_output_capacity = deposit_capacity(&ickb_logic, &dao, 8, amount); let receipt_input = context.create_cell( @@ -170,7 +170,7 @@ fn mixed_phase1_phase2_still_apply_soft_cap_per_receipt() { let receipt_header = insert_header_for_cell(&mut context, &receipt_input, 0, GENESIS_AR); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((300_000 * SHANNONS).pack()) + .capacity((300_000 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -178,7 +178,7 @@ fn mixed_phase1_phase2_still_apply_soft_cap_per_receipt() { let exact = u128::from(quantity) * soft_capped_ickb(amount, GENESIS_AR); let total_raw = u128::from(quantity) * u128::from(amount); - let soft_cap = u128::from(100_000 * SHANNONS); + let soft_cap = u128::from(100_000 * CKB); let naive_aggregate = total_raw - (total_raw - soft_cap) / 10; assert!(exact > naive_aggregate); diff --git a/scripts/tests/src/tests/ickb_logic/xudt_amount_limits.rs b/scripts/tests/src/tests/ickb_logic/xudt_amount_limits.rs index 647fd98..661fa8e 100644 --- a/scripts/tests/src/tests/ickb_logic/xudt_amount_limits.rs +++ b/scripts/tests/src/tests/ickb_logic/xudt_amount_limits.rs @@ -9,7 +9,7 @@ fn oversized_output_udt_amount_is_rejected() { let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((1_000 * SHANNONS).pack()) + .capacity((1_000 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -20,7 +20,7 @@ fn oversized_output_udt_amount_is_rejected() { .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), - receipt_data(1, 1_000 * SHANNONS), + receipt_data(1, 1_000 * CKB), ); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); diff --git a/scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs b/scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs index 26a930b..b0d30f0 100644 --- a/scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs +++ b/scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs @@ -9,7 +9,7 @@ fn xudt_owner_script_output_witness_cannot_mint_without_live_owner_mode() { let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((500 * SHANNONS).pack()) + .capacity((500 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), diff --git a/scripts/tests/src/tests/limit_order/crosswire_blockers.rs b/scripts/tests/src/tests/limit_order/crosswire_blockers.rs index 48b2465..d3dd1a7 100644 --- a/scripts/tests/src/tests/limit_order/crosswire_blockers.rs +++ b/scripts/tests/src/tests/limit_order/crosswire_blockers.rs @@ -10,29 +10,29 @@ fn distinct_mint_capacities_block_master_crosswire() { &mut context, owner1_lock.clone(), helper_type.clone(), - 1_600 * SHANNONS, + 1_600 * CKB, ); let (order2_input, master2_input) = build_real_limit_order_and_master_with_capacity( &mut context, owner2_lock.clone(), helper_type.clone(), - 1_500 * SHANNONS, + 1_500 * CKB, ); let limit_order = limit_order_script(&mut context); - let crosswired_order1_data = order_data_match(100 * SHANNONS as u128, &master2_input, (1, 1)); - let crosswired_order2_data = order_data_match(100 * SHANNONS as u128, &master1_input, (1, 1)); + let crosswired_order1_data = order_data_match(100 * CKB as u128, &master2_input, (1, 1)); + let crosswired_order2_data = order_data_match(100 * CKB as u128, &master1_input, (1, 1)); let crosswire_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(order1_input).build()) .input(CellInput::new_builder().previous_output(order2_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), CellOutput::new_builder() - .capacity((1_400 * SHANNONS).pack()) + .capacity((1_400 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -61,22 +61,22 @@ fn distinct_match_progress_blocks_master_crosswire() { &mut context, owner1_lock.clone(), helper_type.clone(), - 1_600 * SHANNONS, + 1_600 * CKB, ); let (order2_input, master2_input) = build_real_limit_order_and_master_with_capacity( &mut context, owner2_lock.clone(), helper_type.clone(), - 1_500 * SHANNONS, + 1_500 * CKB, ); let limit_order = limit_order_script(&mut context); - let order1_matched_data = order_data_match(100 * SHANNONS as u128, &master1_input, (1, 1)); + let order1_matched_data = order_data_match(100 * CKB as u128, &master1_input, (1, 1)); let order1_match_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(order1_input).build()) .output( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -94,12 +94,12 @@ fn distinct_match_progress_blocks_master_crosswire() { order1_matched_data, ); - let order2_matched_data = order_data_match(200 * SHANNONS as u128, &master2_input, (1, 1)); + let order2_matched_data = order_data_match(200 * CKB as u128, &master2_input, (1, 1)); let order2_match_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(order2_input).build()) .output( CellOutput::new_builder() - .capacity((1_300 * SHANNONS).pack()) + .capacity((1_300 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -117,19 +117,19 @@ fn distinct_match_progress_blocks_master_crosswire() { order2_matched_data, ); - let crosswired_order1_data = order_data_match(200 * SHANNONS as u128, &master2_input, (1, 1)); - let crosswired_order2_data = order_data_match(300 * SHANNONS as u128, &master1_input, (1, 1)); + let crosswired_order1_data = order_data_match(200 * CKB as u128, &master2_input, (1, 1)); + let crosswired_order2_data = order_data_match(300 * CKB as u128, &master1_input, (1, 1)); let crosswire_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(order1_matched).build()) .input(CellInput::new_builder().previous_output(order2_matched).build()) .outputs(vec![ CellOutput::new_builder() - .capacity((1_400 * SHANNONS).pack()) + .capacity((1_400 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), CellOutput::new_builder() - .capacity((1_200 * SHANNONS).pack()) + .capacity((1_200 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -158,22 +158,22 @@ fn real_mint_and_match_orders_cannot_crosswire_masters() { &mut context, owner1_lock.clone(), helper_type.clone(), - 1_600 * SHANNONS, + 1_600 * CKB, ); let (match_order_seed, master2_input) = build_real_limit_order_and_master_with_capacity( &mut context, owner2_lock.clone(), helper_type.clone(), - 1_500 * SHANNONS, + 1_500 * CKB, ); let limit_order = limit_order_script(&mut context); - let match_order_data = order_data_match(100 * SHANNONS as u128, &master2_input, (1, 1)); + let match_order_data = order_data_match(100 * CKB as u128, &master2_input, (1, 1)); let seed_match_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(match_order_seed).build()) .output( CellOutput::new_builder() - .capacity((1_400 * SHANNONS).pack()) + .capacity((1_400 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -191,19 +191,19 @@ fn real_mint_and_match_orders_cannot_crosswire_masters() { match_order_data, ); - let crosswired_mint_data = order_data_match(100 * SHANNONS as u128, &master2_input, (1, 1)); - let crosswired_match_data = order_data_match(200 * SHANNONS as u128, &master1_input, (1, 1)); + let crosswired_mint_data = order_data_match(100 * CKB as u128, &master2_input, (1, 1)); + let crosswired_match_data = order_data_match(200 * CKB as u128, &master1_input, (1, 1)); let crosswire_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(mint_order_input).build()) .input(CellInput::new_builder().previous_output(match_order_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), CellOutput::new_builder() - .capacity((1_300 * SHANNONS).pack()) + .capacity((1_300 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), diff --git a/scripts/tests/src/tests/limit_order/crosswire_live_match.rs b/scripts/tests/src/tests/limit_order/crosswire_live_match.rs index b8ca41e..e435373 100644 --- a/scripts/tests/src/tests/limit_order/crosswire_live_match.rs +++ b/scripts/tests/src/tests/limit_order/crosswire_live_match.rs @@ -13,19 +13,19 @@ fn cloned_live_orders_can_swap_masters_during_match() { build_real_limit_order_and_master(&mut context, owner2_lock.clone(), helper_type.clone()); let limit_order = limit_order_script(&mut context); - let matched_order1_data = order_data_match(100 * SHANNONS as u128, &master2_input, (1, 1)); - let matched_order2_data = order_data_match(100 * SHANNONS as u128, &master1_input, (1, 1)); + let matched_order1_data = order_data_match(100 * CKB as u128, &master2_input, (1, 1)); + let matched_order2_data = order_data_match(100 * CKB as u128, &master1_input, (1, 1)); let crosswire_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(order1_input).build()) .input(CellInput::new_builder().previous_output(order2_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity((1_400 * SHANNONS).pack()) + .capacity((1_400 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), CellOutput::new_builder() - .capacity((1_400 * SHANNONS).pack()) + .capacity((1_400 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -47,7 +47,7 @@ fn cloned_live_orders_can_swap_masters_during_match() { .input(CellInput::new_builder().previous_output(master2_input.clone()).build()) .output( CellOutput::new_builder() - .capacity((1_600 * SHANNONS).pack()) + .capacity((1_600 * CKB).pack()) .lock(owner2_lock.clone()) .build(), ) @@ -66,7 +66,7 @@ fn cloned_live_orders_can_swap_masters_during_match() { .input(CellInput::new_builder().previous_output(master1_input).build()) .output( CellOutput::new_builder() - .capacity((1_600 * SHANNONS).pack()) + .capacity((1_600 * CKB).pack()) .lock(owner1_lock) .build(), ) @@ -93,26 +93,26 @@ fn hybrid_fake_and_real_limit_order_match_keeps_real_master_on_real_metapoint() let fake_master = OutPoint::new(Byte32::from_slice(&[7u8; 32]).expect("byte32"), 9); let fake_order_input = context.create_cell( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), order_data_match(0, &fake_master, (1, 1)), ); - let real_lineage_data = order_data_match(100 * SHANNONS as u128, &real_master_input, (1, 1)); - let fake_lineage_data = order_data_match(100 * SHANNONS as u128, &fake_master, (1, 1)); + let real_lineage_data = order_data_match(100 * CKB as u128, &real_master_input, (1, 1)); + let fake_lineage_data = order_data_match(100 * CKB as u128, &fake_master, (1, 1)); let hybrid_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(fake_order_input).build()) .input(CellInput::new_builder().previous_output(real_order_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity((1_400 * SHANNONS).pack()) + .capacity((1_400 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), CellOutput::new_builder() - .capacity((1_400 * SHANNONS).pack()) + .capacity((1_400 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -144,7 +144,7 @@ fn hybrid_fake_and_real_limit_order_match_keeps_real_master_on_real_metapoint() .input(CellInput::new_builder().previous_output(real_master_input.clone()).build()) .output( CellOutput::new_builder() - .capacity((1_600 * SHANNONS).pack()) + .capacity((1_600 * CKB).pack()) .lock(owner_lock.clone()) .build(), ) @@ -163,7 +163,7 @@ fn hybrid_fake_and_real_limit_order_match_keeps_real_master_on_real_metapoint() .input(CellInput::new_builder().previous_output(real_master_input).build()) .output( CellOutput::new_builder() - .capacity((1_600 * SHANNONS).pack()) + .capacity((1_600 * CKB).pack()) .lock(owner_lock) .build(), ) diff --git a/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs b/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs index e4242b7..1d52a6d 100644 --- a/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs +++ b/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs @@ -10,7 +10,7 @@ fn mint_crosswire_swaps_order_masters() { let limit_order = limit_order_script(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((4_000 * SHANNONS).pack()) + .capacity((4_000 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -20,7 +20,7 @@ fn mint_crosswire_swaps_order_masters() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -30,7 +30,7 @@ fn mint_crosswire_swaps_order_masters() { .type_(Some(limit_order.clone()).pack()) .build(), CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -87,7 +87,7 @@ fn mint_crosswire_swaps_order_masters() { .input(CellInput::new_builder().previous_output(master1.clone()).build()) .output( CellOutput::new_builder() - .capacity((1_700 * SHANNONS).pack()) + .capacity((1_700 * CKB).pack()) .lock(owner1_lock) .build(), ) @@ -103,7 +103,7 @@ fn mint_crosswire_swaps_order_masters() { .input(CellInput::new_builder().previous_output(master1).build()) .output( CellOutput::new_builder() - .capacity((1_700 * SHANNONS).pack()) + .capacity((1_700 * CKB).pack()) .lock(owner2_lock) .build(), ) @@ -125,7 +125,7 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { let limit_order = limit_order_script(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((8_000 * SHANNONS).pack()) + .capacity((8_000 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -133,7 +133,7 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { let mut outputs = vec![ CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -150,7 +150,7 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { } outputs.push( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -222,7 +222,7 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { .input(CellInput::new_builder().previous_output(master2.clone()).build()) .output( CellOutput::new_builder() - .capacity((1_700 * SHANNONS).pack()) + .capacity((1_700 * CKB).pack()) .lock(owner2_lock) .build(), ) @@ -239,7 +239,7 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { .input(CellInput::new_builder().previous_output(master1).build()) .output( CellOutput::new_builder() - .capacity((1_700 * SHANNONS).pack()) + .capacity((1_700 * CKB).pack()) .lock(owner1_lock) .build(), ) diff --git a/scripts/tests/src/tests/limit_order/fake_match_lineage.rs b/scripts/tests/src/tests/limit_order/fake_match_lineage.rs index bec2f48..45a9226 100644 --- a/scripts/tests/src/tests/limit_order/fake_match_lineage.rs +++ b/scripts/tests/src/tests/limit_order/fake_match_lineage.rs @@ -9,7 +9,7 @@ fn fake_match_lineage_can_keep_advancing_without_real_master() { let initial_order = context.create_cell( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -20,12 +20,12 @@ fn fake_match_lineage_can_keep_advancing_without_real_master() { .input(CellInput::new_builder().previous_output(initial_order).build()) .output( CellOutput::new_builder() - .capacity((1_400 * SHANNONS).pack()) + .capacity((1_400 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), ) - .output_data(order_data_match(100 * SHANNONS as u128, &fake_master, (1, 1)).pack()) + .output_data(order_data_match(100 * CKB as u128, &fake_master, (1, 1)).pack()) .build(); let first_match_tx = context.complete_tx(first_match_tx); @@ -37,19 +37,19 @@ fn fake_match_lineage_can_keep_advancing_without_real_master() { context.create_cell_with_out_point( first_match_out_point.clone(), first_match_tx.outputs().get(0).expect("first forged match output"), - order_data_match(100 * SHANNONS as u128, &fake_master, (1, 1)), + order_data_match(100 * CKB as u128, &fake_master, (1, 1)), ); let second_match_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(first_match_out_point).build()) .output( CellOutput::new_builder() - .capacity((1_300 * SHANNONS).pack()) + .capacity((1_300 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), ) - .output_data(order_data_match(200 * SHANNONS as u128, &fake_master, (1, 1)).pack()) + .output_data(order_data_match(200 * CKB as u128, &fake_master, (1, 1)).pack()) .build(); let second_match_tx = context.complete_tx(second_match_tx); @@ -69,7 +69,7 @@ fn fake_match_order_can_strand_real_order() { let limit_order = limit_order_script(&mut context); let phantom_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -89,7 +89,7 @@ fn fake_match_order_can_strand_real_order() { ) .output( CellOutput::new_builder() - .capacity((1_700 * SHANNONS).pack()) + .capacity((1_700 * CKB).pack()) .lock(owner_lock) .build(), ) @@ -109,7 +109,7 @@ fn fake_match_order_can_strand_real_order() { ) .output( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(always_success_lock(&mut context)) .build(), ) diff --git a/scripts/tests/src/tests/limit_order/fulfilled.rs b/scripts/tests/src/tests/limit_order/fulfilled.rs index d4ecc3a..e305a06 100644 --- a/scripts/tests/src/tests/limit_order/fulfilled.rs +++ b/scripts/tests/src/tests/limit_order/fulfilled.rs @@ -43,7 +43,7 @@ fn fulfilled_udt_to_ckb_shape_cannot_reach_guard_and_fails_as_invalid_match() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -51,7 +51,7 @@ fn fulfilled_udt_to_ckb_shape_cannot_reach_guard_and_fails_as_invalid_match() { ); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((100 * SHANNONS).pack()) + .capacity((100 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -62,12 +62,12 @@ fn fulfilled_udt_to_ckb_shape_cannot_reach_guard_and_fails_as_invalid_match() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), CellOutput::new_builder() - .capacity((80 * SHANNONS).pack()) + .capacity((80 * CKB).pack()) .lock(funding_lock) .build(), ]) diff --git a/scripts/tests/src/tests/limit_order/lock_only_shapes.rs b/scripts/tests/src/tests/limit_order/lock_only_shapes.rs index 5460cb6..03aeac6 100644 --- a/scripts/tests/src/tests/limit_order/lock_only_shapes.rs +++ b/scripts/tests/src/tests/limit_order/lock_only_shapes.rs @@ -9,7 +9,7 @@ fn non_empty_args_output_lock_can_be_created_but_not_spent() { let helper_type = helper_type_script(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -19,7 +19,7 @@ fn non_empty_args_output_lock_can_be_created_but_not_spent() { .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order_non_empty, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order_non_empty, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order_non_empty.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -33,7 +33,7 @@ fn non_empty_args_output_lock_can_be_created_but_not_spent() { let out_point = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order_non_empty, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order_non_empty, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order_non_empty.clone()) .type_(Some(helper_type).pack()) .build(), @@ -43,7 +43,7 @@ fn non_empty_args_output_lock_can_be_created_but_not_spent() { .input(CellInput::new_builder().previous_output(out_point).build()) .output( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(always_success_lock(&mut context)) .build(), ) @@ -62,7 +62,7 @@ fn cell_using_limit_order_as_both_lock_and_type_is_rejected() { let limit_order = limit_order_script(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -161,7 +161,7 @@ fn lock_only_limit_order_missing_udt_type_hits_generic_failure_even_at_valid_cap .as_u64(); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((200 * SHANNONS).pack()) + .capacity((200 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -191,7 +191,7 @@ fn lock_only_limit_order_missing_udt_type_hits_generic_failure_even_at_valid_cap .input(CellInput::new_builder().previous_output(forged_out_point).build()) .output( CellOutput::new_builder() - .capacity((200 * SHANNONS).pack()) + .capacity((200 * CKB).pack()) .lock(always_success_lock(&mut context)) .build(), ) diff --git a/scripts/tests/src/tests/limit_order/master_admission.rs b/scripts/tests/src/tests/limit_order/master_admission.rs index b26f3bb..80d1ef4 100644 --- a/scripts/tests/src/tests/limit_order/master_admission.rs +++ b/scripts/tests/src/tests/limit_order/master_admission.rs @@ -10,7 +10,7 @@ fn mint_accepts_master_with_unspendable_foreign_lock() { let poisoned_lock = data1_script(&mut context, "ickb_logic", Bytes::from(vec![1])); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -20,7 +20,7 @@ fn mint_accepts_master_with_unspendable_foreign_lock() { .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type).pack()) .build(), @@ -59,7 +59,7 @@ fn mint_accepts_master_with_unspendable_foreign_lock() { .input(CellInput::new_builder().previous_output(master_out_point).build()) .output( CellOutput::new_builder() - .capacity((1_700 * SHANNONS).pack()) + .capacity((1_700 * CKB).pack()) .lock(always_success_lock(&mut context)) .build(), ) @@ -81,7 +81,7 @@ fn mint_accepts_master_with_empty_args_ickb_logic_lock_and_strands_on_spend() { let benign_foreign_lock = ickb_logic_script(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -91,7 +91,7 @@ fn mint_accepts_master_with_empty_args_ickb_logic_lock_and_strands_on_spend() { .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type).pack()) .build(), @@ -130,7 +130,7 @@ fn mint_accepts_master_with_empty_args_ickb_logic_lock_and_strands_on_spend() { .input(CellInput::new_builder().previous_output(master_out_point).build()) .output( CellOutput::new_builder() - .capacity((1_700 * SHANNONS).pack()) + .capacity((1_700 * CKB).pack()) .lock(always_success_lock(&mut context)) .build(), ) diff --git a/scripts/tests/src/tests/limit_order/match_progression.rs b/scripts/tests/src/tests/limit_order/match_progression.rs index a9704ec..e7ca1c5 100644 --- a/scripts/tests/src/tests/limit_order/match_progression.rs +++ b/scripts/tests/src/tests/limit_order/match_progression.rs @@ -8,7 +8,7 @@ fn udt_to_ckb_match_passes() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -16,7 +16,7 @@ fn udt_to_ckb_match_passes() { ); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((100 * SHANNONS).pack()) + .capacity((100 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -27,12 +27,12 @@ fn udt_to_ckb_match_passes() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), CellOutput::new_builder() - .capacity((80 * SHANNONS).pack()) + .capacity((80 * CKB).pack()) .lock(funding_lock) .build(), ]) @@ -59,7 +59,7 @@ fn udt_to_ckb_match_accepts_exact_minimum_partial_fill() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -67,7 +67,7 @@ fn udt_to_ckb_match_accepts_exact_minimum_partial_fill() { ); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((100 * SHANNONS).pack()) + .capacity((100 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -78,12 +78,12 @@ fn udt_to_ckb_match_accepts_exact_minimum_partial_fill() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_516 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_516 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), CellOutput::new_builder() - .capacity((84 * SHANNONS).pack()) + .capacity((84 * CKB).pack()) .lock(funding_lock) .build(), ]) @@ -112,7 +112,7 @@ fn valid_match_ignores_foreign_typed_output() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -120,7 +120,7 @@ fn valid_match_ignores_foreign_typed_output() { ); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((300 * SHANNONS).pack()) + .capacity((300 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -131,16 +131,16 @@ fn valid_match_ignores_foreign_typed_output() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), CellOutput::new_builder() - .capacity((80 * SHANNONS).pack()) + .capacity((80 * CKB).pack()) .lock(funding_lock) .build(), CellOutput::new_builder() - .capacity((200 * SHANNONS).pack()) + .capacity((200 * CKB).pack()) .lock(foreign_lock) .type_(Some(foreign_type).pack()) .build(), @@ -169,7 +169,7 @@ fn ckb_to_udt_match_passes_with_both_ratios_present() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -180,19 +180,19 @@ fn ckb_to_udt_match_passes_with_both_ratios_present() { .input(CellInput::new_builder().previous_output(input_order).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_480 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_480 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), CellOutput::new_builder() - .capacity((20 * SHANNONS).pack()) + .capacity((20 * CKB).pack()) .lock(funding_lock) .build(), ]) .outputs_data( vec![ order_data_custom( - u128::from(20 * SHANNONS), + u128::from(20 * CKB), 1, [0u8; 32], 5u32.to_le_bytes(), @@ -220,7 +220,7 @@ fn ckb_to_udt_match_accepts_exact_minimum_partial_fill() { let input_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -231,7 +231,7 @@ fn ckb_to_udt_match_accepts_exact_minimum_partial_fill() { .input(CellInput::new_builder().previous_output(input_order_out_point).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS - 16).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB - 16).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -253,7 +253,7 @@ fn udt_to_ckb_match_rejects_small_udt_delta_under_minimum() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -261,7 +261,7 @@ fn udt_to_ckb_match_rejects_small_udt_delta_under_minimum() { ); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((100 * SHANNONS).pack()) + .capacity((100 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -272,12 +272,12 @@ fn udt_to_ckb_match_rejects_small_udt_delta_under_minimum() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), CellOutput::new_builder() - .capacity((80 * SHANNONS).pack()) + .capacity((80 * CKB).pack()) .lock(funding_lock) .build(), ]) @@ -303,7 +303,7 @@ fn udt_to_ckb_match_rejects_large_minimum_partial_fill() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -311,7 +311,7 @@ fn udt_to_ckb_match_rejects_large_minimum_partial_fill() { ); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((100 * SHANNONS).pack()) + .capacity((100 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -322,12 +322,12 @@ fn udt_to_ckb_match_rejects_large_minimum_partial_fill() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), CellOutput::new_builder() - .capacity((80 * SHANNONS).pack()) + .capacity((80 * CKB).pack()) .lock(funding_lock) .build(), ]) @@ -354,23 +354,23 @@ fn match_rejects_invalid_direction_change() { let input_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), - order_data_match(100 * SHANNONS as u128, &master, (1, 1)), + order_data_match(100 * CKB as u128, &master, (1, 1)), ); let tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(input_order_out_point).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_400 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_400 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), ) - .output_data(order_data_match(50 * SHANNONS as u128, &master, (1, 1)).pack()) + .output_data(order_data_match(50 * CKB as u128, &master, (1, 1)).pack()) .build(); let tx = context.complete_tx(tx); @@ -387,23 +387,23 @@ fn match_rejects_unchanged_shape() { let input_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), - order_data_match(100 * SHANNONS as u128, &master, (1, 1)), + order_data_match(100 * CKB as u128, &master, (1, 1)), ); let tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(input_order_out_point).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), ) - .output_data(order_data_match(100 * SHANNONS as u128, &master, (1, 1)).pack()) + .output_data(order_data_match(100 * CKB as u128, &master, (1, 1)).pack()) .build(); let tx = context.complete_tx(tx); @@ -420,7 +420,7 @@ fn match_rejects_decreasing_value() { let input_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -431,12 +431,12 @@ fn match_rejects_decreasing_value() { .input(CellInput::new_builder().previous_output(input_order_out_point).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_400 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_400 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), ) - .output_data(order_data_match(50 * SHANNONS as u128, &master, (1, 1)).pack()) + .output_data(order_data_match(50 * CKB as u128, &master, (1, 1)).pack()) .build(); let tx = context.complete_tx(tx); @@ -452,7 +452,7 @@ fn match_rejects_too_small_partial_fill() { let input_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -463,7 +463,7 @@ fn match_rejects_too_small_partial_fill() { .input(CellInput::new_builder().previous_output(input_order_out_point).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS - 8).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB - 8).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), diff --git a/scripts/tests/src/tests/limit_order/mint_shape_validation.rs b/scripts/tests/src/tests/limit_order/mint_shape_validation.rs index f352c37..cecceea 100644 --- a/scripts/tests/src/tests/limit_order/mint_shape_validation.rs +++ b/scripts/tests/src/tests/limit_order/mint_shape_validation.rs @@ -10,7 +10,7 @@ fn mint_accepts_ckb_min_match_log_64() { let helper_type = helper_type_script(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -20,7 +20,7 @@ fn mint_accepts_ckb_min_match_log_64() { .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type).pack()) .build(), @@ -57,7 +57,7 @@ fn mint_rejects_ckb_min_match_log_65() { let helper_type = helper_type_script(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -67,7 +67,7 @@ fn mint_rejects_ckb_min_match_log_65() { .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type).pack()) .build(), @@ -102,7 +102,7 @@ fn two_master_outputs_fail_as_invalid_configuration_not_duplicate_master() { let limit_order = limit_order_script(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((1_000 * SHANNONS).pack()) + .capacity((1_000 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), diff --git a/scripts/tests/src/tests/limit_order/phantom_lineage.rs b/scripts/tests/src/tests/limit_order/phantom_lineage.rs index a49930f..f504d63 100644 --- a/scripts/tests/src/tests/limit_order/phantom_lineage.rs +++ b/scripts/tests/src/tests/limit_order/phantom_lineage.rs @@ -8,7 +8,7 @@ fn phantom_mint_output_can_be_created() { let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -18,7 +18,7 @@ fn phantom_mint_output_can_be_created() { .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -40,7 +40,7 @@ fn phantom_mint_lineage_can_enter_match_without_real_master() { let phantom_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -56,12 +56,12 @@ fn phantom_mint_lineage_can_enter_match_without_real_master() { ) .output( CellOutput::new_builder() - .capacity((1_400 * SHANNONS).pack()) + .capacity((1_400 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), ) - .output_data(order_data_match(100 * SHANNONS as u128, &phantom_master_out_point, (1, 1)).pack()) + .output_data(order_data_match(100 * CKB as u128, &phantom_master_out_point, (1, 1)).pack()) .build(); let tx = context.complete_tx(tx); @@ -78,7 +78,7 @@ fn phantom_mint_lineage_cannot_rebind_to_an_arbitrary_fake_match_master() { let phantom_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -94,12 +94,12 @@ fn phantom_mint_lineage_cannot_rebind_to_an_arbitrary_fake_match_master() { ) .output( CellOutput::new_builder() - .capacity((1_400 * SHANNONS).pack()) + .capacity((1_400 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), ) - .output_data(order_data_match(100 * SHANNONS as u128, &fake_master, (1, 1)).pack()) + .output_data(order_data_match(100 * CKB as u128, &fake_master, (1, 1)).pack()) .build(); let tx = context.complete_tx(tx); @@ -115,7 +115,7 @@ fn phantom_limit_order_match_still_requires_same_order_info() { let phantom_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -131,12 +131,12 @@ fn phantom_limit_order_match_still_requires_same_order_info() { ) .output( CellOutput::new_builder() - .capacity((1_400 * SHANNONS).pack()) + .capacity((1_400 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), ) - .output_data(order_data_match(100 * SHANNONS as u128, &phantom_master_out_point, (2, 1)).pack()) + .output_data(order_data_match(100 * CKB as u128, &phantom_master_out_point, (2, 1)).pack()) .build(); let tx = context.complete_tx(tx); @@ -152,7 +152,7 @@ fn phantom_limit_order_cannot_be_melted_without_a_master_input() { let phantom_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -167,7 +167,7 @@ fn phantom_limit_order_cannot_be_melted_without_a_master_input() { ) .output( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(always_success_lock(&mut context)) .build(), ) @@ -188,7 +188,7 @@ fn phantom_limit_order_cannot_be_melted_with_an_unrelated_master() { let phantom_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -216,7 +216,7 @@ fn phantom_limit_order_cannot_be_melted_with_an_unrelated_master() { ) .output( CellOutput::new_builder() - .capacity((1_700 * SHANNONS).pack()) + .capacity((1_700 * CKB).pack()) .lock(owner_lock) .build(), ) @@ -237,7 +237,7 @@ fn lock_only_limit_order_output_can_be_created_with_match_order_data() { let limit_order = limit_order_script(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -248,7 +248,7 @@ fn lock_only_limit_order_output_can_be_created_with_match_order_data() { .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), diff --git a/scripts/tests/src/tests/limit_order/poisoning.rs b/scripts/tests/src/tests/limit_order/poisoning.rs index 6df0208..653d236 100644 --- a/scripts/tests/src/tests/limit_order/poisoning.rs +++ b/scripts/tests/src/tests/limit_order/poisoning.rs @@ -9,7 +9,7 @@ fn unrelated_non_empty_args_output_lock_poisons_match() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -17,7 +17,7 @@ fn unrelated_non_empty_args_output_lock_poisons_match() { ); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((100 * SHANNONS).pack()) + .capacity((100 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -28,12 +28,12 @@ fn unrelated_non_empty_args_output_lock_poisons_match() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), CellOutput::new_builder() - .capacity((80 * SHANNONS).pack()) + .capacity((80 * CKB).pack()) .lock(funding_lock) .build(), CellOutput::new_builder() @@ -67,7 +67,7 @@ fn order_shaped_non_empty_args_output_poisons_match() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -75,7 +75,7 @@ fn order_shaped_non_empty_args_output_poisons_match() { ); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((400 * SHANNONS).pack()) + .capacity((400 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -86,16 +86,16 @@ fn order_shaped_non_empty_args_output_poisons_match() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type.clone()).pack()) .build(), CellOutput::new_builder() - .capacity((80 * SHANNONS).pack()) + .capacity((80 * CKB).pack()) .lock(funding_lock) .build(), CellOutput::new_builder() - .capacity(deposit_capacity(&poisoned_lock, &helper_type, 73, 300 * SHANNONS).pack()) + .capacity(deposit_capacity(&poisoned_lock, &helper_type, 73, 300 * CKB).pack()) .lock(poisoned_lock) .type_(Some(helper_type).pack()) .build(), @@ -127,7 +127,7 @@ fn non_empty_args_master_sibling_poisons_match() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -135,7 +135,7 @@ fn non_empty_args_master_sibling_poisons_match() { ); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((100 * SHANNONS).pack()) + .capacity((100 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -155,12 +155,12 @@ fn non_empty_args_master_sibling_poisons_match() { .input(CellInput::new_builder().previous_output(poisoned_master_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), CellOutput::new_builder() - .capacity((80 * SHANNONS).pack()) + .capacity((80 * CKB).pack()) .lock(funding_lock) .build(), ]) diff --git a/scripts/tests/src/tests/limit_order/real_lineage.rs b/scripts/tests/src/tests/limit_order/real_lineage.rs index 788be06..26f5848 100644 --- a/scripts/tests/src/tests/limit_order/real_lineage.rs +++ b/scripts/tests/src/tests/limit_order/real_lineage.rs @@ -6,9 +6,9 @@ fn real_order_match_cannot_rewrite_master_outpoint_to_an_arbitrary_master() { let mut context = Context::default(); let (owner_lock, helper_type) = named_lock_and_helper_type_scripts(&mut context, b"owner"); let (real_order_out_point, _real_master_out_point) = - build_real_limit_order_and_master_with_capacity(&mut context, owner_lock.clone(), helper_type.clone(), 1_600 * SHANNONS); + build_real_limit_order_and_master_with_capacity(&mut context, owner_lock.clone(), helper_type.clone(), 1_600 * CKB); let (_victim_order_out_point, victim_master_out_point) = - build_real_limit_order_and_master_with_capacity(&mut context, owner_lock.clone(), helper_type.clone(), 1_500 * SHANNONS); + build_real_limit_order_and_master_with_capacity(&mut context, owner_lock.clone(), helper_type.clone(), 1_500 * CKB); let limit_order = limit_order_script(&mut context); let tx = TransactionBuilder::default() @@ -19,12 +19,12 @@ fn real_order_match_cannot_rewrite_master_outpoint_to_an_arbitrary_master() { ) .output( CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type.clone()).pack()) .build(), ) - .output_data(order_data_match(100 * SHANNONS as u128, &victim_master_out_point, (1, 1)).pack()) + .output_data(order_data_match(100 * CKB as u128, &victim_master_out_point, (1, 1)).pack()) .build(); let tx = context.complete_tx(tx); @@ -49,12 +49,12 @@ fn real_limit_order_can_transition_from_mint_to_match_without_consuming_master() ) .output( CellOutput::new_builder() - .capacity((1_400 * SHANNONS).pack()) + .capacity((1_400 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), ) - .output_data(order_data_match(100 * SHANNONS as u128, &real_master_out_point, (1, 1)).pack()) + .output_data(order_data_match(100 * CKB as u128, &real_master_out_point, (1, 1)).pack()) .build(); let tx = context.complete_tx(tx); @@ -80,12 +80,12 @@ fn real_limit_order_match_rejects_rewriting_order_info() { ) .output( CellOutput::new_builder() - .capacity((1_400 * SHANNONS).pack()) + .capacity((1_400 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), ) - .output_data(order_data_match(100 * SHANNONS as u128, &real_master_out_point, (2, 1)).pack()) + .output_data(order_data_match(100 * CKB as u128, &real_master_out_point, (2, 1)).pack()) .build(); let tx = context.complete_tx(tx); diff --git a/scripts/tests/src/tests/limit_order/remint.rs b/scripts/tests/src/tests/limit_order/remint.rs index 316cd2f..f3d4f82 100644 --- a/scripts/tests/src/tests/limit_order/remint.rs +++ b/scripts/tests/src/tests/limit_order/remint.rs @@ -33,7 +33,7 @@ fn can_atomically_melt_and_remint_with_negative_distance_and_filler() { .lock(filler_lock) .build(), CellOutput::new_builder() - .capacity((1_500 * SHANNONS).pack()) + .capacity((1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -65,7 +65,7 @@ fn can_atomically_melt_and_remint_with_negative_distance_and_filler() { .input(CellInput::new_builder().previous_output(new_master).build()) .output( CellOutput::new_builder() - .capacity((1_700 * SHANNONS).pack()) + .capacity((1_700 * CKB).pack()) .lock(owner_lock) .build(), ) diff --git a/scripts/tests/src/tests/limit_order/same_master.rs b/scripts/tests/src/tests/limit_order/same_master.rs index d5cf1f2..11bf748 100644 --- a/scripts/tests/src/tests/limit_order/same_master.rs +++ b/scripts/tests/src/tests/limit_order/same_master.rs @@ -9,7 +9,7 @@ fn match_rejects_two_outputs_sharing_one_master() { let input_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -20,22 +20,22 @@ fn match_rejects_two_outputs_sharing_one_master() { .input(CellInput::new_builder().previous_output(input_order_out_point).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_400 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_400 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), ) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 100 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 100 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), ) .outputs_data( vec![ - order_data_match(50 * SHANNONS as u128, &master, (1, 1)), - order_data_match(10 * SHANNONS as u128, &master, (1, 1)), + order_data_match(50 * CKB as u128, &master, (1, 1)), + order_data_match(10 * CKB as u128, &master, (1, 1)), ] .pack(), ) @@ -55,7 +55,7 @@ fn same_master_collision_on_inputs_is_rejected() { let first_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -63,7 +63,7 @@ fn same_master_collision_on_inputs_is_rejected() { ); let second_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_400 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_400 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -75,7 +75,7 @@ fn same_master_collision_on_inputs_is_rejected() { .input(CellInput::new_builder().previous_output(second_order).build()) .output( CellOutput::new_builder() - .capacity((2_900 * SHANNONS).pack()) + .capacity((2_900 * CKB).pack()) .lock(always_success_lock(&mut context)) .build(), ) diff --git a/scripts/tests/src/tests/owned_owner/dao_crosswiring.rs b/scripts/tests/src/tests/owned_owner/dao_crosswiring.rs index 4b2ea32..a3eaa17 100644 --- a/scripts/tests/src/tests/owned_owner/dao_crosswiring.rs +++ b/scripts/tests/src/tests/owned_owner/dao_crosswiring.rs @@ -8,8 +8,8 @@ fn crosswired_batch_is_blocked_by_dao_index_rules() { let user2_lock = named_always_success_lock(&mut context, b"user2"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let amount1 = 1_000 * SHANNONS; - let amount2 = 1_100 * SHANNONS; + let amount1 = 1_000 * CKB; + let amount2 = 1_100 * CKB; let total1 = deposit_capacity(&ickb_logic, &dao, 8, amount1); let total2 = deposit_capacity(&ickb_logic, &dao, 8, amount2); let header1 = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); @@ -93,8 +93,8 @@ fn weak_lock_valid_dao_batch_can_crosswire_claims() { let user2_lock = named_always_success_lock(&mut context, b"user2"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let amount1 = 1_000 * SHANNONS; - let amount2 = 1_100 * SHANNONS; + let amount1 = 1_000 * CKB; + let amount2 = 1_100 * CKB; let total1 = deposit_capacity(&ickb_logic, &dao, 8, amount1); let total2 = deposit_capacity(&ickb_logic, &dao, 8, amount2); let header1 = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); @@ -179,8 +179,8 @@ fn weak_lock_crosswired_batch_reassigns_phase2_claims() { let user2_lock = named_always_success_lock(&mut context, b"user2"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let amount1 = 1_000 * SHANNONS; - let amount2 = 1_200 * SHANNONS; + let amount1 = 1_000 * CKB; + let amount2 = 1_200 * CKB; let total1 = deposit_capacity(&ickb_logic, &dao, 8, amount1); let total2 = deposit_capacity(&ickb_logic, &dao, 8, amount2); let deposit_header1 = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); @@ -340,9 +340,9 @@ fn weak_lock_three_way_crosswire_rotates_claims() { let user3_lock = named_always_success_lock(&mut context, b"user3"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let amount1 = 1_000 * SHANNONS; - let amount2 = 1_100 * SHANNONS; - let amount3 = 1_200 * SHANNONS; + let amount1 = 1_000 * CKB; + let amount2 = 1_100 * CKB; + let amount3 = 1_200 * CKB; let total1 = deposit_capacity(&ickb_logic, &dao, 8, amount1); let total2 = deposit_capacity(&ickb_logic, &dao, 8, amount2); let total3 = deposit_capacity(&ickb_logic, &dao, 8, amount3); diff --git a/scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs b/scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs index 3f0c06f..431a73e 100644 --- a/scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs +++ b/scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs @@ -9,7 +9,7 @@ fn phase1_accepts_unspendable_foreign_owner_lock() { let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); let poisoned_lock = data1_script(&mut context, "limit_order", Bytes::from(vec![1])); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let deposit_input = context.create_cell( CellOutput::new_builder() @@ -104,7 +104,7 @@ fn phase1_accepts_limit_order_owner_lock_but_claim_strands() { let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); let benign_foreign_lock = limit_order_script(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let deposit_input = context.create_cell( CellOutput::new_builder() @@ -204,7 +204,7 @@ fn limit_order_backed_owner_is_blocked_in_phase1() { let xudt = xudt_script(&mut context, &ickb_logic); let burn_lock = named_always_success_lock(&mut context, b"owner"); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let deposit_input = context.create_cell( CellOutput::new_builder() @@ -244,7 +244,7 @@ fn limit_order_backed_owner_is_blocked_in_phase1() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &owned_owner, owner_order_data.len(), 1_500 * SHANNONS).pack()) + .capacity(deposit_capacity(&limit_order, &owned_owner, owner_order_data.len(), 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), diff --git a/scripts/tests/src/tests/owned_owner/live_claim_rotation.rs b/scripts/tests/src/tests/owned_owner/live_claim_rotation.rs index 5976511..670b6e2 100644 --- a/scripts/tests/src/tests/owned_owner/live_claim_rotation.rs +++ b/scripts/tests/src/tests/owned_owner/live_claim_rotation.rs @@ -82,8 +82,8 @@ fn live_claims_cannot_rotate_into_new_pairs() { let user2_lock = named_always_success_lock(&mut context, b"user2"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let amount1 = 1_000 * SHANNONS; - let amount2 = 1_100 * SHANNONS; + let amount1 = 1_000 * CKB; + let amount2 = 1_100 * CKB; let total1 = deposit_capacity(&ickb_logic, &dao, 8, amount1); let total2 = deposit_capacity(&ickb_logic, &dao, 8, amount2); let deposit_header1 = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); diff --git a/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs b/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs index 56e9502..de75bbd 100644 --- a/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs +++ b/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs @@ -25,7 +25,7 @@ fn weak_lock_mixed_foreign_and_ickb_batch_can_crosswire_claims() { ); link_cell_to_header(&mut context, &foreign_deposit_input, &foreign_deposit_header); - let protocol_deposit_amount = 1_000 * SHANNONS; + let protocol_deposit_amount = 1_000 * CKB; let protocol_deposit_capacity = deposit_capacity(&ickb_logic, &dao, 8, protocol_deposit_amount); let protocol_deposit_input = context.create_cell( CellOutput::new_builder() diff --git a/scripts/tests/src/tests/owned_owner/owner_distance_encoding.rs b/scripts/tests/src/tests/owned_owner/owner_distance_encoding.rs index 2c84fcd..3e12af9 100644 --- a/scripts/tests/src/tests/owned_owner/owner_distance_encoding.rs +++ b/scripts/tests/src/tests/owned_owner/owner_distance_encoding.rs @@ -10,7 +10,7 @@ fn truncated_owner_distance_output_is_rejected() { let owner_lock = named_always_success_lock(&mut context, b"owner"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let udt_input = context.create_cell( CellOutput::new_builder() @@ -62,7 +62,7 @@ fn zero_length_owner_distance_output_is_rejected_as_encoding() { let owner_lock = named_always_success_lock(&mut context, b"owner"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let udt_input = context.create_cell( CellOutput::new_builder() @@ -114,7 +114,7 @@ fn owner_distance_trailing_bytes_are_ignored() { let owner_lock = named_always_success_lock(&mut context, b"owner"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let udt_input = context.create_cell( CellOutput::new_builder() diff --git a/scripts/tests/src/tests/owned_owner/pair_formation.rs b/scripts/tests/src/tests/owned_owner/pair_formation.rs index 71e9b5e..0ef1ba5 100644 --- a/scripts/tests/src/tests/owned_owner/pair_formation.rs +++ b/scripts/tests/src/tests/owned_owner/pair_formation.rs @@ -8,7 +8,7 @@ fn valid_output_pair_passes() { let owner_lock = named_always_success_lock(&mut context, b"owner"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let deposit_input = context.create_cell( CellOutput::new_builder() @@ -110,7 +110,7 @@ fn two_owner_cells_for_one_owned_output_are_rejected() { let funding_lock = named_always_success_lock(&mut context, b"funding"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let deposit_input = context.create_cell( CellOutput::new_builder() @@ -181,7 +181,7 @@ fn orphan_withdrawal_request_can_be_created_but_not_claimed() { let user_lock = named_always_success_lock(&mut context, b"user"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let deposit_input = context.create_cell( diff --git a/scripts/tests/src/tests/owned_owner/phase1_poisoning.rs b/scripts/tests/src/tests/owned_owner/phase1_poisoning.rs index 1ea8c34..4cf84cf 100644 --- a/scripts/tests/src/tests/owned_owner/phase1_poisoning.rs +++ b/scripts/tests/src/tests/owned_owner/phase1_poisoning.rs @@ -9,7 +9,7 @@ fn unrelated_non_empty_args_output_lock_poisons_withdrawal() { let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); let poisoned_lock = data1_script(&mut context, "owned_owner", Bytes::from(vec![1])); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header, deposit_input, udt_input) = create_withdrawal_inputs( &mut context, &ickb_logic, @@ -65,7 +65,7 @@ fn foreign_typed_output_is_ignored() { let foreign_lock = named_always_success_lock(&mut context, b"foreign-lock"); let foreign_type = named_always_success_lock(&mut context, b"foreign-type"); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header, deposit_input, udt_input) = create_withdrawal_inputs( &mut context, &ickb_logic, @@ -125,7 +125,7 @@ fn owned_shaped_non_empty_args_output_poisons_withdrawal() { let dao = dao_script(&mut context); let xudt = xudt_script(&mut context, &ickb_logic); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header, deposit_input, udt_input) = create_withdrawal_inputs( &mut context, &ickb_logic, @@ -184,7 +184,7 @@ fn non_empty_args_owner_sibling_poisons_withdrawal() { let dao = dao_script(&mut context); let xudt = xudt_script(&mut context, &ickb_logic); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header, deposit_input, udt_input) = create_withdrawal_inputs( &mut context, &ickb_logic, diff --git a/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs b/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs index 5f9045b..574474c 100644 --- a/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs +++ b/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs @@ -10,7 +10,7 @@ fn adjacent_positive_distance_pair_can_complete_phase2_claim() { let filler_lock = named_always_success_lock(&mut context, b"filler"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let funding_input = context.create_cell( @@ -134,7 +134,7 @@ fn sparse_positive_distance_pair_can_complete_phase2_claim_at_exact_capacity() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let funding_input = context.create_cell( diff --git a/scripts/tests/src/tests/owned_owner/script_misuse.rs b/scripts/tests/src/tests/owned_owner/script_misuse.rs index b50873a..3714e7d 100644 --- a/scripts/tests/src/tests/owned_owner/script_misuse.rs +++ b/scripts/tests/src/tests/owned_owner/script_misuse.rs @@ -12,13 +12,13 @@ fn zero_distance_owner_output_is_rejected() { let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), ); let owned_output = CellOutput::new_builder() - .capacity((1_000 * SHANNONS).pack()) + .capacity((1_000 * CKB).pack()) .lock(owned_owner.clone()) .type_(Some(dao).pack()) .build(); @@ -112,13 +112,13 @@ fn non_withdrawal_owned_cell_is_rejected() { let funding_input = context.create_cell( CellOutput::new_builder() - .capacity((2_000 * SHANNONS).pack()) + .capacity((2_000 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), ); let owned_output = CellOutput::new_builder() - .capacity((1_000 * SHANNONS).pack()) + .capacity((1_000 * CKB).pack()) .lock(owned_owner.clone()) .type_(Some(dao).pack()) .build(); @@ -187,13 +187,13 @@ fn lock_only_owned_owner_dao_deposit_output_can_be_created_but_not_spent() { let funding_lock = always_success_lock(&mut context); let owned_owner = owned_owner_script(&mut context); let dao = dao_script(&mut context); - let funding_input = context.create_cell(CellOutput::new_builder().capacity((2_000 * SHANNONS).pack()).lock(funding_lock).build(), Bytes::new()); + let funding_input = context.create_cell(CellOutput::new_builder().capacity((2_000 * CKB).pack()).lock(funding_lock).build(), Bytes::new()); let create_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity((1_000 * SHANNONS).pack()) + .capacity((1_000 * CKB).pack()) .lock(owned_owner.clone()) .type_(Some(dao.clone()).pack()) .build(), @@ -205,7 +205,7 @@ fn lock_only_owned_owner_dao_deposit_output_can_be_created_but_not_spent() { let forged_out_point = context.create_cell( CellOutput::new_builder() - .capacity((1_000 * SHANNONS).pack()) + .capacity((1_000 * CKB).pack()) .lock(owned_owner) .type_(Some(dao).pack()) .build(), @@ -213,7 +213,7 @@ fn lock_only_owned_owner_dao_deposit_output_can_be_created_but_not_spent() { ); let spend_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(forged_out_point).build()) - .output(CellOutput::new_builder().capacity((1_000 * SHANNONS).pack()).lock(always_success_lock(&mut context)).build()) + .output(CellOutput::new_builder().capacity((1_000 * CKB).pack()).lock(always_success_lock(&mut context)).build()) .output_data(Bytes::new().pack()) .build(); let spend_tx = context.complete_tx(spend_tx); diff --git a/scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs b/scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs index 7feb8e4..3184bdf 100644 --- a/scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs +++ b/scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs @@ -9,7 +9,7 @@ fn weak_lock_can_reassign_withdrawal_owner_output() { let attacker_lock = named_always_success_lock(&mut context, b"attacker"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header, deposit_input, udt_input) = create_withdrawal_inputs( &mut context, &ickb_logic, @@ -54,7 +54,7 @@ fn sighash_lock_binds_withdrawal_owner_output_to_the_signed_transaction() { let attacker_lock = named_always_success_lock(&mut context, b"attacker"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header, deposit_input, udt_input) = create_withdrawal_inputs( &mut context, &ickb_logic, @@ -121,8 +121,8 @@ fn mixed_sighash_and_weak_udts_bind_all_withdrawal_outputs_once_signed() { let attacker_lock = named_always_success_lock(&mut context, b"attacker"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let amount1 = 1_000 * SHANNONS; - let amount2 = 1_200 * SHANNONS; + let amount1 = 1_000 * CKB; + let amount2 = 1_200 * CKB; let total1 = deposit_capacity(&ickb_logic, &dao, 8, amount1); let total2 = deposit_capacity(&ickb_logic, &dao, 8, amount2); let header1 = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); @@ -251,8 +251,8 @@ fn two_weak_udts_can_reassign_combined_withdrawal_owner_outputs() { let attacker_lock = named_always_success_lock(&mut context, b"attacker"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let amount1 = 1_000 * SHANNONS; - let amount2 = 1_200 * SHANNONS; + let amount1 = 1_000 * CKB; + let amount2 = 1_200 * CKB; let total1 = deposit_capacity(&ickb_logic, &dao, 8, amount1); let total2 = deposit_capacity(&ickb_logic, &dao, 8, amount2); let header1 = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); diff --git a/scripts/tests/src/tests/owned_owner/withdrawal_amount_and_headers.rs b/scripts/tests/src/tests/owned_owner/withdrawal_amount_and_headers.rs index cc43786..eba9e71 100644 --- a/scripts/tests/src/tests/owned_owner/withdrawal_amount_and_headers.rs +++ b/scripts/tests/src/tests/owned_owner/withdrawal_amount_and_headers.rs @@ -10,7 +10,7 @@ fn withdrawal_accepts_xudt_input_with_trailing_bytes() { let user_lock = always_success_lock(&mut context); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let deposit_input = context.create_cell( CellOutput::new_builder() @@ -66,7 +66,7 @@ fn withdrawal_rejects_short_xudt_input_data() { let user_lock = always_success_lock(&mut context); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let deposit_input = context.create_cell( CellOutput::new_builder() @@ -119,7 +119,7 @@ fn withdrawal_rejects_zero_length_xudt_input_data() { let user_lock = always_success_lock(&mut context); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let deposit_input = context.create_cell( CellOutput::new_builder() @@ -172,7 +172,7 @@ fn withdrawal_without_deposit_header_dep_is_rejected() { let user_lock = always_success_lock(&mut context); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let deposit_input = context.create_cell( CellOutput::new_builder() @@ -223,8 +223,8 @@ fn withdrawal_with_two_deposits_from_distinct_headers_passes() { let user_lock = always_success_lock(&mut context); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let first_amount = 1_000 * SHANNONS; - let second_amount = 1_200 * SHANNONS; + let first_amount = 1_000 * CKB; + let second_amount = 1_200 * CKB; let first_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, first_amount); let second_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, second_amount); let first_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); @@ -309,8 +309,8 @@ fn withdrawal_with_one_missing_deposit_header_dep_is_rejected() { let user_lock = always_success_lock(&mut context); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let first_amount = 1_000 * SHANNONS; - let second_amount = 1_200 * SHANNONS; + let first_amount = 1_000 * CKB; + let second_amount = 1_200 * CKB; let first_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, first_amount); let second_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, second_amount); let first_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); @@ -393,7 +393,7 @@ fn withdrawal_with_zero_accumulated_rate_deposit_header_is_rejected() { let user_lock = always_success_lock(&mut context); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let deposit_amount = 1_000 * SHANNONS; + let deposit_amount = 1_000 * CKB; let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, deposit_amount); let malformed_header = gen_header(1554, 0, 35, 1000, 1000); let deposit_input = context.create_cell( @@ -446,7 +446,7 @@ fn withdrawal_applies_soft_cap_discount_above_boundary() { let owner_lock = named_always_success_lock(&mut context, b"owner"); let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); - let amount = 100_001 * SHANNONS; + let amount = 100_001 * CKB; let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, amount); let deposit_header = gen_header(1554, GENESIS_AR, 35, 1000, 1000); let deposit_input = context.create_cell( diff --git a/scripts/tests/src/tests/replay_helpers.rs b/scripts/tests/src/tests/replay_helpers.rs index 20c01bf..b7084cd 100644 --- a/scripts/tests/src/tests/replay_helpers.rs +++ b/scripts/tests/src/tests/replay_helpers.rs @@ -114,7 +114,7 @@ pub(super) fn rpc_header(number: &str, epoch: &str, dao: &str) -> ckb_testtool:: pub(super) fn soft_capped_ickb(amount: u64, accumulated_rate: u64) -> u128 { let raw = u128::from(amount) * u128::from(GENESIS_AR) / u128::from(accumulated_rate); - let soft_cap = u128::from(100_000 * SHANNONS); + let soft_cap = u128::from(100_000 * CKB); if raw > soft_cap { raw - (raw - soft_cap) / 10 } else { From e5e09a5af8f59e68ca87e65ef966035b4abac7f8 Mon Sep 17 00:00:00 2001 From: phroi <90913182+phroi@users.noreply.github.com> Date: Sat, 26 Sep 2026 15:15:29 +0200 Subject: [PATCH 02/13] test: track the golden-vector generator The stack's testkit checks its TypeScript contract oracle against golden vectors computed by the contracts' own Rust logic. The generator lived only as untracked files in a local checkout, so the stack's fixture could not be regenerated from any commit. vector-gen compiles c256.rs and ickb_logic/constants.rs straight from the contract sources and holds byte-exact copies of the private deposit_to_ickb and validate, which drift_checks asserts are still substrings of their sources. The cases and expected values live in src/vectors.rs so the contract tests can replay them; src/main.rs writes them as JSON. Its output parses to the same data as the stack's committed fixture. The crate stays outside the contracts workspace. Its lockfile uses format 3, since the pinned Rust 1.74 cannot read format 4. --- scripts/vector-gen/Cargo.lock | 65 ++++ scripts/vector-gen/Cargo.toml | 12 + .../vector-gen/src/copied/deposit_to_ickb.rs | 14 + .../src/copied/limit_order_types.rs | 21 ++ .../src/copied/limit_order_validate.rs | 48 +++ scripts/vector-gen/src/main.rs | 76 +++++ scripts/vector-gen/src/vectors.rs | 296 ++++++++++++++++++ 7 files changed, 532 insertions(+) create mode 100644 scripts/vector-gen/Cargo.lock create mode 100644 scripts/vector-gen/Cargo.toml create mode 100644 scripts/vector-gen/src/copied/deposit_to_ickb.rs create mode 100644 scripts/vector-gen/src/copied/limit_order_types.rs create mode 100644 scripts/vector-gen/src/copied/limit_order_validate.rs create mode 100644 scripts/vector-gen/src/main.rs create mode 100644 scripts/vector-gen/src/vectors.rs diff --git a/scripts/vector-gen/Cargo.lock b/scripts/vector-gen/Cargo.lock new file mode 100644 index 0000000..bdc953f --- /dev/null +++ b/scripts/vector-gen/Cargo.lock @@ -0,0 +1,65 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "uint", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "vector-gen" +version = "0.1.0" +dependencies = [ + "primitive-types", +] diff --git a/scripts/vector-gen/Cargo.toml b/scripts/vector-gen/Cargo.toml new file mode 100644 index 0000000..f453863 --- /dev/null +++ b/scripts/vector-gen/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "vector-gen" +version = "0.1.0" +edition = "2021" + +# Standalone on purpose: the empty [workspace] table keeps this generator out of +# the contracts workspace in ../Cargo.toml. The contract tests include its +# src/vectors.rs directly, so the vectors have one definition. +[workspace] + +[dependencies] +primitive-types = { version = "0.12.2", default-features = false } diff --git a/scripts/vector-gen/src/copied/deposit_to_ickb.rs b/scripts/vector-gen/src/copied/deposit_to_ickb.rs new file mode 100644 index 0000000..c7673ca --- /dev/null +++ b/scripts/vector-gen/src/copied/deposit_to_ickb.rs @@ -0,0 +1,14 @@ +fn deposit_to_ickb(index: usize, source: Source, amount: u64) -> Result { + let amount = u128::from(amount); + let ar_0 = GENESIS_ACCUMULATED_RATE; + let ar_m = u128::from(extract_accumulated_rate(index, source)?); + + let ickb_amount = amount * ar_0 / ar_m; + + // Apply a 10% discount for the amount exceeding the soft iCKB cap per deposit + if ickb_amount > ICKB_SOFT_CAP_PER_DEPOSIT { + return Ok(ickb_amount - (ickb_amount - ICKB_SOFT_CAP_PER_DEPOSIT) / 10); + } + + Ok(ickb_amount) +} diff --git a/scripts/vector-gen/src/copied/limit_order_types.rs b/scripts/vector-gen/src/copied/limit_order_types.rs new file mode 100644 index 0000000..5956f34 --- /dev/null +++ b/scripts/vector-gen/src/copied/limit_order_types.rs @@ -0,0 +1,21 @@ +#[derive(Clone, Copy, PartialEq)] +struct Data { + ckb: C256, + udt: C256, + ckb_unoccupied: C256, + info: Info, +} + +#[derive(Clone, Copy, PartialEq)] +struct Info { + udt_hash: [u8; 32], + ckb_to_udt: Option, + udt_to_ckb: Option, + ckb_min_match: C256, +} + +#[derive(Clone, Copy, PartialEq)] +struct Ratio { + ckb_mul: C256, + udt_mul: C256, +} diff --git a/scripts/vector-gen/src/copied/limit_order_validate.rs b/scripts/vector-gen/src/copied/limit_order_validate.rs new file mode 100644 index 0000000..fb84168 --- /dev/null +++ b/scripts/vector-gen/src/copied/limit_order_validate.rs @@ -0,0 +1,48 @@ +fn validate(i: Data, o: Data) -> Result<(), Error> { + if i.info != o.info { + return Err(Error::DifferentInfo); + } + + let (is_ckb_to_udt, Ratio { ckb_mul, udt_mul }, ckb_min_match) = match ( + i.info.ckb_to_udt, + i.ckb > o.ckb, + i.info.udt_to_ckb, + i.udt > o.udt, + ) { + (Some(ratio), true, _, false) => (true, ratio, i.info.ckb_min_match), + (_, false, Some(ratio), true) => (false, ratio, i.info.ckb_min_match), + _ => return Err(Error::InvalidMatch), + }; + + // Check that limit order does not lose value + if i.ckb * ckb_mul + i.udt * udt_mul > o.ckb * ckb_mul + o.udt * udt_mul { + return Err(Error::DecreasingValue); + } + + // Validate limit order match + if is_ckb_to_udt { + // CKB -> UDT + // Check that an already fulfilled order is not modified + if i.ckb_unoccupied.is_zero() { + return Err(Error::AttemptToChangeFulfilled); + } + + // DOS prevention: disallow partial match lower than the equivalent of ckb_min_match + if !o.ckb_unoccupied.is_zero() && i.ckb < o.ckb + ckb_min_match { + return Err(Error::InsufficientMatch); + } + } else { + // UDT -> CKB + // Check that an already fulfilled order is not modified + if i.udt.is_zero() { + return Err(Error::AttemptToChangeFulfilled); + } + + // DOS prevention: disallow partial match lower than the equivalent of ckb_min_match + if !o.udt.is_zero() && i.udt * udt_mul < o.udt * udt_mul + ckb_min_match * ckb_mul { + return Err(Error::InsufficientMatch); + } + } + + Ok(()) +} diff --git a/scripts/vector-gen/src/main.rs b/scripts/vector-gen/src/main.rs new file mode 100644 index 0000000..62b5f48 --- /dev/null +++ b/scripts/vector-gen/src/main.rs @@ -0,0 +1,76 @@ +//! Golden protocol vector generator for the iCKB stack testkit: writes the rows +//! of `vectors.rs` as JSON. +//! +//! Usage: cargo run --release -- + +mod vectors; + +use vectors::{limit_order, DepositRow, LimitRow}; + +fn json_str(s: &str) -> &str { + assert!( + s.chars().all(|c| c.is_ascii() && c != '"' && c != '\\'), + "string needs JSON escaping: {s}" + ); + s +} + +fn ratio_json(r: Option<(u64, u64)>) -> String { + match r { + Some((c, u)) => format!("{{\"ckbMul\": \"{c}\", \"udtMul\": \"{u}\"}}"), + None => "null".into(), + } +} + +fn side_json((ckb, udt, unoccupied): limit_order::Side) -> String { + format!("{{\"ckb\": \"{ckb}\", \"udt\": \"{udt}\", \"ckbUnoccupied\": \"{unoccupied}\"}}") +} + +fn main() { + vectors::drift_checks(); + + let deposit_json: Vec = vectors::deposit_rows() + .iter() + .map(|DepositRow { ar, amount, expected_ickb, note }| { + format!( + " {{\"arDecimal\": \"{ar}\", \"unoccupiedShannons\": \"{amount}\", \"expectedIckb\": \"{expected_ickb}\", \"note\": \"{}\"}}", + json_str(note) + ) + }) + .collect(); + + let limit_json: Vec = vectors::limit_rows() + .iter() + .map(|row| { + let LimitRow { ckb_to_udt, udt_to_ckb, ckb_min_match_log: log, input, output, verdict, note } = row; + let verdict = match verdict { + Ok(()) => "ok".into(), + Err(e) => format!("{e:?}"), + }; + format!( + " {{\"ckbToUdt\": {}, \"udtToCkb\": {}, \"ckbMinMatchLog\": {log}, \"input\": {}, \"output\": {}, \"verdict\": \"{verdict}\", \"note\": \"{}\"}}", + ratio_json(*ckb_to_udt), + ratio_json(*udt_to_ckb), + side_json(*input), + side_json(*output), + json_str(note) + ) + }) + .collect(); + + let out = format!( + "{{\n \"depositToIckb\": [\n{}\n ],\n \"limitOrderMatch\": [\n{}\n ]\n}}\n", + deposit_json.join(",\n"), + limit_json.join(",\n") + ); + + let path = std::env::args() + .nth(1) + .unwrap_or_else(|| "protocol_vectors.json".into()); + std::fs::write(&path, out).expect("failed to write output"); + println!( + "wrote {} depositToIckb rows and {} limitOrderMatch rows to {path}", + deposit_json.len(), + limit_json.len() + ); +} diff --git a/scripts/vector-gen/src/vectors.rs b/scripts/vector-gen/src/vectors.rs new file mode 100644 index 0000000..b42b08a --- /dev/null +++ b/scripts/vector-gen/src/vectors.rs @@ -0,0 +1,296 @@ +//! The golden protocol vectors: the cases and the values the contracts' own Rust +//! logic gives them. Shared by the JSON writer (`main.rs`) and the contract tests, +//! which replay its rows against the release binaries (`scripts/tests`). +//! +//! Provenance: `c256.rs` and `ickb_logic/constants.rs` are compiled directly from +//! the contract sources via `#[path]`. `deposit_to_ickb` and `validate` are +//! private, syscall-bound functions, so they are included as byte-exact verbatim +//! copies (src/copied/*); `drift_checks` asserts each copy is still a substring of +//! its source file. + +// Contract source compiled directly (not copied). +#[allow(dead_code)] +#[path = "../../contracts/utils/src/c256.rs"] +mod c256; + +// Contract source compiled directly (not copied). +#[allow(dead_code)] +#[path = "../../contracts/ickb_logic/src/constants.rs"] +mod ickb_constants; + +/// iCKB deposit conversion, around the verbatim copy of `deposit_to_ickb` +/// (scripts/contracts/ickb_logic/src/entry.rs lines 71-84). +pub mod ickb { + use super::ickb_constants::ICKB_SOFT_CAP_PER_DEPOSIT; + + // Verbatim value from scripts/contracts/utils/src/constants.rs + // (that file cannot be #[path]-included: it depends on ckb-std). + // Drift-checked by substring in drift_checks(). + pub const GENESIS_ACCUMULATED_RATE: u128 = 10_000_000_000_000_000; // 10^16 Genesis block accumulated rate + + #[derive(Debug)] + pub enum Error {} + + // Off-chain stand-in: on-chain, `extract_accumulated_rate(index, source)` + // reads AR_m from the deposit's header dep. Here the Source carries it. + #[derive(Clone, Copy)] + pub struct Source { + pub ar: u64, + } + + fn extract_accumulated_rate(_index: usize, source: Source) -> Result { + Ok(source.ar) + } + + include!("copied/deposit_to_ickb.rs"); + + pub fn compute(ar: u64, amount: u64) -> u128 { + deposit_to_ickb(0, Source { ar }, amount).unwrap() + } +} + +/// Limit order match validation, around the verbatim copies of `validate` and +/// the order data types (scripts/contracts/limit_order/src/entry.rs lines +/// 86-133 and 141-161). +pub mod limit_order { + use super::c256::C256; + + // Same variant names as scripts/contracts/limit_order/src/error.rs + // (name presence drift-checked in drift_checks()); only the variants reachable + // from `validate` are needed here. + #[derive(Debug, PartialEq)] + pub enum Error { + DifferentInfo, + InvalidMatch, + DecreasingValue, + AttemptToChangeFulfilled, + InsufficientMatch, + } + + include!("copied/limit_order_types.rs"); + include!("copied/limit_order_validate.rs"); + + /// (ckb capacity, udt amount, unoccupied ckb) of one order cell. + pub type Side = (u64, u128, u64); + + pub fn run( + c2u: Option<(u64, u64)>, + u2c: Option<(u64, u64)>, + min_log: u8, + i: Side, + o: Side, + ) -> Result<(), Error> { + assert!(min_log <= 64, "ckb_min_match_log out of the parser's 0..=64 range"); + let ratio = |r: Option<(u64, u64)>| { + r.map(|(ckb_mul, udt_mul)| Ratio { + ckb_mul: C256::from(ckb_mul), + udt_mul: C256::from(udt_mul), + }) + }; + let info = Info { + udt_hash: [0u8; 32], + ckb_to_udt: ratio(c2u), + udt_to_ckb: ratio(u2c), + // Same computation as the order parser: `n @ 0..=64 => C256::from(1u128 << n)` + ckb_min_match: C256::from(1u128 << min_log), + }; + let data = |(ckb, udt, unoccupied): Side| Data { + ckb: C256::from(ckb), + udt: C256::from(udt), + ckb_unoccupied: C256::from(unoccupied), + info, + }; + validate(data(i), data(o)) + } +} + +use ickb_constants::{ + CKB_MAXIMUM_UNOCCUPIED_CAPACITY_PER_DEPOSIT as MAX_DEPOSIT, + CKB_MINIMUM_UNOCCUPIED_CAPACITY_PER_DEPOSIT as MIN_DEPOSIT, ICKB_SOFT_CAP_PER_DEPOSIT, +}; + +const STD_DEPOSIT: u64 = 100_000 * 100_000_000; // 100_000 CKB, the standard deposit size +const CKB_250K: u64 = 250_000 * 100_000_000; // mid discount region + +const AR_GENESIS: u64 = 10_000_000_000_000_000; +const AR_105: u64 = 10_500_000_000_000_000; // realistic 1.05e16 +const AR_118: u64 = 11_800_000_000_000_000; // realistic 1.18e16 + +/// Largest unoccupied capacity whose conversion at `ar` stays at or under the +/// soft cap (so it takes no discount); +1 shannon crosses the cap. +fn softcap_boundary(ar: u64) -> u64 { + let ar0 = ickb::GENESIS_ACCUMULATED_RATE; + let x = ((ICKB_SOFT_CAP_PER_DEPOSIT + 1) * u128::from(ar) - 1) / ar0; + let x = u64::try_from(x).unwrap(); + assert!(u128::from(x) * ar0 / u128::from(ar) <= ICKB_SOFT_CAP_PER_DEPOSIT); + assert!(u128::from(x + 1) * ar0 / u128::from(ar) > ICKB_SOFT_CAP_PER_DEPOSIT); + x +} + +pub fn drift_checks() { + let ickb_entry = include_str!("../../contracts/ickb_logic/src/entry.rs"); + assert!( + ickb_entry.contains(include_str!("copied/deposit_to_ickb.rs").trim_end()), + "copied deposit_to_ickb drifted from ickb_logic/src/entry.rs" + ); + let lo_entry = include_str!("../../contracts/limit_order/src/entry.rs"); + assert!( + lo_entry.contains(include_str!("copied/limit_order_validate.rs").trim_end()), + "copied validate drifted from limit_order/src/entry.rs" + ); + assert!( + lo_entry.contains(include_str!("copied/limit_order_types.rs").trim_end()), + "copied order types drifted from limit_order/src/entry.rs" + ); + assert!( + include_str!("../../contracts/utils/src/constants.rs") + .contains("pub const GENESIS_ACCUMULATED_RATE: u128 = 10_000_000_000_000_000;"), + "GENESIS_ACCUMULATED_RATE drifted from utils/src/constants.rs" + ); + let lo_errors = include_str!("../../contracts/limit_order/src/error.rs"); + for variant in [ + "DifferentInfo", + "InvalidMatch", + "DecreasingValue", + "AttemptToChangeFulfilled", + "InsufficientMatch", + ] { + assert!(lo_errors.contains(variant), "Error variant {variant} missing from limit_order/src/error.rs"); + } +} + + +/// One `depositToIckb` vector: a receipt of `amount` unoccupied shannons at `ar`. +pub struct DepositRow { + pub ar: u64, + pub amount: u64, + pub expected_ickb: u128, + pub note: String, +} + +/// One `limitOrderMatch` vector and the verdict of the copied `validate`. +pub struct LimitRow { + pub ckb_to_udt: Option<(u64, u64)>, + pub udt_to_ckb: Option<(u64, u64)>, + pub ckb_min_match_log: u8, + pub input: limit_order::Side, + pub output: limit_order::Side, + pub verdict: Result<(), limit_order::Error>, + pub note: &'static str, +} + +pub fn deposit_rows() -> Vec { + rows().0 +} + +pub fn limit_rows() -> Vec { + rows().1 +} + +fn rows() -> (Vec, Vec) { + // ---------------- depositToIckb ---------------- + let mut deposit_rows: Vec<(u64, u64, String)> = Vec::new(); + for (ar, ar_note) in [ + (AR_GENESIS, "genesis AR 1e16 (identity)"), + (AR_105, "AR 1.05e16"), + (AR_118, "AR 1.18e16"), + ] { + let boundary = softcap_boundary(ar); + for (amount, note) in [ + (MIN_DEPOSIT, "minimum deposit bound, 1000 CKB unoccupied"), + (5 * MIN_DEPOSIT, "mid-range 5000 CKB"), + (STD_DEPOSIT, "standard 100k CKB deposit"), + (boundary, "soft-cap boundary: largest amount with no discount"), + (boundary + 1, "one shannon past the soft-cap boundary"), + (CKB_250K, "mid discount region, 250k CKB"), + (MAX_DEPOSIT, "maximum deposit bound, 1M CKB unoccupied"), + ] { + deposit_rows.push((ar, amount, format!("{note} at {ar_note}"))); + } + } + deposit_rows.push(( + AR_GENESIS + 1, + STD_DEPOSIT, + "AR one above genesis: floor drops one shannon".into(), + )); + deposit_rows.push((2 * AR_GENESIS, STD_DEPOSIT, "doubled AR halves iCKB for standard deposit".into())); + deposit_rows.push((2 * AR_GENESIS, MAX_DEPOSIT, "doubled AR, max deposit, discount region".into())); + + // ---------------- limitOrderMatch ---------------- + // (ckb_to_udt, udt_to_ckb, ckb_min_match_log, input, output, note) + type LRow = ( + Option<(u64, u64)>, + Option<(u64, u64)>, + u8, + limit_order::Side, + limit_order::Side, + &'static str, + ); + #[rustfmt::skip] + let limit_rows: Vec = vec![ + // ckb2udt basics, ratio 2:1, min-match log 10 (1024), occupied 100 + (Some((2, 1)), None, 10, (10_100, 0, 10_000), (8_076, 4_048, 7_976), "ckb2udt 2:1 equal-value partial match"), + (Some((2, 1)), None, 10, (10_100, 0, 10_000), (8_076, 4_047, 7_976), "ckb2udt: one udt shannon short of equal value"), + (Some((2, 1)), None, 10, (10_100, 0, 10_000), (8_076, 4_049, 7_976), "ckb2udt: matcher overpays one udt shannon"), + (Some((2, 1)), None, 10, (10_100, 0, 10_000), (9_076, 2_048, 8_976), "ckb2udt: partial match exactly at ckb_min_match 1024"), + (Some((2, 1)), None, 10, (10_100, 0, 10_000), (9_077, 2_046, 8_977), "ckb2udt: one shannon below ckb_min_match"), + (Some((2, 1)), None, 10, (200, 0, 100), (100, 200, 0), "ckb2udt: below-min final fill allowed when output is fulfilled"), + (Some((2, 1)), None, 10, (10_100, 4_048, 0), (10_000, 4_248, 0), "ckb2udt: value-preserving change of fulfilled order rejected"), + (Some((2, 1)), None, 10, (201, 0, 1), (200, 2, 0), "ckb2udt: single-shannon completion of nearly fulfilled order"), + (Some((2, 1)), None, 10, (10_100, 0, 0), (10_000, 100, 0), "check order: DecreasingValue precedes AttemptToChangeFulfilled"), + // udt2ckb basics, ratio 1:1, min-match log 10, occupied 100 + (None, Some((1, 1)), 10, (10_100, 50_000, 10_000), (30_100, 30_000, 30_000), "udt2ckb 1:1 equal-value partial match"), + (None, Some((1, 1)), 10, (10_100, 50_000, 10_000), (30_099, 30_000, 29_999), "udt2ckb: one ckb shannon short of equal value"), + (None, Some((1, 1)), 10, (10_100, 50_000, 10_000), (11_124, 48_976, 11_024), "udt2ckb: udt moved exactly the min-match equivalent 1024"), + (None, Some((1, 1)), 10, (10_100, 50_000, 10_000), (11_123, 48_977, 11_023), "udt2ckb: one udt below the min-match equivalent"), + (None, Some((1, 1)), 10, (200, 10, 100), (210, 0, 110), "udt2ckb: below-min final fill allowed when udt is exhausted"), + (None, Some((1, 1)), 10, (10_000, 0, 9_900), (10_100, 0, 10_000), "fulfilled udt2ckb: udt=0 matches no direction arm, so InvalidMatch, never AttemptToChangeFulfilled"), + // C1 counterexample: ratio 2:1, min-match log 3 (8) + (Some((2, 1)), None, 3, (1_100, 0, 1_000), (1_098, 4, 998), "C1: moving 2 ckb is below ckb_min_match 8"), + (Some((2, 1)), None, 3, (1_100, 0, 1_000), (1_092, 16, 992), "C1: correct minimum, 8 ckb for 16 udt"), + // asymmetric small ratio 2:3, min-match log 10 -> udt threshold ceil(2048/3) = 683 + (None, Some((2, 3)), 10, (10_100, 10_000, 10_000), (11_125, 9_317, 11_025), "asymmetric 2:3: 683 udt meets the min-match equivalent"), + (None, Some((2, 3)), 10, (10_100, 10_000, 10_000), (11_123, 9_318, 11_023), "asymmetric 2:3: 682 udt is one below the min-match equivalent"), + // asymmetric large multipliers (1e9 scale), min-match log 0 + (Some((1_000_000_007, 730_000_001)), None, 0, (10_000_000_000, 0, 9_999_999_900), (9_269_999_999, 1_000_000_007, 9_269_999_899), "large multipliers: exact equal value ckb2udt"), + (Some((1_000_000_007, 730_000_001)), None, 0, (10_000_000_000, 0, 9_999_999_900), (9_269_999_999, 1_000_000_006, 9_269_999_899), "large multipliers: one udt shannon short"), + (None, Some((999_983, 1_299_709)), 0, (10_000_000_000, 2_000_000, 9_999_999_900), (10_001_299_709, 1_000_017, 10_001_299_609), "large multipliers: exact equal value udt2ckb"), + // 256-bit regime: udt near u128 max, value products exceed u128 + (None, Some((1_000, 1_000_000_000_000_000)), 0, (10_000, 330_000_000_000_000_000_000_000_000_000_000_000_000, 9_900), (1_000_000_000_010_000, 329_999_999_999_999_999_999_999_999_999_999_999_000, 1_000_000_000_009_900), "256-bit regime: value products exceed u128, C256 stays exact"), + (None, Some((1_000, 1_000_000_000_000_000)), 0, (10_000, 330_000_000_000_000_000_000_000_000_000_000_000_000, 9_900), (1_000_000_000_009_999, 329_999_999_999_999_999_999_999_999_999_999_999_000, 1_000_000_000_009_899), "256-bit regime: one ckb shannon short"), + // dual-ratio orders: ckb_to_udt 2:1 and udt_to_ckb 1:1, min-match log 0 + (Some((2, 1)), Some((1, 1)), 0, (1_100, 0, 1_000), (1_000, 150, 900), "dual ratio: ckb-decrease priced by ckb_to_udt 2:1, 150 udt insufficient"), + (Some((2, 1)), Some((1, 1)), 0, (1_100, 0, 1_000), (1_000, 200, 900), "dual ratio: 200 udt satisfies ckb_to_udt 2:1"), + (Some((2, 1)), Some((1, 1)), 0, (1_100, 300, 1_000), (1_160, 200, 1_060), "dual ratio: udt-decrease priced by udt_to_ckb 1:1, 60 ckb insufficient though 2:1 would pass"), + (Some((2, 1)), Some((1, 1)), 0, (1_100, 300, 1_000), (1_200, 200, 1_100), "dual ratio: udt_to_ckb side exact equal value"), + // invalid configurations + (None, Some((1, 1)), 10, (1_100, 0, 1_000), (1_000, 100, 900), "sell-ckb move against a udt2ckb-only order"), + (Some((1, 1)), None, 10, (1_000, 100, 900), (1_100, 0, 1_000), "sell-udt move against a ckb2udt-only order"), + (Some((1, 1)), Some((1, 1)), 10, (1_100, 100, 1_000), (1_100, 100, 1_000), "no-op match rejected"), + (Some((1, 1)), Some((1, 1)), 10, (1_100, 100, 1_000), (1_000, 50, 900), "both sides decrease"), + (Some((1, 1)), Some((1, 1)), 10, (1_000, 50, 900), (1_100, 100, 1_000), "both sides increase"), + // min-match log extremes + (Some((1, 1)), None, 64, (2_000, 0, 1_900), (1_000, 1_000, 900), "min-match log 64: any partial ckb2udt is insufficient"), + (Some((1, 1)), None, 64, (2_000, 0, 1_900), (100, 1_900, 0), "min-match log 64: completion bypasses the check"), + (Some((1, 1)), None, 0, (1_100, 0, 1_000), (1_099, 1, 999), "min-match log 0: single-shannon partial match allowed"), + ]; + + + let deposits = deposit_rows + .into_iter() + .map(|(ar, amount, note)| DepositRow { ar, amount, expected_ickb: ickb::compute(ar, amount), note }) + .collect(); + let limits = limit_rows + .into_iter() + .map(|(ckb_to_udt, udt_to_ckb, ckb_min_match_log, input, output, note)| LimitRow { + ckb_to_udt, + udt_to_ckb, + ckb_min_match_log, + input, + output, + verdict: limit_order::run(ckb_to_udt, udt_to_ckb, ckb_min_match_log, input, output), + note, + }) + .collect(); + (deposits, limits) +} From 35bf3ada89d8b618ab3dfccb4c10e145d79752fb Mon Sep 17 00:00:00 2001 From: phroi <90913182+phroi@users.noreply.github.com> Date: Sat, 26 Sep 2026 15:15:33 +0200 Subject: [PATCH 03/13] test: fixtures hold consensus-valid cells, checked on every verify ckb-testtool runs scripts only, so fixtures could build cells or withdrawals a node would reject and still pass. Many did: order cells were sized for 73 bytes of order data instead of 89, xUDT cells sat 26 CKB below their occupied capacity, owner, master and funding cells held a few hundred shannons, and named locks carried args longer than any real lock. What those tests showed depended on the fixture rather than on the scripts. Tests now verify through VerifyRealistic::verify. It asserts every input and output holds at least its occupied capacity, and, for transactions the scripts accept, the node's DaoScriptSizeVerifier rule that a deposit and its withdrawal request use locks of the same size. Self-tests show both checks fire. The fixtures follow: - typed cells take occupied_capacity(lock, type, data length); - CKB amounts written in shannons become CKB; - named locks take a secp lock's 20-byte args, so mainnet replay capacities fit; - DAO transactions whose outputs exceed their inputs gain a funding input, appended so input and output indices still pair; - foreign deposits wrapped by Owned Owner use a lock of its size. Existing tests now state what real cells show: - a terminal CKB->UDT fill passes at exact occupied capacity; - a fulfilled order continuation fails as InvalidMatch; - a lock-only order returns the typed MissingUdtType, where the undersized fixtures had trapped with -1; - two cloned live orders permuted in a match strand neither master; - the real-order stranding uses a foreign-token fake order; - the spread-path test follows one verified trajectory from receipt to claim. --- scripts/tests/README.md | 2 + scripts/tests/src/tests.rs | 112 ++++++++- scripts/tests/src/tests/fixtures.rs | 35 ++- .../tests/ickb_logic/creation_blind_spots.rs | 24 +- .../tests/ickb_logic/dao_phase2_batching.rs | 12 +- .../src/tests/ickb_logic/deposit_bounds.rs | 16 +- .../tests/ickb_logic/economic_precision.rs | 215 ++++++++++-------- .../ickb_logic/mixed_flow_composition.rs | 26 +-- .../ickb_logic/multi_quantity_receipts.rs | 10 +- .../src/tests/ickb_logic/phase2_headers.rs | 28 +-- .../ickb_logic/phase2_recipient_binding.rs | 34 +-- .../phase2_sibling_classification.rs | 60 ++--- .../ickb_logic/phase2_xudt_output_data.rs | 18 +- .../src/tests/ickb_logic/receipt_encoding.rs | 16 +- .../src/tests/ickb_logic/receipt_matching.rs | 12 +- .../receiptless_deposit_blind_spot.rs | 119 +++++++--- .../tests/src/tests/ickb_logic/soft_cap.rs | 36 +-- .../tests/ickb_logic/xudt_amount_limits.rs | 12 +- .../ickb_logic/xudt_owner_witness_fallback.rs | 10 +- .../tests/limit_order/crosswire_blockers.rs | 14 +- .../tests/limit_order/crosswire_live_match.rs | 29 +-- .../limit_order/crosswire_mint_creation.rs | 28 +-- .../tests/limit_order/fake_match_lineage.rs | 68 +++++- .../tests/src/tests/limit_order/fulfilled.rs | 20 +- .../src/tests/limit_order/lock_only_shapes.rs | 26 +-- .../src/tests/limit_order/master_admission.rs | 12 +- .../tests/limit_order/match_progression.rs | 85 +++---- .../limit_order/mint_shape_validation.rs | 14 +- .../src/tests/limit_order/phantom_lineage.rs | 18 +- .../tests/src/tests/limit_order/poisoning.rs | 24 +- .../src/tests/limit_order/real_lineage.rs | 6 +- scripts/tests/src/tests/limit_order/remint.rs | 10 +- .../src/tests/limit_order/same_master.rs | 18 +- .../src/tests/owned_owner/dao_crosswiring.rs | 47 ++-- .../tests/owned_owner/foreign_dao_wrapping.rs | 13 +- .../foreign_owner_lock_boundaries.rs | 22 +- .../tests/owned_owner/live_claim_rotation.rs | 21 +- .../owned_owner/melt_pairing_and_witness.rs | 38 ++-- .../owned_owner/mixed_asset_crosswiring.rs | 18 +- .../owned_owner/owner_distance_encoding.rs | 18 +- .../src/tests/owned_owner/pair_formation.rs | 32 +-- .../src/tests/owned_owner/phase1_poisoning.rs | 23 +- .../owned_owner/positive_distance_claims.rs | 24 +- .../src/tests/owned_owner/script_misuse.rs | 34 +-- .../owned_owner/weak_lock_output_rebinding.rs | 38 ++-- .../withdrawal_amount_and_headers.rs | 59 ++--- .../replay/family_attacker_limit_order.rs | 8 +- .../replay/family_mainnet_eight_claim.rs | 8 +- .../src/tests/replay/family_mixed_restake.rs | 8 +- .../tests/replay/family_two_claim_restake.rs | 8 +- .../src/tests/replay/lineage_21ccbca0.rs | 6 +- .../src/tests/replay/lineage_30f8ed8a.rs | 4 +- .../src/tests/replay/lineage_86d442e2.rs | 8 +- .../src/tests/replay/lineage_b866945c.rs | 9 +- .../src/tests/replay/lineage_b923f354.rs | 4 +- scripts/tests/src/tests/replay/tx_5f6d0d5b.rs | 2 +- scripts/tests/src/tests/replay/tx_9df44c51.rs | 2 +- scripts/tests/src/tests/signing.rs | 10 +- 58 files changed, 935 insertions(+), 698 deletions(-) diff --git a/scripts/tests/README.md b/scripts/tests/README.md index ed6973a..fd6aeb0 100644 --- a/scripts/tests/README.md +++ b/scripts/tests/README.md @@ -12,3 +12,5 @@ Some replay tests intentionally rebuild live transaction shapes instead of minimizing the fixture. Those cases keep the audit claims tied to realistic batching, witness layout, header dependencies, and cross-script interaction patterns. Current strong-lock coverage is direct for `secp256k1_blake160_sighash_all`, which the signed-flow tests use as the representative whole-transaction-binding lock. This repo does not include a `QRL` fixture or harness, so conclusions for other strong-lock deployments rely on the same binding property and deployment assumptions rather than a separate replay in this suite. + +`ckb-testtool`'s `Context::verify_tx` executes `OutputsDataVerifier`, which checks that the output and output-data counts match, and then executes the transaction scripts through `TransactionScriptsVerifier`. It does not run the full node non-contextual or contextual transaction verifiers, so it does not establish checks such as occupied capacity, `since`, or cellbase maturity. Tests therefore verify through `VerifyRealistic::verify` in `src/tests.rs`, which first holds every input and output to its occupied capacity and then holds every accepted DAO withdrawal to the node's lock-size rule, so no fixture builds a cell or withdrawal the node would reject. Other consensus-level conclusions rely on CKB source evidence rather than `Context::verify_tx` alone. diff --git a/scripts/tests/src/tests.rs b/scripts/tests/src/tests.rs index f031d74..d3ed784 100644 --- a/scripts/tests/src/tests.rs +++ b/scripts/tests/src/tests.rs @@ -26,6 +26,100 @@ use fixtures::*; use replay_helpers::*; use signing::*; +// ckb-testtool runs scripts only, so a fixture could build a cell consensus rejects and still pass. +// Tests verify through this check, which first holds every input and output to its occupied capacity. +trait VerifyRealistic { + fn verify(&self, tx: &TransactionView, max_cycles: u64) -> Result; +} + +impl VerifyRealistic for Context { + fn verify(&self, tx: &TransactionView, max_cycles: u64) -> Result { + let check = |side: &str, index: usize, cell: &CellOutput, data_len: usize| { + let occupied = cell + .occupied_capacity(ckb_testtool::ckb_types::core::Capacity::bytes(data_len).expect("data length")) + .expect("occupied capacity") + .as_u64(); + let capacity: u64 = cell.capacity().unpack(); + assert!( + capacity >= occupied, + "{side} {index} holds {capacity} shannons, below its occupied capacity {occupied}" + ); + }; + for (index, input) in tx.inputs().into_iter().enumerate() { + if let Some((cell, data)) = self.get_cell(&input.previous_output()) { + check("input", index, &cell, data.len()); + } + } + for (index, (cell, data)) in tx.outputs().into_iter().zip(tx.outputs_data()).enumerate() { + check("output", index, &cell, data.raw_data().len()); + } + let cycles = self.verify_tx(tx, max_cycles)?; + // A transaction the scripts accept must also pass the node's DaoScriptSizeVerifier: a + // deposit and the withdrawal request at its index use locks of the same serialized size. + let dao_code_hash = build_genesis_type_id_script(OUTPUT_INDEX_DAO).calc_script_hash(); + let is_dao = |cell: &CellOutput| { + cell.type_().to_opt().map_or(false, |script| { + script.code_hash() == dao_code_hash && script.hash_type() == ScriptHashType::Type.into() + }) + }; + for (index, (input, output)) in tx.inputs().into_iter().zip(tx.outputs()).enumerate() { + let Some((deposit, data)) = self.get_cell(&input.previous_output()) else { + continue; + }; + if is_dao(&deposit) && is_dao(&output) && data.iter().all(|byte| *byte == 0) { + assert_eq!( + deposit.lock().total_size(), + output.lock().total_size(), + "DAO output {index} changes the lock size of the deposit it withdraws" + ); + } + } + Ok(cycles) + } +} + +#[test] +#[should_panic(expected = "below its occupied capacity")] +fn verify_rejects_a_cell_below_its_occupied_capacity() { + let mut context = Context::default(); + let lock = always_success_lock(&mut context); + let input = context.create_cell( + CellOutput::new_builder().capacity((1_000 * CKB).pack()).lock(lock.clone()).build(), + Bytes::new(), + ); + let tx = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(input).build()) + .output(CellOutput::new_builder().capacity((40 * CKB).pack()).lock(lock).build()) + .output_data(Bytes::new().pack()) + .build(); + let tx = context.complete_tx(tx); + let _ = context.verify(&tx, MAX_CYCLES); +} + +#[test] +#[should_panic(expected = "changes the lock size of the deposit it withdraws")] +fn verify_rejects_a_withdrawal_request_whose_lock_size_differs() { + let mut context = Context::default(); + let deposit_lock = named_always_success_lock(&mut context, b"depositor"); + let request_lock = always_success_lock(&mut context); + let dao = dao_script(&mut context); + let capacity = 1_000 * CKB; + let deposit = context.create_cell( + CellOutput::new_builder().capacity(capacity.pack()).lock(deposit_lock).type_(Some(dao.clone()).pack()).build(), + dao_deposit_data(), + ); + let header = gen_header(1554, GENESIS_AR, 35, 1000, 1000); + link_cell_to_header(&mut context, &deposit, &header); + let tx = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(deposit).build()) + .output(CellOutput::new_builder().capacity(capacity.pack()).lock(request_lock).type_(Some(dao).pack()).build()) + .output_data(withdrawal_request_data(1554).pack()) + .header_dep(header.hash()) + .build(); + let tx = context.complete_tx(tx); + let _ = context.verify(&tx, MAX_CYCLES); +} + // Shared test constants and on-chain error codes. const MAX_CYCLES: u64 = 10_000_000; const CKB: u64 = 100_000_000; @@ -46,6 +140,7 @@ const ERROR_LENGTH_NOT_ENOUGH: i8 = 3; const ERROR_AMOUNT_MISMATCH: i8 = 11; const ERROR_AMOUNT_UNREASONABLY_BIG: i8 = 12; const ERROR_DAO_INVALID_WITHDRAW_BLOCK: i8 = -14; +const ERROR_DAO_INVALID_WITHDRAWING_CELL: i8 = -20; const ERROR_DAO_INCORRECT_CAPACITY: i8 = -15; const ERROR_LIMIT_ORDER_INVALID_CONFIGURATION: i8 = 21; const ERROR_LIMIT_ORDER_DIFFERENT_INFO: i8 = 16; @@ -59,6 +154,7 @@ const ERROR_LIMIT_ORDER_INVALID_RATIO: i8 = 9; const ERROR_LIMIT_ORDER_INVALID_CKB_MIN_MATCH_LOG: i8 = 10; const ERROR_LIMIT_ORDER_CONCAVE_RATIO: i8 = 11; const ERROR_LIMIT_ORDER_BOTH_RATIOS_NULL: i8 = 12; +const ERROR_LIMIT_ORDER_MISSING_UDT_TYPE: i8 = 13; const ERROR_LIMIT_ORDER_INVALID_MATCH: i8 = 17; const ERROR_LIMIT_ORDER_DECREASING_VALUE: i8 = 18; const ERROR_LIMIT_ORDER_INSUFFICIENT_MATCH: i8 = 20; @@ -130,7 +226,7 @@ fn scaffolding_tests_fail_for_the_reasons_reported() { let ickb_logic = data1_script(&mut context, "ickb_logic", Bytes::from(vec![42])); let input_out_point = context.create_cell( CellOutput::new_builder() - .capacity(1000u64.pack()) + .capacity((1000 * CKB).pack()) .lock(ickb_logic.clone()) .build(), Bytes::new(), @@ -139,25 +235,25 @@ fn scaffolding_tests_fail_for_the_reasons_reported() { .input(CellInput::new_builder().previous_output(input_out_point).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(500u64.pack()) + .capacity((500 * CKB).pack()) .lock(ickb_logic.clone()) .build(), CellOutput::new_builder() - .capacity(500u64.pack()) + .capacity((500 * CKB).pack()) .lock(ickb_logic) .build(), ]) .outputs_data(vec![Bytes::new(), Bytes::new()].pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); let mut context = Context::default(); let ickb_logic = ickb_logic_script(&mut context); let input_out_point = context.create_cell( CellOutput::new_builder() - .capacity(1000u64.pack()) + .capacity((1000 * CKB).pack()) .lock(ickb_logic.clone()) .build(), Bytes::new(), @@ -166,17 +262,17 @@ fn scaffolding_tests_fail_for_the_reasons_reported() { .input(CellInput::new_builder().previous_output(input_out_point).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(500u64.pack()) + .capacity((500 * CKB).pack()) .lock(ickb_logic.clone()) .build(), CellOutput::new_builder() - .capacity(500u64.pack()) + .capacity((500 * CKB).pack()) .lock(ickb_logic) .build(), ]) .outputs_data(vec![Bytes::new(), Bytes::new()].pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SCRIPT_MISUSE); } diff --git a/scripts/tests/src/tests/fixtures.rs b/scripts/tests/src/tests/fixtures.rs index 1f99a86..ff907da 100644 --- a/scripts/tests/src/tests/fixtures.rs +++ b/scripts/tests/src/tests/fixtures.rs @@ -23,8 +23,11 @@ pub(super) fn always_success_lock(context: &mut Context) -> Script { always_success_script(context, Bytes::new()) } +// Named locks stand in for real user locks, so their args take a secp lock's 20-byte size and +// the cells they guard need the same occupied capacity as on chain. pub(super) fn named_always_success_lock(context: &mut Context, name: &[u8]) -> Script { - always_success_script(context, Bytes::from(name.to_vec())) + let args = ckb_testtool::ckb_hash::blake2b_256(name)[..20].to_vec(); + always_success_script(context, Bytes::from(args)) } pub(super) fn data1_script(context: &mut Context, binary: &str, args: Bytes) -> Script { @@ -150,6 +153,20 @@ pub(super) fn capacity_for_data(data_len: u64) -> u64 { 100 * CKB + data_len } +/// A plain CKB cell that funds a transaction's outputs, as a wallet adds one on chain. +pub(super) fn funding_cell(context: &mut Context) -> OutPoint { + let lock = named_always_success_lock(context, b"funding"); + context.create_cell( + CellOutput::new_builder().capacity((1_000 * CKB).pack()).lock(lock).build(), + Bytes::new(), + ) +} + +/// The least capacity a cell with this lock, type and data length can hold on chain. +pub(super) fn occupied_capacity(lock: &Script, type_: &Script, data_len: usize) -> u64 { + deposit_capacity(lock, type_, data_len, 0) +} + pub(super) fn deposit_capacity(lock: &Script, type_: &Script, data_len: usize, unused_capacity: u64) -> u64 { let output = CellOutput::new_builder() .lock(lock.clone()) @@ -306,7 +323,7 @@ pub(super) fn create_withdrawal_inputs( link_cell_to_header(context, &deposit_input, &deposit_header); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock) .type_(Some(xudt.clone()).pack()) .build(), @@ -350,7 +367,7 @@ pub(super) fn build_real_limit_order_and_master_with_capacity( ) .output( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) .lock(owner_lock) .type_(Some(limit_order).pack()) .build(), @@ -359,7 +376,7 @@ pub(super) fn build_real_limit_order_and_master_with_capacity( .build(); let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("real limit order mint should verify"); let order_out_point = seed_verified_output(context, &tx, 0, order_data_mint(0, 1, (1, 1))); let master_out_point = seed_verified_output(context, &tx, 1, Bytes::new()); @@ -373,14 +390,14 @@ pub(super) fn assert_lock_only_limit_order_spend_error(data: Bytes, expected_err let (limit_order, output_type) = limit_order_and_helper_type_scripts(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity(500u64.pack()) + .capacity((500 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), ); let forged_output = CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(output_type).pack()) .build(); @@ -391,7 +408,7 @@ pub(super) fn assert_lock_only_limit_order_spend_error(data: Bytes, expected_err .build(); let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("lock-only forged order should be creatable"); let forged_out_point = context.create_cell(forged_output, data); @@ -403,13 +420,13 @@ pub(super) fn assert_lock_only_limit_order_spend_error(data: Bytes, expected_err ) .output( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(always_success_lock(&mut context)) .build(), ) .output_data(Bytes::new().pack()) .build(); let spend_tx = context.complete_tx(spend_tx); - let err = context.verify_tx(&spend_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&spend_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, expected_error); } diff --git a/scripts/tests/src/tests/ickb_logic/creation_blind_spots.rs b/scripts/tests/src/tests/ickb_logic/creation_blind_spots.rs index b8e1b45..4c9b98d 100644 --- a/scripts/tests/src/tests/ickb_logic/creation_blind_spots.rs +++ b/scripts/tests/src/tests/ickb_logic/creation_blind_spots.rs @@ -9,7 +9,7 @@ fn lock_only_ickb_logic_non_dao_output_can_be_created() { let helper_type = helper_type_script(&mut context); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity(500u64.pack()) + .capacity((500 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -19,7 +19,7 @@ fn lock_only_ickb_logic_non_dao_output_can_be_created() { .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(ickb_logic.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -29,12 +29,12 @@ fn lock_only_ickb_logic_non_dao_output_can_be_created() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("lock-only misuse cell creation bypasses ickb_logic"); let phantom_out_point = context.create_cell( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(ickb_logic) .type_(Some(helper_type).pack()) .build(), @@ -44,7 +44,7 @@ fn lock_only_ickb_logic_non_dao_output_can_be_created() { .input(CellInput::new_builder().previous_output(phantom_out_point).build()) .output( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(always_success_lock(&mut context)) .build(), ) @@ -52,7 +52,7 @@ fn lock_only_ickb_logic_non_dao_output_can_be_created() { .build(); let spend_tx = context.complete_tx(spend_tx); - let err = context.verify_tx(&spend_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&spend_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SCRIPT_MISUSE); } @@ -64,7 +64,7 @@ fn non_empty_args_ickb_logic_lock_output_can_be_created_but_not_spent() { let ickb_logic_non_empty = data1_script(&mut context, "ickb_logic", Bytes::from(vec![1])); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity(500u64.pack()) + .capacity((500 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -74,7 +74,7 @@ fn non_empty_args_ickb_logic_lock_output_can_be_created_but_not_spent() { .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(ickb_logic_non_empty.clone()) .build(), ) @@ -82,12 +82,12 @@ fn non_empty_args_ickb_logic_lock_output_can_be_created_but_not_spent() { .build(); let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("non-empty-args output lock can be created because output locks do not execute"); let out_point = context.create_cell( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(ickb_logic_non_empty) .build(), Bytes::new(), @@ -96,13 +96,13 @@ fn non_empty_args_ickb_logic_lock_output_can_be_created_but_not_spent() { .input(CellInput::new_builder().previous_output(out_point).build()) .output( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(always_success_lock(&mut context)) .build(), ) .output_data(Bytes::new().pack()) .build(); let spend_tx = context.complete_tx(spend_tx); - let err = context.verify_tx(&spend_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&spend_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); } diff --git a/scripts/tests/src/tests/ickb_logic/dao_phase2_batching.rs b/scripts/tests/src/tests/ickb_logic/dao_phase2_batching.rs index ce12de3..edeca2c 100644 --- a/scripts/tests/src/tests/ickb_logic/dao_phase2_batching.rs +++ b/scripts/tests/src/tests/ickb_logic/dao_phase2_batching.rs @@ -48,7 +48,7 @@ fn dao_phase2_with_65_outputs_hits_the_upstream_batch_limit() { .build(); let tx = sign_tx(context.complete_tx(tx), &privkey); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_DAO_TOO_MANY_OUTPUT_CELLS); } @@ -57,7 +57,7 @@ fn dao_phase2_with_65_outputs_hits_the_upstream_batch_limit() { fn dao_phase2_with_64_outputs_from_64_distinct_headers_passes() { let (context, tx) = build_many_header_phase2_batch(64, None); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("64-output DAO phase2 batch with distinct deposit headers should verify"); } @@ -102,7 +102,7 @@ fn dao_phase2_rejects_header_dep_index_witness_in_output_type() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, -11); } @@ -147,7 +147,7 @@ fn dao_phase2_rejects_short_header_dep_index_witness_in_input_type() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, -11); } @@ -155,7 +155,7 @@ fn dao_phase2_rejects_short_header_dep_index_witness_in_input_type() { #[test] fn dao_phase2_rejects_misbound_deposit_header_index_in_large_batch() { let (context, tx) = build_many_header_phase2_batch(64, Some((37, 1))); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_DAO_INVALID_WITHDRAW_BLOCK); } @@ -240,6 +240,6 @@ fn dao_phase2_with_two_distinct_deposit_headers_passes() { let tx = sign_tx(context.complete_tx(tx), &privkey); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("two-header DAO phase2 batch should verify"); } diff --git a/scripts/tests/src/tests/ickb_logic/deposit_bounds.rs b/scripts/tests/src/tests/ickb_logic/deposit_bounds.rs index 68f6093..73db905 100644 --- a/scripts/tests/src/tests/ickb_logic/deposit_bounds.rs +++ b/scripts/tests/src/tests/ickb_logic/deposit_bounds.rs @@ -21,7 +21,7 @@ fn deposit_below_minimum_is_rejected() { .type_(Some(dao).pack()) .build(); let receipt_output = CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock) .type_(Some(ickb_logic).pack()) .build(); @@ -33,7 +33,7 @@ fn deposit_below_minimum_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_DEPOSIT_TOO_SMALL); } @@ -58,7 +58,7 @@ fn deposit_at_minimum_is_accepted() { .type_(Some(dao).pack()) .build(); let receipt_output = CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock) .type_(Some(ickb_logic).pack()) .build(); @@ -71,7 +71,7 @@ fn deposit_at_minimum_is_accepted() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("deposit at the minimum boundary should verify"); } @@ -96,7 +96,7 @@ fn deposit_above_maximum_is_rejected() { .type_(Some(dao).pack()) .build(); let receipt_output = CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock) .type_(Some(ickb_logic).pack()) .build(); @@ -108,7 +108,7 @@ fn deposit_above_maximum_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_DEPOSIT_TOO_BIG); } @@ -133,7 +133,7 @@ fn deposit_at_maximum_is_accepted() { .type_(Some(dao).pack()) .build(); let receipt_output = CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock) .type_(Some(ickb_logic).pack()) .build(); @@ -146,6 +146,6 @@ fn deposit_at_maximum_is_accepted() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("deposit at the maximum boundary should verify"); } diff --git a/scripts/tests/src/tests/ickb_logic/economic_precision.rs b/scripts/tests/src/tests/ickb_logic/economic_precision.rs index 5a303c0..a1a1ae1 100644 --- a/scripts/tests/src/tests/ickb_logic/economic_precision.rs +++ b/scripts/tests/src/tests/ickb_logic/economic_precision.rs @@ -18,7 +18,7 @@ fn reported_rounding_claim_is_blocked_by_actual_shannon_precision() { let receipt_1152 = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&owner_lock, &ickb_logic, 12).pack()) .lock(owner_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -30,7 +30,7 @@ fn reported_rounding_claim_is_blocked_by_actual_shannon_precision() { .input(CellInput::new_builder().previous_output(receipt_1152.clone()).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -40,7 +40,7 @@ fn reported_rounding_claim_is_blocked_by_actual_shannon_precision() { .build(); let mint_claimed_1000_tx = context.complete_tx(mint_claimed_1000_tx); let err = context - .verify_tx(&mint_claimed_1000_tx, MAX_CYCLES) + .verify(&mint_claimed_1000_tx, MAX_CYCLES) .unwrap_err(); assert_script_error(err, ERROR_AMOUNT_MISMATCH); @@ -48,7 +48,7 @@ fn reported_rounding_claim_is_blocked_by_actual_shannon_precision() { .input(CellInput::new_builder().previous_output(receipt_1152).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -58,12 +58,12 @@ fn reported_rounding_claim_is_blocked_by_actual_shannon_precision() { .build(); let mint_exact_1152_tx = context.complete_tx(mint_exact_1152_tx); context - .verify_tx(&mint_exact_1152_tx, MAX_CYCLES) + .verify(&mint_exact_1152_tx, MAX_CYCLES) .expect("1152 CKB receipt should mint its exact shannon-precision amount"); let receipt_1151 = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&owner_lock, &ickb_logic, 12).pack()) .lock(owner_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -75,7 +75,7 @@ fn reported_rounding_claim_is_blocked_by_actual_shannon_precision() { .input(CellInput::new_builder().previous_output(receipt_1151).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock) .type_(Some(xudt).pack()) .build(), @@ -84,7 +84,7 @@ fn reported_rounding_claim_is_blocked_by_actual_shannon_precision() { .header_dep(receipt_1151_header.hash()) .build(); let remint_exact_1152_tx = context.complete_tx(remint_exact_1152_tx); - let err = context.verify_tx(&remint_exact_1152_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&remint_exact_1152_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_AMOUNT_MISMATCH); } @@ -114,7 +114,7 @@ fn reported_rounding_withdrawal_claim_is_blocked_by_actual_shannon_precision() { let udt_1000 = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -131,7 +131,7 @@ fn reported_rounding_withdrawal_claim_is_blocked_by_actual_shannon_precision() { .type_(Some(dao.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) .lock(user_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), @@ -140,7 +140,7 @@ fn reported_rounding_withdrawal_claim_is_blocked_by_actual_shannon_precision() { .header_dep(header.hash()) .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_AMOUNT_MISMATCH); let deposit_1152_b = context.create_cell( @@ -154,7 +154,7 @@ fn reported_rounding_withdrawal_claim_is_blocked_by_actual_shannon_precision() { link_cell_to_header(&mut context, &deposit_1152_b, &header); let udt_exact = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -170,7 +170,7 @@ fn reported_rounding_withdrawal_claim_is_blocked_by_actual_shannon_precision() { .type_(Some(dao.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) .lock(user_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), @@ -180,7 +180,7 @@ fn reported_rounding_withdrawal_claim_is_blocked_by_actual_shannon_precision() { .build(); let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("withdrawing 1152 CKB should require the exact shannon-precision iCKB amount"); let deposit_1151 = context.create_cell( @@ -194,7 +194,7 @@ fn reported_rounding_withdrawal_claim_is_blocked_by_actual_shannon_precision() { link_cell_to_header(&mut context, &deposit_1151, &header); let udt_exact_again = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -210,7 +210,7 @@ fn reported_rounding_withdrawal_claim_is_blocked_by_actual_shannon_precision() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) .lock(user_lock) .type_(Some(owned_owner).pack()) .build(), @@ -219,7 +219,7 @@ fn reported_rounding_withdrawal_claim_is_blocked_by_actual_shannon_precision() { .header_dep(header.hash()) .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_AMOUNT_MISMATCH); } @@ -234,87 +234,12 @@ fn withdrawal_burn_matches_later_protocol_value_within_one_shannon_across_header let withdraw_header = gen_header(2_000_610, withdraw_ar, 575, 2_000_000, 1100); let mut run_case = |amount: u64, deposit_number: u64, deposit_ar: u64| -> u128 { - let deposit_header = gen_header(deposit_number, deposit_ar, 35, 1000, 1000); - let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, amount); - let deposit_occupied_capacity = deposit_total_capacity - amount; - - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), + let (burned_ickb, claim_capacity, deposit_occupied_capacity) = burn_and_claim( + &mut context, + (&user_lock, &ickb_logic, &dao, &xudt), + (&withdraw_header, withdraw_ar), + (amount, deposit_number, deposit_ar), ); - link_cell_to_header(&mut context, &deposit_input, &deposit_header); - - let burned_ickb = soft_capped_ickb(amount, deposit_ar); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - udt_data(burned_ickb), - ); - - let phase1_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .output( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(user_lock.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - ) - .output_data(withdrawal_request_data(deposit_number).pack()) - .header_dep(deposit_header.hash()) - .build(); - let phase1_tx = context.complete_tx(phase1_tx); - context - .verify_tx(&phase1_tx, MAX_CYCLES) - .expect("exact phase1 burn should verify for the deposit header"); - - let withdrawal_out_point = OutPoint::new(phase1_tx.hash(), 0); - let withdrawal_output = phase1_tx.outputs().get(0).expect("withdrawing output"); - context.create_cell_with_out_point( - withdrawal_out_point.clone(), - withdrawal_output.clone(), - withdrawal_request_data(deposit_number), - ); - link_cell_to_header(&mut context, &withdrawal_out_point, &withdraw_header); - - let claim_capacity = dao_maximum_withdraw_capacity( - &withdrawal_output, - withdrawal_request_data(deposit_number).len(), - deposit_ar, - withdraw_ar, - ); - let witness = header_dep_index_witness(1); - let claim_tx = TransactionBuilder::default() - .input( - CellInput::new_builder() - .previous_output(withdrawal_out_point) - .since(0x2003e800000002f4u64.pack()) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity(claim_capacity.pack()) - .lock(user_lock.clone()) - .build(), - ) - .output_data(Bytes::new().pack()) - .header_dep(withdraw_header.hash()) - .header_dep(deposit_header.hash()) - .witness(witness.pack()) - .build(); - let claim_tx = context.complete_tx(claim_tx); - context - .verify_tx(&claim_tx, MAX_CYCLES) - .expect("phase2 claim should verify for the withdrawal request"); - let later_ickb_value = soft_capped_ickb(claim_capacity - deposit_occupied_capacity, withdraw_ar); assert!(burned_ickb >= later_ickb_value); @@ -322,7 +247,6 @@ fn withdrawal_burn_matches_later_protocol_value_within_one_shannon_across_header burned_ickb - later_ickb_value <= 1, "phase1 burn {burned_ickb} and later normalized claim value {later_ickb_value} should differ by at most one shannon" ); - burned_ickb }; @@ -339,3 +263,98 @@ fn withdrawal_burn_matches_later_protocol_value_within_one_shannon_across_header "the oversized deposit should still cost more iCKB than the smaller newer deposit after the haircut" ); } + +/// Phase 1 burns exactly the deposit's iCKB value, then phase 2 claims the DAO maximum. +/// Returns (burned iCKB, claimed capacity, deposit occupied capacity). +fn burn_and_claim( + context: &mut Context, + scripts: (&Script, &Script, &Script, &Script), + withdraw: (&ckb_testtool::ckb_types::core::HeaderView, u64), + (amount, deposit_number, deposit_ar): (u64, u64, u64), +) -> (u128, u64, u64) { + let (user_lock, ickb_logic, dao, xudt) = scripts; + let (withdraw_header, withdraw_ar) = withdraw; + let deposit_header = gen_header(deposit_number, deposit_ar, 35, 1000, 1000); + let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, amount); + let deposit_occupied_capacity = deposit_total_capacity - amount; + + let deposit_input = context.create_cell( + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(ickb_logic.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + dao_deposit_data(), + ); + link_cell_to_header(context, &deposit_input, &deposit_header); + + let burned_ickb = soft_capped_ickb(amount, deposit_ar); + let udt_input = context.create_cell( + CellOutput::new_builder() + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) + .lock(user_lock.clone()) + .type_(Some(xudt.clone()).pack()) + .build(), + udt_data(burned_ickb), + ); + + let phase1_tx = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(deposit_input).build()) + .input(CellInput::new_builder().previous_output(udt_input).build()) + .output( + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(user_lock.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + ) + .output_data(withdrawal_request_data(deposit_number).pack()) + .header_dep(deposit_header.hash()) + .build(); + let phase1_tx = context.complete_tx(phase1_tx); + context + .verify(&phase1_tx, MAX_CYCLES) + .expect("exact phase1 burn should verify for the deposit header"); + + let withdrawal_out_point = OutPoint::new(phase1_tx.hash(), 0); + let withdrawal_output = phase1_tx.outputs().get(0).expect("withdrawing output"); + context.create_cell_with_out_point( + withdrawal_out_point.clone(), + withdrawal_output.clone(), + withdrawal_request_data(deposit_number), + ); + link_cell_to_header(context, &withdrawal_out_point, withdraw_header); + + let claim_capacity = dao_maximum_withdraw_capacity( + &withdrawal_output, + withdrawal_request_data(deposit_number).len(), + deposit_ar, + withdraw_ar, + ); + let witness = header_dep_index_witness(1); + let claim_tx = TransactionBuilder::default() + .input( + CellInput::new_builder() + .previous_output(withdrawal_out_point) + .since(0x2003e800000002f4u64.pack()) + .build(), + ) + .output( + CellOutput::new_builder() + .capacity(claim_capacity.pack()) + .lock(user_lock.clone()) + .build(), + ) + .output_data(Bytes::new().pack()) + .header_dep(withdraw_header.hash()) + .header_dep(deposit_header.hash()) + .witness(witness.pack()) + .build(); + let claim_tx = context.complete_tx(claim_tx); + context + .verify(&claim_tx, MAX_CYCLES) + .expect("phase2 claim should verify for the withdrawal request"); + + + (burned_ickb, claim_capacity, deposit_occupied_capacity) +} diff --git a/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs b/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs index ac992dc..bcdb77c 100644 --- a/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs +++ b/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs @@ -10,7 +10,7 @@ fn mixed_flow_cannot_overmint_by_combining_new_deposit_with_phase2_receipt() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -32,12 +32,12 @@ fn mixed_flow_cannot_overmint_by_combining_new_deposit_with_phase2_receipt() { .type_(Some(dao).pack()) .build(); let new_receipt_output = CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(); let udt_output = CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(); @@ -58,7 +58,7 @@ fn mixed_flow_cannot_overmint_by_combining_new_deposit_with_phase2_receipt() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_AMOUNT_MISMATCH); } @@ -75,7 +75,7 @@ fn mixed_flow_cannot_overmint_when_deposit_phase1_phase2_and_withdrawal_share_on let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) .lock(user_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -96,7 +96,7 @@ fn mixed_flow_cannot_overmint_when_deposit_phase1_phase2_and_withdrawal_share_on let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -121,17 +121,17 @@ fn mixed_flow_cannot_overmint_when_deposit_phase1_phase2_and_withdrawal_share_on .type_(Some(dao).pack()) .build(); let owner_output = CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) .lock(user_lock.clone()) .type_(Some(owned_owner).pack()) .build(); let new_receipt_output = CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) .lock(user_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(); let udt_output = CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock) .type_(Some(xudt).pack()) .build(); @@ -157,7 +157,7 @@ fn mixed_flow_cannot_overmint_when_deposit_phase1_phase2_and_withdrawal_share_on .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_AMOUNT_MISMATCH); } @@ -179,7 +179,7 @@ fn all_three_scripts_can_compose_in_one_live_state_transition() { let receipt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&owner_lock, &ickb_logic, 12).pack()) .lock(owner_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -213,7 +213,7 @@ fn all_three_scripts_can_compose_in_one_live_state_transition() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock) .type_(Some(owned_owner).pack()) .build(), @@ -231,6 +231,6 @@ fn all_three_scripts_can_compose_in_one_live_state_transition() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("a live receipt, live deposit, and live limit order should compose in one valid transaction"); } diff --git a/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs b/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs index 4c25312..09f1bf6 100644 --- a/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs +++ b/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs @@ -24,7 +24,7 @@ fn repeated_deposit_bucket_can_be_matched_by_one_multi_quantity_receipt() { .build() }; let receipt_output = CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock) .type_(Some(ickb_logic.clone()).pack()) .build(); @@ -37,7 +37,7 @@ fn repeated_deposit_bucket_can_be_matched_by_one_multi_quantity_receipt() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("one receipt with quantity 2 should match two equal-sized deposits"); } @@ -51,7 +51,7 @@ fn multi_quantity_receipt_can_be_converted_in_phase2() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -63,7 +63,7 @@ fn multi_quantity_receipt_can_be_converted_in_phase2() { .input(CellInput::new_builder().previous_output(receipt_out_point).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -74,6 +74,6 @@ fn multi_quantity_receipt_can_be_converted_in_phase2() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("a valid receipt with quantity 2 should mint the combined iCKB amount in phase2"); } diff --git a/scripts/tests/src/tests/ickb_logic/phase2_headers.rs b/scripts/tests/src/tests/ickb_logic/phase2_headers.rs index 12ed90a..40d3ea2 100644 --- a/scripts/tests/src/tests/ickb_logic/phase2_headers.rs +++ b/scripts/tests/src/tests/ickb_logic/phase2_headers.rs @@ -10,7 +10,7 @@ fn phase2_conversion_without_receipt_header_dep_is_rejected() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -22,7 +22,7 @@ fn phase2_conversion_without_receipt_header_dep_is_rejected() { .input(CellInput::new_builder().previous_output(receipt_out_point).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -31,7 +31,7 @@ fn phase2_conversion_without_receipt_header_dep_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_ITEM_MISSING); } @@ -46,7 +46,7 @@ fn phase2_conversion_with_two_receipts_from_distinct_headers_passes() { let second_amount = 1_200 * CKB; let first_receipt = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -54,7 +54,7 @@ fn phase2_conversion_with_two_receipts_from_distinct_headers_passes() { ); let second_receipt = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -72,7 +72,7 @@ fn phase2_conversion_with_two_receipts_from_distinct_headers_passes() { .input(CellInput::new_builder().previous_output(second_receipt).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -84,7 +84,7 @@ fn phase2_conversion_with_two_receipts_from_distinct_headers_passes() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("phase2 conversion should support multiple receipts from distinct headers"); } @@ -99,7 +99,7 @@ fn phase2_conversion_with_one_missing_receipt_header_dep_is_rejected() { let second_amount = 1_200 * CKB; let first_receipt = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -107,7 +107,7 @@ fn phase2_conversion_with_one_missing_receipt_header_dep_is_rejected() { ); let second_receipt = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -123,7 +123,7 @@ fn phase2_conversion_with_one_missing_receipt_header_dep_is_rejected() { .input(CellInput::new_builder().previous_output(second_receipt).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -133,7 +133,7 @@ fn phase2_conversion_with_one_missing_receipt_header_dep_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_ITEM_MISSING); } @@ -147,7 +147,7 @@ fn phase2_conversion_with_zero_accumulated_rate_header_is_rejected() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -160,7 +160,7 @@ fn phase2_conversion_with_zero_accumulated_rate_header_is_rejected() { .input(CellInput::new_builder().previous_output(receipt_out_point).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -170,6 +170,6 @@ fn phase2_conversion_with_zero_accumulated_rate_header_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SCRIPT_PANIC); } diff --git a/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs b/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs index 164de1e..4ab0f2f 100644 --- a/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs +++ b/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs @@ -26,7 +26,7 @@ fn weak_lock_receipt_can_reassign_phase2_mint_recipient() { ) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&attacker_lock, &xudt, 16).pack()) .lock(attacker_lock) .type_(Some(xudt).pack()) .build(), @@ -37,7 +37,7 @@ fn weak_lock_receipt_can_reassign_phase2_mint_recipient() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("weak lock should allow reassigning the phase2 mint recipient"); } @@ -52,7 +52,7 @@ fn sighash_lock_binds_phase2_mint_outputs_to_the_signed_transaction() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&owner_lock, &ickb_logic, 12).pack()) .lock(owner_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -64,7 +64,7 @@ fn sighash_lock_binds_phase2_mint_outputs_to_the_signed_transaction() { .input(CellInput::new_builder().previous_output(receipt_out_point).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -77,20 +77,20 @@ fn sighash_lock_binds_phase2_mint_outputs_to_the_signed_transaction() { let tx = sign_tx(context.complete_tx(tx), &privkey); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("signed owner transaction should verify"); let tampered_tx = tx .as_advanced_builder() .set_outputs(vec![ CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&attacker_lock, &xudt, 16).pack()) .lock(attacker_lock) .type_(Some(xudt).pack()) .build(), ]) .build(); - let err = context.verify_tx(&tampered_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } @@ -107,7 +107,7 @@ fn mixed_sighash_and_weak_receipts_bind_all_phase2_outputs_once_signed() { let amount2 = 1_200 * CKB; let receipt1 = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&owner_lock, &ickb_logic, 12).pack()) .lock(owner_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -115,7 +115,7 @@ fn mixed_sighash_and_weak_receipts_bind_all_phase2_outputs_once_signed() { ); let receipt2 = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&weak_lock, &ickb_logic, 12).pack()) .lock(weak_lock) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -132,7 +132,7 @@ fn mixed_sighash_and_weak_receipts_bind_all_phase2_outputs_once_signed() { .input(CellInput::new_builder().previous_output(receipt2).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -147,20 +147,20 @@ fn mixed_sighash_and_weak_receipts_bind_all_phase2_outputs_once_signed() { let tx = sign_tx_by_input_group(context.complete_tx(tx), &privkey, 0, 1); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("mixed strong+weak phase2 tx should verify when signed"); let tampered_tx = tx .as_advanced_builder() .set_outputs(vec![ CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&attacker_lock, &xudt, 16).pack()) .lock(attacker_lock) .type_(Some(xudt).pack()) .build(), ]) .build(); - let err = context.verify_tx(&tampered_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } @@ -177,7 +177,7 @@ fn two_weak_receipts_can_reassign_combined_phase2_mint_recipient() { let amount2 = 1_200 * CKB; let receipt1 = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&weak_lock_1, &ickb_logic, 12).pack()) .lock(weak_lock_1) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -185,7 +185,7 @@ fn two_weak_receipts_can_reassign_combined_phase2_mint_recipient() { ); let receipt2 = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&weak_lock_2, &ickb_logic, 12).pack()) .lock(weak_lock_2) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -202,7 +202,7 @@ fn two_weak_receipts_can_reassign_combined_phase2_mint_recipient() { .input(CellInput::new_builder().previous_output(receipt2).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&attacker_lock, &xudt, 16).pack()) .lock(attacker_lock) .type_(Some(xudt).pack()) .build(), @@ -214,6 +214,6 @@ fn two_weak_receipts_can_reassign_combined_phase2_mint_recipient() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("all-weak phase2 inputs can reassign the combined phase2 mint recipient"); } diff --git a/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs b/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs index bfd01a9..8689e2a 100644 --- a/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs +++ b/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs @@ -11,7 +11,7 @@ fn unrelated_non_empty_args_output_lock_poisons_phase2() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -20,7 +20,7 @@ fn unrelated_non_empty_args_output_lock_poisons_phase2() { let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let extra_input = context.create_cell( CellOutput::new_builder() - .capacity(500u64.pack()) + .capacity((500 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -31,12 +31,12 @@ fn unrelated_non_empty_args_output_lock_poisons_phase2() { .input(CellInput::new_builder().previous_output(extra_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock.clone()) .type_(Some(xudt).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(poisoned_lock) .build(), ]) @@ -45,7 +45,7 @@ fn unrelated_non_empty_args_output_lock_poisons_phase2() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); } @@ -59,7 +59,7 @@ fn ickb_xudt_shaped_output_lock_poisons_phase2() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -68,7 +68,7 @@ fn ickb_xudt_shaped_output_lock_poisons_phase2() { let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let extra_input = context.create_cell( CellOutput::new_builder() - .capacity(500u64.pack()) + .capacity((500 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -79,7 +79,7 @@ fn ickb_xudt_shaped_output_lock_poisons_phase2() { .input(CellInput::new_builder().previous_output(extra_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -93,7 +93,7 @@ fn ickb_xudt_shaped_output_lock_poisons_phase2() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SCRIPT_MISUSE); } @@ -107,7 +107,7 @@ fn dao_deposit_shaped_output_lock_poisons_phase2() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -116,7 +116,7 @@ fn dao_deposit_shaped_output_lock_poisons_phase2() { let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let extra_input = context.create_cell( CellOutput::new_builder() - .capacity(500u64.pack()) + .capacity((500 * CKB).pack()) .lock(funding_lock.clone()) .build(), Bytes::new(), @@ -127,7 +127,7 @@ fn dao_deposit_shaped_output_lock_poisons_phase2() { .input(CellInput::new_builder().previous_output(extra_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -141,7 +141,7 @@ fn dao_deposit_shaped_output_lock_poisons_phase2() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SCRIPT_MISUSE); } @@ -157,7 +157,7 @@ fn foreign_xudt_output_lock_is_ignored() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -177,7 +177,7 @@ fn foreign_xudt_output_lock_is_ignored() { .input(CellInput::new_builder().previous_output(extra_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -192,7 +192,7 @@ fn foreign_xudt_output_lock_is_ignored() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("same xudt code with different args should stay outside iCKB classification"); } @@ -208,7 +208,7 @@ fn foreign_xudt_type_output_is_ignored() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -228,12 +228,12 @@ fn foreign_xudt_type_output_is_ignored() { .input(CellInput::new_builder().previous_output(extra_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock.clone()) .type_(Some(xudt).pack()) .build(), CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &foreign_xudt, 16).pack()) .lock(funding_lock.clone()) .type_(Some(foreign_xudt).pack()) .build(), @@ -244,7 +244,7 @@ fn foreign_xudt_type_output_is_ignored() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("same xudt code with different args should stay outside iCKB UDT accounting"); } @@ -258,7 +258,7 @@ fn withdrawal_request_shaped_dao_output_lock_is_ignored() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -278,7 +278,7 @@ fn withdrawal_request_shaped_dao_output_lock_is_ignored() { .input(CellInput::new_builder().previous_output(extra_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -293,7 +293,7 @@ fn withdrawal_request_shaped_dao_output_lock_is_ignored() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("non-zero dao-shaped lock outputs should remain outside deposit classification"); } @@ -310,7 +310,7 @@ fn deposit_shaped_non_empty_args_output_poisons_phase2() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -330,7 +330,7 @@ fn deposit_shaped_non_empty_args_output_poisons_phase2() { .input(CellInput::new_builder().previous_output(extra_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -345,7 +345,7 @@ fn deposit_shaped_non_empty_args_output_poisons_phase2() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); } @@ -361,7 +361,7 @@ fn non_empty_args_receipt_sibling_poisons_phase2() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -370,7 +370,7 @@ fn non_empty_args_receipt_sibling_poisons_phase2() { let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let poisoned_receipt = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &poisoned_receipt_type, 12).pack()) .lock(funding_lock.clone()) .type_(Some(poisoned_receipt_type).pack()) .build(), @@ -383,7 +383,7 @@ fn non_empty_args_receipt_sibling_poisons_phase2() { .input(CellInput::new_builder().previous_output(poisoned_receipt).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -393,6 +393,6 @@ fn non_empty_args_receipt_sibling_poisons_phase2() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); } diff --git a/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs b/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs index 893d5e8..d0f1cef 100644 --- a/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs +++ b/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs @@ -10,7 +10,7 @@ fn phase2_mint_accepts_xudt_data_with_trailing_bytes() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -24,7 +24,7 @@ fn phase2_mint_accepts_xudt_data_with_trailing_bytes() { .input(CellInput::new_builder().previous_output(receipt_out_point).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(output_data.len() as u64).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, output_data.len()).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -35,7 +35,7 @@ fn phase2_mint_accepts_xudt_data_with_trailing_bytes() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("phase2 mint should accept xudt data with trailing bytes"); } @@ -49,7 +49,7 @@ fn phase2_mint_rejects_short_xudt_output_data() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -61,7 +61,7 @@ fn phase2_mint_rejects_short_xudt_output_data() { .input(CellInput::new_builder().previous_output(receipt_out_point).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(8).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 8).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -71,7 +71,7 @@ fn phase2_mint_rejects_short_xudt_output_data() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_ENCODING); } @@ -85,7 +85,7 @@ fn phase2_mint_rejects_zero_length_xudt_output_data() { let deposit_amount = 1_000 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -97,7 +97,7 @@ fn phase2_mint_rejects_zero_length_xudt_output_data() { .input(CellInput::new_builder().previous_output(receipt_out_point).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(0).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 0).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -107,6 +107,6 @@ fn phase2_mint_rejects_zero_length_xudt_output_data() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_ENCODING); } diff --git a/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs b/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs index 1cb327d..b84c2a9 100644 --- a/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs +++ b/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs @@ -22,7 +22,7 @@ fn receipt_trailing_bytes_do_not_change_creation_accounting() { .type_(Some(dao).pack()) .build(); let receipt_output = CellOutput::new_builder() - .capacity(capacity_for_data(15).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 15).pack()) .lock(funding_lock) .type_(Some(ickb_logic).pack()) .build(); @@ -40,7 +40,7 @@ fn receipt_trailing_bytes_do_not_change_creation_accounting() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("receipt trailing bytes should not affect accounting"); } @@ -65,7 +65,7 @@ fn receipt_trailing_bytes_do_not_change_phase2_conversion() { .input(CellInput::new_builder().previous_output(receipt_out_point).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -76,7 +76,7 @@ fn receipt_trailing_bytes_do_not_change_phase2_conversion() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("receipt trailing bytes should not affect phase2 conversion"); } @@ -102,7 +102,7 @@ fn truncated_receipt_output_with_small_amount_is_rejected() { .type_(Some(dao).pack()) .build(); let receipt_output = CellOutput::new_builder() - .capacity(capacity_for_data(9).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 9).pack()) .lock(funding_lock) .type_(Some(ickb_logic).pack()) .build(); @@ -115,7 +115,7 @@ fn truncated_receipt_output_with_small_amount_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_ENCODING); } @@ -140,7 +140,7 @@ fn truncated_receipt_input_with_small_amount_is_rejected() { .input(CellInput::new_builder().previous_output(receipt_out_point).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -150,6 +150,6 @@ fn truncated_receipt_input_with_small_amount_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_ENCODING); } diff --git a/scripts/tests/src/tests/ickb_logic/receipt_matching.rs b/scripts/tests/src/tests/ickb_logic/receipt_matching.rs index 9dd81ab..f9852cd 100644 --- a/scripts/tests/src/tests/ickb_logic/receipt_matching.rs +++ b/scripts/tests/src/tests/ickb_logic/receipt_matching.rs @@ -21,7 +21,7 @@ fn zero_quantity_receipt_is_rejected() { .type_(Some(dao).pack()) .build(); let receipt_output = CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock) .type_(Some(ickb_logic).pack()) .build(); @@ -33,7 +33,7 @@ fn zero_quantity_receipt_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_EMPTY_RECEIPT); } @@ -58,7 +58,7 @@ fn forged_receipt_quantity_without_enough_deposits_is_rejected() { .type_(Some(dao).pack()) .build(); let receipt_output = CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock) .type_(Some(ickb_logic).pack()) .build(); @@ -70,7 +70,7 @@ fn forged_receipt_quantity_without_enough_deposits_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_RECEIPT_MISMATCH); } @@ -94,7 +94,7 @@ fn receipt_for_unmatched_deposit_amount_is_rejected() { .type_(Some(dao).pack()) .build(); let receipt_output = CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock) .type_(Some(ickb_logic).pack()) .build(); @@ -106,6 +106,6 @@ fn receipt_for_unmatched_deposit_amount_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_RECEIPT_MISMATCH); } diff --git a/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs b/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs index 2db6000..6698c00 100644 --- a/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs +++ b/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs @@ -31,7 +31,7 @@ fn receiptless_dao_shaped_output_is_accepted_as_deposit() { let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("receiptless DAO-shaped ickb_logic output can be created at output-lock creation time"); let receiptless_deposit_input = context.create_cell( @@ -47,7 +47,7 @@ fn receiptless_dao_shaped_output_is_accepted_as_deposit() { let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -70,7 +70,7 @@ fn receiptless_dao_shaped_output_is_accepted_as_deposit() { let withdraw_tx = context.complete_tx(withdraw_tx); context - .verify_tx(&withdraw_tx, MAX_CYCLES) + .verify(&withdraw_tx, MAX_CYCLES) .expect("later phase1 withdrawal request should accept the receiptless DAO-shaped output as a structurally valid deposit input"); } @@ -112,7 +112,7 @@ fn split_receipt_against_receiptless_aggregate_mints_only_spread() { .build(); let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("aggregate receiptless deposit creation is allowed at output-lock creation time"); let receiptless_aggregate_deposit = context.create_cell( @@ -128,7 +128,7 @@ fn split_receipt_against_receiptless_aggregate_mints_only_spread() { let receipt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) .lock(user_lock.clone()) .type_(Some(ickb_logic).pack()) .build(), @@ -141,6 +141,7 @@ fn split_receipt_against_receiptless_aggregate_mints_only_spread() { let tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(receiptless_aggregate_deposit).build()) .input(CellInput::new_builder().previous_output(receipt_input).build()) + .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) .outputs(vec![ CellOutput::new_builder() .capacity(aggregate_total_capacity.pack()) @@ -148,7 +149,7 @@ fn split_receipt_against_receiptless_aggregate_mints_only_spread() { .type_(Some(dao.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock) .type_(Some(xudt).pack()) .build(), @@ -159,31 +160,87 @@ fn split_receipt_against_receiptless_aggregate_mints_only_spread() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("split receipt should mint only the soft-cap spread while the separately funded aggregate principal stays in the withdrawal output"); let tampered_tx = tx .as_advanced_builder() .set_outputs_data(vec![withdrawal_request_data(1554).pack(), udt_data(delta + 1).pack()]) .build(); - let err = context.verify_tx(&tampered_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_AMOUNT_MISMATCH); } -// Build the same delta-only spread path and then complete the DAO phase2 claim on the rolled withdrawal cell: both steps should pass, showing the self-funded aggregate principal stays recoverable even though only the spread minted in phase1. +// Verify one continuous split-deposit receipt, receiptless creation, delta-only spread, and DAO phase2 claim trajectory: each later input keeps the preceding verified output's tx hash and index. #[test] -fn spread_path_keeps_self_funded_principal_claimable() { +fn verified_receiptless_creation_spread_and_claim_trajectory() { let mut context = Context::default(); let user_lock = always_success_lock(&mut context); let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); let split_amount = 100_000 * CKB; let aggregate_amount = 2 * split_amount; + let split_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, split_amount); let aggregate_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, aggregate_amount); let delta = 10_000 * CKB as u128; let deposit_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); + let split_funding_input = context.create_cell( + CellOutput::new_builder() + .capacity((2 * split_total_capacity + capacity_for_data(16)).pack()) + .lock(user_lock.clone()) + .build(), + Bytes::new(), + ); + let split_tx = TransactionBuilder::default() + .input( + CellInput::new_builder() + .previous_output(split_funding_input) + .build(), + ) + .outputs(vec![ + CellOutput::new_builder() + .capacity(split_total_capacity.pack()) + .lock(ickb_logic.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + CellOutput::new_builder() + .capacity(split_total_capacity.pack()) + .lock(ickb_logic.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + CellOutput::new_builder() + .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) + .lock(user_lock.clone()) + .type_(Some(ickb_logic.clone()).pack()) + .build(), + ]) + .outputs_data( + vec![ + dao_deposit_data(), + dao_deposit_data(), + receipt_data(2, split_amount), + ] + .pack(), + ) + .build(); + let split_tx = context.complete_tx(split_tx); + context + .verify(&split_tx, MAX_CYCLES) + .expect("two split deposits should create their quantity-two receipt"); + let split_deposit_1 = seed_verified_output(&mut context, &split_tx, 0, dao_deposit_data()); + let split_deposit_2 = seed_verified_output(&mut context, &split_tx, 1, dao_deposit_data()); + let receipt_input = seed_verified_output( + &mut context, + &split_tx, + 2, + receipt_data(2, split_amount), + ); + link_cell_to_header(&mut context, &split_deposit_1, &deposit_header); + link_cell_to_header(&mut context, &split_deposit_2, &deposit_header); + link_cell_to_header(&mut context, &receipt_input, &deposit_header); + let funding_input = context.create_cell( CellOutput::new_builder() .capacity(aggregate_total_capacity.pack()) @@ -204,34 +261,23 @@ fn spread_path_keeps_self_funded_principal_claimable() { .build(); let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("aggregate receiptless deposit creation is allowed at output-lock creation time"); - let receiptless_aggregate_deposit = context.create_cell( - CellOutput::new_builder() - .capacity(aggregate_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + let receiptless_aggregate_deposit = seed_verified_output( + &mut context, + &create_tx, + 0, dao_deposit_data(), ); link_cell_to_header(&mut context, &receiptless_aggregate_deposit, &deposit_header); - let receipt_input = context.create_cell( - CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(2, split_amount), - ); - link_cell_to_header(&mut context, &receipt_input, &deposit_header); - // This is the same delta-only mint path as above, then a DAO phase2 claim. // The claim demonstrates that the self-funded aggregate principal stays spendable after minting only the spread. let mint_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(receiptless_aggregate_deposit).build()) .input(CellInput::new_builder().previous_output(receipt_input).build()) + .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) .outputs(vec![ CellOutput::new_builder() .capacity(aggregate_total_capacity.pack()) @@ -239,7 +285,7 @@ fn spread_path_keeps_self_funded_principal_claimable() { .type_(Some(dao.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -249,7 +295,7 @@ fn spread_path_keeps_self_funded_principal_claimable() { .build(); let mint_tx = context.complete_tx(mint_tx); context - .verify_tx(&mint_tx, MAX_CYCLES) + .verify(&mint_tx, MAX_CYCLES) .expect("split receipt should realize the soft-cap spread while rolling only the self-funded aggregate deposit into withdrawal"); let withdrawal_output = mint_tx.outputs().get(0).expect("withdrawing output"); @@ -288,7 +334,7 @@ fn spread_path_keeps_self_funded_principal_claimable() { .build(); let claim_tx = context.complete_tx(claim_tx); context - .verify_tx(&claim_tx, MAX_CYCLES) + .verify(&claim_tx, MAX_CYCLES) .expect("the self-funded principal from the receiptless aggregate-deposit soft-cap path should remain spendable in DAO phase2"); } @@ -323,7 +369,7 @@ fn receiptless_aggregate_alone_cannot_mint_spread() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock) .type_(Some(xudt).pack()) .build(), @@ -333,7 +379,7 @@ fn receiptless_aggregate_alone_cannot_mint_spread() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_AMOUNT_MISMATCH); } @@ -372,7 +418,7 @@ fn oversized_receiptless_aggregate_realizes_larger_spread() { .build(); let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("oversized aggregate receiptless deposit can still be created at output-lock creation time"); let receiptless_aggregate_deposit = context.create_cell( @@ -388,7 +434,7 @@ fn oversized_receiptless_aggregate_realizes_larger_spread() { let receipt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) .lock(user_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -399,6 +445,7 @@ fn oversized_receiptless_aggregate_realizes_larger_spread() { let tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(receiptless_aggregate_deposit).build()) .input(CellInput::new_builder().previous_output(receipt_input).build()) + .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) .outputs(vec![ CellOutput::new_builder() .capacity(aggregate_total_capacity.pack()) @@ -406,7 +453,7 @@ fn oversized_receiptless_aggregate_realizes_larger_spread() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock) .type_(Some(xudt).pack()) .build(), @@ -417,6 +464,6 @@ fn oversized_receiptless_aggregate_realizes_larger_spread() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("the oversized self-funded receiptless aggregate deposit should realize a larger soft-cap spread far past the intended per-deposit maximum"); } diff --git a/scripts/tests/src/tests/ickb_logic/soft_cap.rs b/scripts/tests/src/tests/ickb_logic/soft_cap.rs index b85a2b5..958115e 100644 --- a/scripts/tests/src/tests/ickb_logic/soft_cap.rs +++ b/scripts/tests/src/tests/ickb_logic/soft_cap.rs @@ -10,7 +10,7 @@ fn phase2_mint_applies_soft_cap_discount_above_boundary() { let amount = 100_001 * CKB; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -22,7 +22,7 @@ fn phase2_mint_applies_soft_cap_discount_above_boundary() { .input(CellInput::new_builder().previous_output(receipt_out_point.clone()).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -31,14 +31,14 @@ fn phase2_mint_applies_soft_cap_discount_above_boundary() { .header_dep(receipt_header.clone()) .build(); let naive_tx = context.complete_tx(naive_tx); - let err = context.verify_tx(&naive_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&naive_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_AMOUNT_MISMATCH); let exact_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(receipt_out_point).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -48,7 +48,7 @@ fn phase2_mint_applies_soft_cap_discount_above_boundary() { .build(); let exact_tx = context.complete_tx(exact_tx); context - .verify_tx(&exact_tx, MAX_CYCLES) + .verify(&exact_tx, MAX_CYCLES) .expect("phase2 mint should apply the documented soft-cap discount above 100k iCKB"); } @@ -64,7 +64,7 @@ fn phase2_mint_does_not_discount_at_soft_cap_boundary() { let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic).pack()) .build(), @@ -76,7 +76,7 @@ fn phase2_mint_does_not_discount_at_soft_cap_boundary() { .input(CellInput::new_builder().previous_output(receipt_out_point).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -87,7 +87,7 @@ fn phase2_mint_does_not_discount_at_soft_cap_boundary() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("phase2 mint should keep the full amount exactly at the 100k soft-cap boundary"); } @@ -102,7 +102,7 @@ fn multi_quantity_phase2_mint_applies_soft_cap_per_deposit() { let quantity = 2u32; let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -119,7 +119,7 @@ fn multi_quantity_phase2_mint_applies_soft_cap_per_deposit() { .input(CellInput::new_builder().previous_output(receipt_out_point.clone()).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -128,14 +128,14 @@ fn multi_quantity_phase2_mint_applies_soft_cap_per_deposit() { .header_dep(receipt_header.clone()) .build(); let naive_tx = context.complete_tx(naive_tx); - let err = context.verify_tx(&naive_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&naive_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_AMOUNT_MISMATCH); let exact_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(receipt_out_point).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -145,7 +145,7 @@ fn multi_quantity_phase2_mint_applies_soft_cap_per_deposit() { .build(); let exact_tx = context.complete_tx(exact_tx); context - .verify_tx(&exact_tx, MAX_CYCLES) + .verify(&exact_tx, MAX_CYCLES) .expect("multi-quantity receipts should apply the soft cap per deposit, not once on the aggregate"); } @@ -161,7 +161,7 @@ fn mixed_phase1_phase2_still_apply_soft_cap_per_receipt() { let deposit_output_capacity = deposit_capacity(&ickb_logic, &dao, 8, amount); let receipt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -198,12 +198,12 @@ fn mixed_phase1_phase2_still_apply_soft_cap_per_receipt() { .type_(Some(dao.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -222,11 +222,11 @@ fn mixed_phase1_phase2_still_apply_soft_cap_per_receipt() { }; let naive_tx = context.complete_tx(build_tx(naive_aggregate)); - let err = context.verify_tx(&naive_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&naive_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_AMOUNT_MISMATCH); let exact_tx = context.complete_tx(build_tx(exact)); context - .verify_tx(&exact_tx, MAX_CYCLES) + .verify(&exact_tx, MAX_CYCLES) .expect("fresh deposit creation in the same transaction should not let above-cap receipt conversion escape the per-receipt soft-cap discount"); } diff --git a/scripts/tests/src/tests/ickb_logic/xudt_amount_limits.rs b/scripts/tests/src/tests/ickb_logic/xudt_amount_limits.rs index 661fa8e..2a3693d 100644 --- a/scripts/tests/src/tests/ickb_logic/xudt_amount_limits.rs +++ b/scripts/tests/src/tests/ickb_logic/xudt_amount_limits.rs @@ -16,7 +16,7 @@ fn oversized_output_udt_amount_is_rejected() { ); let receipt_out_point = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(12).pack()) + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) .lock(funding_lock.clone()) .type_(Some(ickb_logic.clone()).pack()) .build(), @@ -29,7 +29,7 @@ fn oversized_output_udt_amount_is_rejected() { .input(CellInput::new_builder().previous_output(receipt_out_point).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -39,7 +39,7 @@ fn oversized_output_udt_amount_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_AMOUNT_UNREASONABLY_BIG); } @@ -52,7 +52,7 @@ fn xudt_amount_at_u64_max_boundary_is_allowed() { let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -63,7 +63,7 @@ fn xudt_amount_at_u64_max_boundary_is_allowed() { .input(CellInput::new_builder().previous_output(udt_input).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock) .type_(Some(xudt).pack()) .build(), @@ -73,6 +73,6 @@ fn xudt_amount_at_u64_max_boundary_is_allowed() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("u64::MAX should remain a valid xUDT amount boundary"); } diff --git a/scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs b/scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs index b0d30f0..536165d 100644 --- a/scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs +++ b/scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs @@ -20,7 +20,7 @@ fn xudt_owner_script_output_witness_cannot_mint_without_live_owner_mode() { .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) .lock(funding_lock) .type_(Some(xudt).pack()) .build(), @@ -30,7 +30,7 @@ fn xudt_owner_script_output_witness_cannot_mint_without_live_owner_mode() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_XUDT_AMOUNT); } @@ -43,7 +43,7 @@ fn xudt_owner_script_input_witness_cannot_mint_without_live_owner_mode() { let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -55,7 +55,7 @@ fn xudt_owner_script_input_witness_cannot_mint_without_live_owner_mode() { .input(CellInput::new_builder().previous_output(udt_input).build()) .output( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock) .type_(Some(xudt).pack()) .build(), @@ -65,6 +65,6 @@ fn xudt_owner_script_input_witness_cannot_mint_without_live_owner_mode() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_XUDT_AMOUNT); } diff --git a/scripts/tests/src/tests/limit_order/crosswire_blockers.rs b/scripts/tests/src/tests/limit_order/crosswire_blockers.rs index d3dd1a7..3060d69 100644 --- a/scripts/tests/src/tests/limit_order/crosswire_blockers.rs +++ b/scripts/tests/src/tests/limit_order/crosswire_blockers.rs @@ -41,7 +41,7 @@ fn distinct_mint_capacities_block_master_crosswire() { .build(); let crosswire_tx = context.complete_tx(crosswire_tx); - let err = context.verify_tx(&crosswire_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&crosswire_tx, MAX_CYCLES).unwrap_err(); assert_script_error_in( err, &[ @@ -85,7 +85,7 @@ fn distinct_match_progress_blocks_master_crosswire() { .build(); let order1_match_tx = context.complete_tx(order1_match_tx); context - .verify_tx(&order1_match_tx, MAX_CYCLES) + .verify(&order1_match_tx, MAX_CYCLES) .expect("order1 should enter its first match state"); let order1_matched = OutPoint::new(order1_match_tx.hash(), 0); context.create_cell_with_out_point( @@ -108,7 +108,7 @@ fn distinct_match_progress_blocks_master_crosswire() { .build(); let order2_match_tx = context.complete_tx(order2_match_tx); context - .verify_tx(&order2_match_tx, MAX_CYCLES) + .verify(&order2_match_tx, MAX_CYCLES) .expect("order2 should enter a later match state with different progress"); let order2_matched = OutPoint::new(order2_match_tx.hash(), 0); context.create_cell_with_out_point( @@ -138,7 +138,7 @@ fn distinct_match_progress_blocks_master_crosswire() { .build(); let crosswire_tx = context.complete_tx(crosswire_tx); - let err = context.verify_tx(&crosswire_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&crosswire_tx, MAX_CYCLES).unwrap_err(); assert_script_error_in( err, &[ @@ -182,7 +182,7 @@ fn real_mint_and_match_orders_cannot_crosswire_masters() { .build(); let seed_match_tx = context.complete_tx(seed_match_tx); context - .verify_tx(&seed_match_tx, MAX_CYCLES) + .verify(&seed_match_tx, MAX_CYCLES) .expect("the second real order should enter match state before the mixed crosswire"); let match_order_input = OutPoint::new(seed_match_tx.hash(), 0); context.create_cell_with_out_point( @@ -212,7 +212,7 @@ fn real_mint_and_match_orders_cannot_crosswire_masters() { .build(); let crosswire_tx = context.complete_tx(crosswire_tx); - let err = context.verify_tx(&crosswire_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&crosswire_tx, MAX_CYCLES).unwrap_err(); assert_script_error_in( err, &[ @@ -358,6 +358,6 @@ fn different_info_mainnet_orders_cannot_crosswire_during_match() { .build(); let crosswire_tx = context.complete_tx(crosswire_tx); - let err = context.verify_tx(&crosswire_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&crosswire_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_DIFFERENT_INFO); } diff --git a/scripts/tests/src/tests/limit_order/crosswire_live_match.rs b/scripts/tests/src/tests/limit_order/crosswire_live_match.rs index e435373..84ec4a1 100644 --- a/scripts/tests/src/tests/limit_order/crosswire_live_match.rs +++ b/scripts/tests/src/tests/limit_order/crosswire_live_match.rs @@ -1,8 +1,8 @@ use super::*; -// Continue two indistinguishable real orders into swapped match outputs; the match path accepts, then the swapped master lock can melt while the original master can no longer do so. +// Continue two indistinguishable real orders into permuted match outputs; each output remains redeemable by the master encoded in its data. #[test] -fn cloned_live_orders_can_swap_masters_during_match() { +fn cloned_live_orders_can_permute_without_stranding_either_master() { let mut context = Context::default(); let (owner1_key, owner1_lock, owner1_secp_data_dep) = secp_lock(&mut context); let (owner2_key, owner2_lock, owner2_secp_data_dep) = secp_lock(&mut context); @@ -35,12 +35,12 @@ fn cloned_live_orders_can_swap_masters_during_match() { let crosswire_tx = context.complete_tx(crosswire_tx); context - .verify_tx(&crosswire_tx, MAX_CYCLES) + .verify(&crosswire_tx, MAX_CYCLES) .expect("two cloned live orders with indistinguishable checked state can be re-emitted as matched orders that permute their master metapoints"); - // Materialize both matched outputs as live cells; the follow-up check only spends order1. + // Materialize both matched outputs and redeem each by its encoded master. let crosswired_order1 = seed_verified_output(&mut context, &crosswire_tx, 0, matched_order1_data); - seed_verified_output(&mut context, &crosswire_tx, 1, matched_order2_data); + let crosswired_order2 = seed_verified_output(&mut context, &crosswire_tx, 1, matched_order2_data); let rebound_melt = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(crosswired_order1.clone()).build()) @@ -58,11 +58,11 @@ fn cloned_live_orders_can_swap_masters_during_match() { .build(); let rebound_melt = sign_tx_by_input_group(context.complete_tx(rebound_melt), &owner2_key, 1, 1); context - .verify_tx(&rebound_melt, MAX_CYCLES) + .verify(&rebound_melt, MAX_CYCLES) .expect("the alternate master can melt the permuted cloned continuation after the metapoint swap"); - let intended_melt = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(crosswired_order1).build()) + let other_melt = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(crosswired_order2).build()) .input(CellInput::new_builder().previous_output(master1_input).build()) .output( CellOutput::new_builder() @@ -75,9 +75,10 @@ fn cloned_live_orders_can_swap_masters_during_match() { .witness(empty_witness().pack()) .cell_dep(owner1_secp_data_dep) .build(); - let intended_melt = sign_tx_by_input_group(context.complete_tx(intended_melt), &owner1_key, 1, 1); - let err = context.verify_tx(&intended_melt, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); + let other_melt = sign_tx_by_input_group(context.complete_tx(other_melt), &owner1_key, 1, 1); + context + .verify(&other_melt, MAX_CYCLES) + .expect("the other permuted continuation should remain redeemable by its encoded master"); } // Mix a forged match-shaped input with one real order, keep each metapoint on its own output, and confirm only the real lineage still melts with the real master. @@ -122,7 +123,7 @@ fn hybrid_fake_and_real_limit_order_match_keeps_real_master_on_real_metapoint() let hybrid_tx = context.complete_tx(hybrid_tx); context - .verify_tx(&hybrid_tx, MAX_CYCLES) + .verify(&hybrid_tx, MAX_CYCLES) .expect("a fake match-shaped input can coexist with a real order in one valid match tx"); let hybrid_hash = hybrid_tx.hash(); @@ -155,7 +156,7 @@ fn hybrid_fake_and_real_limit_order_match_keeps_real_master_on_real_metapoint() .build(); let real_lineage_melt = sign_tx_by_input_group(context.complete_tx(real_lineage_melt), &owner_key, 1, 1); context - .verify_tx(&real_lineage_melt, MAX_CYCLES) + .verify(&real_lineage_melt, MAX_CYCLES) .expect("the real master should still authorize the melt on the real metapoint in the hybrid match"); let fake_lineage_melt_with_real_master = TransactionBuilder::default() @@ -179,7 +180,7 @@ fn hybrid_fake_and_real_limit_order_match_keeps_real_master_on_real_metapoint() 1, ); let err = context - .verify_tx(&fake_lineage_melt_with_real_master, MAX_CYCLES) + .verify(&fake_lineage_melt_with_real_master, MAX_CYCLES) .unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } diff --git a/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs b/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs index 1d52a6d..b25a74c 100644 --- a/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs +++ b/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs @@ -1,6 +1,6 @@ use super::*; -// Create two mint pairs with crosswired distances while neither master lock executes; creation passes, the swapped master can melt, and the intuitive pairing fails. +// Create two mint pairs with crosswired distances: the script still pairs each order with exactly one master, so creation passes, the swapped master can melt, and the intuitive pairing fails. #[test] fn mint_crosswire_swaps_order_masters() { let mut context = Context::default(); @@ -25,7 +25,7 @@ fn mint_crosswire_swaps_order_masters() { .type_(Some(helper_type.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner1_lock, &limit_order, 0).pack()) .lock(owner1_lock.clone()) .type_(Some(limit_order.clone()).pack()) .build(), @@ -35,7 +35,7 @@ fn mint_crosswire_swaps_order_masters() { .type_(Some(helper_type.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner2_lock, &limit_order, 0).pack()) .lock(owner2_lock.clone()) .type_(Some(limit_order.clone()).pack()) .build(), @@ -53,7 +53,7 @@ fn mint_crosswire_swaps_order_masters() { let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("cross-wired master assignment should pass deployed mint validation"); let tx_hash = create_tx.hash(); @@ -95,7 +95,7 @@ fn mint_crosswire_swaps_order_masters() { .build(); let melt_other_users_order = context.complete_tx(melt_other_users_order); context - .verify_tx(&melt_other_users_order, MAX_CYCLES) + .verify(&melt_other_users_order, MAX_CYCLES) .expect("master1 is bound to order2 when mint distances are cross-wired"); let melt_expected_order = TransactionBuilder::default() @@ -110,11 +110,11 @@ fn mint_crosswire_swaps_order_masters() { .output_data(Bytes::new().pack()) .build(); let melt_expected_order = context.complete_tx(melt_expected_order); - let err = context.verify_tx(&melt_expected_order, MAX_CYCLES).unwrap_err(); + let err = context.verify(&melt_expected_order, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } -// Create the same crosswire through sparse output spacing and negative distances; mint passes without executing master locks, and the far paired master remains the valid melt path. +// Create the same crosswire through sparse output spacing and negative distances; limit_order runs at mint and accepts the crosswired distances, and the far paired master remains the valid melt path. #[test] fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { let mut context = Context::default(); @@ -142,7 +142,7 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { for _ in 0..8 { outputs.push( CellOutput::new_builder() - .capacity(100u64.pack()) + .capacity((100 * CKB).pack()) .lock(filler_lock.clone()) .build(), ); @@ -158,14 +158,14 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { outputs_data.push(order_data_mint(0, 3, (1, 1))); outputs.push( CellOutput::new_builder() - .capacity(100u64.pack()) + .capacity((100 * CKB).pack()) .lock(filler_lock) .build(), ); outputs_data.push(Bytes::new()); outputs.push( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner2_lock, &limit_order, 0).pack()) .lock(owner2_lock.clone()) .type_(Some(limit_order.clone()).pack()) .build(), @@ -173,7 +173,7 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { outputs_data.push(Bytes::new()); outputs.push( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner1_lock, &limit_order, 0).pack()) .lock(owner1_lock.clone()) .type_(Some(limit_order.clone()).pack()) .build(), @@ -188,7 +188,7 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("sparse far-distance crosswire should still pass deployed mint validation"); let tx_hash = create_tx.hash(); @@ -231,7 +231,7 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { let melt_crosswired = context.complete_tx(melt_crosswired); context - .verify_tx(&melt_crosswired, MAX_CYCLES) + .verify(&melt_crosswired, MAX_CYCLES) .expect("far-distance sparse layout still binds order1 to owner2's master"); let melt_expected = TransactionBuilder::default() @@ -246,6 +246,6 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { .output_data(Bytes::new().pack()) .build(); let melt_expected = context.complete_tx(melt_expected); - let err = context.verify_tx(&melt_expected, MAX_CYCLES).unwrap_err(); + let err = context.verify(&melt_expected, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } diff --git a/scripts/tests/src/tests/limit_order/fake_match_lineage.rs b/scripts/tests/src/tests/limit_order/fake_match_lineage.rs index 45a9226..8189ef7 100644 --- a/scripts/tests/src/tests/limit_order/fake_match_lineage.rs +++ b/scripts/tests/src/tests/limit_order/fake_match_lineage.rs @@ -30,7 +30,7 @@ fn fake_match_lineage_can_keep_advancing_without_real_master() { let first_match_tx = context.complete_tx(first_match_tx); context - .verify_tx(&first_match_tx, MAX_CYCLES) + .verify(&first_match_tx, MAX_CYCLES) .expect("a forged match-shaped order should survive one valid-looking match transition without any real master"); let first_match_out_point = OutPoint::new(first_match_tx.hash(), 0); @@ -54,26 +54,70 @@ fn fake_match_lineage_can_keep_advancing_without_real_master() { let second_match_tx = context.complete_tx(second_match_tx); context - .verify_tx(&second_match_tx, MAX_CYCLES) + .verify(&second_match_tx, MAX_CYCLES) .expect("the fake match-shaped lineage should stay reusable across multiple later match transitions without any real master"); } -// Forge a match-shaped order that points at a real master, melt through that real master lock, then show the legitimate order is stranded because its master was already consumed. +// Forge a foreign-token order with unrelated pricing that points at a real master, melt through that master, then show the legitimate order is stranded. #[test] -fn fake_match_order_can_strand_real_order() { +fn foreign_token_fake_order_with_arbitrary_info_can_strand_real_order() { let mut context = Context::default(); let (owner_lock, helper_type) = named_lock_and_helper_type_scripts(&mut context, b"owner"); - let (real_order_out_point, real_master_out_point) = - build_real_limit_order_and_master(&mut context, owner_lock.clone(), helper_type.clone()); - let limit_order = limit_order_script(&mut context); + let funding_lock = always_success_lock(&mut context); + let funding_input = context.create_cell( + CellOutput::new_builder() + .capacity((1_700 * CKB).pack()) + .lock(funding_lock) + .build(), + Bytes::new(), + ); + let mint_tx = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(funding_input).build()) + .outputs(vec![ + CellOutput::new_builder() + .capacity((1_500 * CKB).pack()) + .lock(limit_order.clone()) + .type_(Some(helper_type).pack()) + .build(), + CellOutput::new_builder() + .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) + .lock(owner_lock.clone()) + .type_(Some(limit_order.clone()).pack()) + .build(), + ]) + .outputs_data(vec![order_data_mint(0, 1, (1, 1)), Bytes::new()].pack()) + .build(); + let mint_tx = context.complete_tx(mint_tx); + context + .verify(&mint_tx, MAX_CYCLES) + .expect("the real order and occupied-capacity-valid master should mint"); + let real_order_out_point = + seed_verified_output(&mut context, &mint_tx, 0, order_data_mint(0, 1, (1, 1))); + let real_master_out_point = seed_verified_output(&mut context, &mint_tx, 1, Bytes::new()); + + let foreign_token = named_always_success_lock(&mut context, b"foreign-token"); + let master_index: u32 = real_master_out_point.index().unpack(); + let fake_data = order_data_custom( + 123, + 1, + real_master_out_point + .tx_hash() + .as_slice() + .try_into() + .expect("master tx hash"), + master_index.to_le_bytes(), + (7, 11), + (0, 0), + 42, + ); let phantom_order_out_point = context.create_cell( CellOutput::new_builder() .capacity((1_500 * CKB).pack()) .lock(limit_order) - .type_(Some(helper_type).pack()) + .type_(Some(foreign_token).pack()) .build(), - order_data_match(0, &real_master_out_point, (1, 1)), + fake_data, ); let tx = TransactionBuilder::default() @@ -98,8 +142,8 @@ fn fake_match_order_can_strand_real_order() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) - .expect("a fake match-shaped order should melt successfully against the referenced real master"); + .verify(&tx, MAX_CYCLES) + .expect("a foreign-token fake order with arbitrary pricing should melt against the referenced real master"); let stranded_order_tx = TransactionBuilder::default() .input( @@ -116,6 +160,6 @@ fn fake_match_order_can_strand_real_order() { .output_data(Bytes::new().pack()) .build(); let stranded_order_tx = context.complete_tx(stranded_order_tx); - let err = context.verify_tx(&stranded_order_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&stranded_order_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } diff --git a/scripts/tests/src/tests/limit_order/fulfilled.rs b/scripts/tests/src/tests/limit_order/fulfilled.rs index e305a06..dba7669 100644 --- a/scripts/tests/src/tests/limit_order/fulfilled.rs +++ b/scripts/tests/src/tests/limit_order/fulfilled.rs @@ -1,15 +1,15 @@ use super::*; -// Continue a fulfilled CKB->UDT-shaped match cell as if matching again; the lock path traps before a typed fulfilled-order error is surfaced. +// An occupied-capacity-valid fulfilled CKB->UDT cell has no capacity left to decrease, so a continuation fails the outer match-shape check. #[test] -fn fulfilled_ckb_to_udt_shape_cannot_reopen_as_match() { +fn fulfilled_ckb_to_udt_shape_fails_as_invalid_match() { let mut context = Context::default(); let (limit_order, helper_type) = limit_order_and_helper_type_scripts(&mut context); let master = OutPoint::new(Byte32::zero(), 5); let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 0).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 0).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -20,7 +20,7 @@ fn fulfilled_ckb_to_udt_shape_cannot_reopen_as_match() { .input(CellInput::new_builder().previous_output(input_order).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 0).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 0).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -29,10 +29,8 @@ fn fulfilled_ckb_to_udt_shape_cannot_reopen_as_match() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); - // The deployed release binary traps with a generic -1 here instead of surfacing the - // internal AttemptToChangeFulfilled branch as a typed script error. - assert_script_error(err, ERROR_SCRIPT_PANIC); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); + assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_MATCH); } // Forge a fulfilled UDT->CKB-shaped cell and try to continue it; this shape never reaches the inner fulfilled guard and instead fails the outer match validation. @@ -43,7 +41,7 @@ fn fulfilled_udt_to_ckb_shape_cannot_reach_guard_and_fails_as_invalid_match() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -62,7 +60,7 @@ fn fulfilled_udt_to_ckb_shape_cannot_reach_guard_and_fails_as_invalid_match() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -83,6 +81,6 @@ fn fulfilled_udt_to_ckb_shape_cannot_reach_guard_and_fails_as_invalid_match() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_MATCH); } diff --git a/scripts/tests/src/tests/limit_order/lock_only_shapes.rs b/scripts/tests/src/tests/limit_order/lock_only_shapes.rs index 03aeac6..99f33d9 100644 --- a/scripts/tests/src/tests/limit_order/lock_only_shapes.rs +++ b/scripts/tests/src/tests/limit_order/lock_only_shapes.rs @@ -19,7 +19,7 @@ fn non_empty_args_output_lock_can_be_created_but_not_spent() { .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order_non_empty, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order_non_empty, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order_non_empty.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -28,12 +28,12 @@ fn non_empty_args_output_lock_can_be_created_but_not_spent() { .build(); let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("non-empty-args limit_order output lock can be created because output locks do not execute"); let out_point = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order_non_empty, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order_non_empty, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order_non_empty.clone()) .type_(Some(helper_type).pack()) .build(), @@ -50,7 +50,7 @@ fn non_empty_args_output_lock_can_be_created_but_not_spent() { .output_data(Bytes::new().pack()) .build(); let spend_tx = context.complete_tx(spend_tx); - let err = context.verify_tx(&spend_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&spend_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); } @@ -72,7 +72,7 @@ fn cell_using_limit_order_as_both_lock_and_type_is_rejected() { .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&limit_order, &limit_order, 0).pack()) .lock(limit_order.clone()) .type_(Some(limit_order).pack()) .build(), @@ -81,7 +81,7 @@ fn cell_using_limit_order_as_both_lock_and_type_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_SCRIPT_MISUSE); } @@ -145,16 +145,16 @@ fn lock_only_limit_order_with_both_ratios_null_can_be_created_but_not_spent() { ); } -// Forge a lock-only order with no UDT type and just-enough occupied capacity; creation skips the lock, but spending reaches the input path and traps generically. +// Forge a lock-only order with no UDT type and exact occupied capacity; spending reaches the typed missing-UDT check. #[test] -fn lock_only_limit_order_missing_udt_type_hits_generic_failure_even_at_valid_capacity() { +fn lock_only_limit_order_missing_udt_type_returns_typed_error_at_valid_capacity() { let mut context = Context::default(); let funding_lock = always_success_lock(&mut context); let limit_order = limit_order_script(&mut context); let forged_output = CellOutput::new_builder().lock(limit_order.clone()).build(); let forged_capacity = forged_output .occupied_capacity( - ckb_testtool::ckb_types::core::Capacity::bytes(73) + ckb_testtool::ckb_types::core::Capacity::bytes(89) .expect("occupied capacity bytes"), ) .expect("occupied capacity") @@ -180,7 +180,7 @@ fn lock_only_limit_order_missing_udt_type_hits_generic_failure_even_at_valid_cap .build(); let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("lock-only limit_order output without a UDT type can still be created"); let forged_out_point = context.create_cell( @@ -199,10 +199,8 @@ fn lock_only_limit_order_missing_udt_type_hits_generic_failure_even_at_valid_cap .build(); let spend_tx = context.complete_tx(spend_tx); - let err = context.verify_tx(&spend_tx, MAX_CYCLES).unwrap_err(); - // The committed release binary traps with a generic -1 here instead of surfacing a stable - // MissingUdtType code, even when the forged order uses an occupied-capacity-valid layout. - assert_script_error(err, ERROR_SCRIPT_PANIC); + let err = context.verify(&spend_tx, MAX_CYCLES).unwrap_err(); + assert_script_error(err, ERROR_LIMIT_ORDER_MISSING_UDT_TYPE); } // Create a lock-only output with valid mint data plus trailing bytes, then spend it and fail on the input-side length check. diff --git a/scripts/tests/src/tests/limit_order/master_admission.rs b/scripts/tests/src/tests/limit_order/master_admission.rs index 80d1ef4..4211931 100644 --- a/scripts/tests/src/tests/limit_order/master_admission.rs +++ b/scripts/tests/src/tests/limit_order/master_admission.rs @@ -27,7 +27,7 @@ fn mint_accepts_master_with_unspendable_foreign_lock() { ) .output( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&poisoned_lock, &limit_order, 0).pack()) .lock(poisoned_lock) .type_(Some(limit_order.clone()).pack()) .build(), @@ -37,7 +37,7 @@ fn mint_accepts_master_with_unspendable_foreign_lock() { let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("limit_order mint accepts a master whose lock never executed on creation"); let tx_hash = create_tx.hash(); @@ -67,7 +67,7 @@ fn mint_accepts_master_with_unspendable_foreign_lock() { .build(); let melt_tx = context.complete_tx(melt_tx); - let err = context.verify_tx(&melt_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&melt_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); } @@ -98,7 +98,7 @@ fn mint_accepts_master_with_empty_args_ickb_logic_lock_and_strands_on_spend() { ) .output( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&benign_foreign_lock, &limit_order, 0).pack()) .lock(benign_foreign_lock) .type_(Some(limit_order.clone()).pack()) .build(), @@ -108,7 +108,7 @@ fn mint_accepts_master_with_empty_args_ickb_logic_lock_and_strands_on_spend() { let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("limit_order mint accepts an empty-args ickb_logic master lock at creation"); let tx_hash = create_tx.hash(); @@ -138,6 +138,6 @@ fn mint_accepts_master_with_empty_args_ickb_logic_lock_and_strands_on_spend() { .build(); let melt_tx = context.complete_tx(melt_tx); - let err = context.verify_tx(&melt_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&melt_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SCRIPT_MISUSE); } diff --git a/scripts/tests/src/tests/limit_order/match_progression.rs b/scripts/tests/src/tests/limit_order/match_progression.rs index e7ca1c5..43592c7 100644 --- a/scripts/tests/src/tests/limit_order/match_progression.rs +++ b/scripts/tests/src/tests/limit_order/match_progression.rs @@ -8,7 +8,7 @@ fn udt_to_ckb_match_passes() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -27,7 +27,7 @@ fn udt_to_ckb_match_passes() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -47,7 +47,7 @@ fn udt_to_ckb_match_passes() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("udt-to-ckb partial matches should verify when value and minimum match hold"); } @@ -59,7 +59,7 @@ fn udt_to_ckb_match_accepts_exact_minimum_partial_fill() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -78,7 +78,7 @@ fn udt_to_ckb_match_accepts_exact_minimum_partial_fill() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_516 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_516 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -98,7 +98,7 @@ fn udt_to_ckb_match_accepts_exact_minimum_partial_fill() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("udt-to-ckb partial matches should verify when the fill lands exactly on the minimum boundary"); } @@ -112,7 +112,7 @@ fn valid_match_ignores_foreign_typed_output() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -131,7 +131,7 @@ fn valid_match_ignores_foreign_typed_output() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -157,7 +157,7 @@ fn valid_match_ignores_foreign_typed_output() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("limit_order should ignore unrelated foreign typed outputs during a valid match"); } @@ -169,23 +169,25 @@ fn ckb_to_udt_match_passes_with_both_ratios_present() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), order_data_custom(0, 1, [0u8; 32], 5u32.to_le_bytes(), (1, 1), (1, 1), 4), ); + // The matcher collects the 20 CKB into its own funding cell, which a bare 20 CKB cell could not hold. let tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(input_order).build()) + .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_480 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_480 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), CellOutput::new_builder() - .capacity((20 * CKB).pack()) + .capacity((1_020 * CKB).pack()) .lock(funding_lock) .build(), ]) @@ -208,7 +210,7 @@ fn ckb_to_udt_match_passes_with_both_ratios_present() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("ckb-to-udt partial matches should verify when both ratios are present and value is preserved"); } @@ -220,7 +222,7 @@ fn ckb_to_udt_match_accepts_exact_minimum_partial_fill() { let input_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -231,7 +233,7 @@ fn ckb_to_udt_match_accepts_exact_minimum_partial_fill() { .input(CellInput::new_builder().previous_output(input_order_out_point).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB - 16).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB - 16).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -241,7 +243,7 @@ fn ckb_to_udt_match_accepts_exact_minimum_partial_fill() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("ckb-to-udt partial matches should verify when the fill lands exactly on the minimum boundary"); } @@ -253,7 +255,7 @@ fn udt_to_ckb_match_rejects_small_udt_delta_under_minimum() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -272,7 +274,7 @@ fn udt_to_ckb_match_rejects_small_udt_delta_under_minimum() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -291,7 +293,7 @@ fn udt_to_ckb_match_rejects_small_udt_delta_under_minimum() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INSUFFICIENT_MATCH); } @@ -303,7 +305,7 @@ fn udt_to_ckb_match_rejects_large_minimum_partial_fill() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -322,7 +324,7 @@ fn udt_to_ckb_match_rejects_large_minimum_partial_fill() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -341,7 +343,7 @@ fn udt_to_ckb_match_rejects_large_minimum_partial_fill() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INSUFFICIENT_MATCH); } @@ -354,7 +356,7 @@ fn match_rejects_invalid_direction_change() { let input_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -365,7 +367,7 @@ fn match_rejects_invalid_direction_change() { .input(CellInput::new_builder().previous_output(input_order_out_point).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_400 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_400 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -374,7 +376,7 @@ fn match_rejects_invalid_direction_change() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_MATCH); } @@ -387,7 +389,7 @@ fn match_rejects_unchanged_shape() { let input_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -398,7 +400,7 @@ fn match_rejects_unchanged_shape() { .input(CellInput::new_builder().previous_output(input_order_out_point).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -407,7 +409,7 @@ fn match_rejects_unchanged_shape() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_MATCH); } @@ -420,7 +422,7 @@ fn match_rejects_decreasing_value() { let input_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -431,7 +433,7 @@ fn match_rejects_decreasing_value() { .input(CellInput::new_builder().previous_output(input_order_out_point).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_400 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_400 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -440,7 +442,7 @@ fn match_rejects_decreasing_value() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_DECREASING_VALUE); } @@ -452,7 +454,7 @@ fn match_rejects_too_small_partial_fill() { let input_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -463,7 +465,7 @@ fn match_rejects_too_small_partial_fill() { .input(CellInput::new_builder().previous_output(input_order_out_point).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB - 8).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB - 8).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -472,19 +474,19 @@ fn match_rejects_too_small_partial_fill() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INSUFFICIENT_MATCH); } -// Continue an almost-empty CKB->UDT order down to zero unoccupied value; the input lock traps generically instead of surfacing a stable typed error. +// Fully fill a CKB->UDT order down to its exact occupied capacity; terminal fills bypass the partial-fill minimum. #[test] -fn zero_unoccupied_match_shape_hits_generic_failure() { +fn ckb_to_udt_terminal_full_fill_passes_at_occupied_capacity() { let mut context = Context::default(); let (limit_order, helper_type) = limit_order_and_helper_type_scripts(&mut context); let input_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 8).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 8).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -495,7 +497,7 @@ fn zero_unoccupied_match_shape_hits_generic_failure() { .input(CellInput::new_builder().previous_output(input_order_out_point).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 0).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 0).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -504,8 +506,7 @@ fn zero_unoccupied_match_shape_hits_generic_failure() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); - // The deployed release binary traps with a generic -1 here instead of surfacing a stable - // typed error for this zero-unoccupied transition shape. - assert_script_error(err, ERROR_SCRIPT_PANIC); + context + .verify(&tx, MAX_CYCLES) + .expect("a terminal full fill at exact occupied capacity should verify"); } diff --git a/scripts/tests/src/tests/limit_order/mint_shape_validation.rs b/scripts/tests/src/tests/limit_order/mint_shape_validation.rs index cecceea..f9c179a 100644 --- a/scripts/tests/src/tests/limit_order/mint_shape_validation.rs +++ b/scripts/tests/src/tests/limit_order/mint_shape_validation.rs @@ -27,7 +27,7 @@ fn mint_accepts_ckb_min_match_log_64() { ) .output( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) .lock(owner_lock) .type_(Some(limit_order).pack()) .build(), @@ -43,7 +43,7 @@ fn mint_accepts_ckb_min_match_log_64() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("ckb_min_match_log == 64 should be accepted at the encoding boundary"); } @@ -74,7 +74,7 @@ fn mint_rejects_ckb_min_match_log_65() { ) .output( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) .lock(owner_lock) .type_(Some(limit_order).pack()) .build(), @@ -89,7 +89,7 @@ fn mint_rejects_ckb_min_match_log_65() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CKB_MIN_MATCH_LOG); } @@ -112,12 +112,12 @@ fn two_master_outputs_fail_as_invalid_configuration_not_duplicate_master() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) .lock(owner_lock.clone()) .type_(Some(limit_order.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) .lock(owner_lock) .type_(Some(limit_order).pack()) .build(), @@ -126,6 +126,6 @@ fn two_master_outputs_fail_as_invalid_configuration_not_duplicate_master() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } diff --git a/scripts/tests/src/tests/limit_order/phantom_lineage.rs b/scripts/tests/src/tests/limit_order/phantom_lineage.rs index f504d63..be78425 100644 --- a/scripts/tests/src/tests/limit_order/phantom_lineage.rs +++ b/scripts/tests/src/tests/limit_order/phantom_lineage.rs @@ -1,6 +1,6 @@ use super::*; -// Create a mint-shaped output lock with no real master cell behind its distance; creation passes because no master lock executes on output. +// Create a mint-shaped output lock with no real master cell behind its distance; creation passes because the transaction holds no master cell, so limit_order never runs, and the order's own lock does not execute on output. #[test] fn phantom_mint_output_can_be_created() { let mut context = Context::default(); @@ -28,7 +28,7 @@ fn phantom_mint_output_can_be_created() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("phantom order creation should bypass limit_order validation"); } @@ -66,7 +66,7 @@ fn phantom_mint_lineage_can_enter_match_without_real_master() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("a phantom mint-shaped order should be able to transition into match state without any real master"); } @@ -103,7 +103,7 @@ fn phantom_mint_lineage_cannot_rebind_to_an_arbitrary_fake_match_master() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } @@ -140,7 +140,7 @@ fn phantom_limit_order_match_still_requires_same_order_info() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_DIFFERENT_INFO); } @@ -175,7 +175,7 @@ fn phantom_limit_order_cannot_be_melted_without_a_master_input() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } @@ -196,7 +196,7 @@ fn phantom_limit_order_cannot_be_melted_with_an_unrelated_master() { ); let unrelated_master_out_point = context.create_cell( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) .lock(owner_lock.clone()) .type_(Some(limit_order).pack()) .build(), @@ -224,7 +224,7 @@ fn phantom_limit_order_cannot_be_melted_with_an_unrelated_master() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } @@ -258,6 +258,6 @@ fn lock_only_limit_order_output_can_be_created_with_match_order_data() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("lock-only output can be created with MatchOrderData"); } diff --git a/scripts/tests/src/tests/limit_order/poisoning.rs b/scripts/tests/src/tests/limit_order/poisoning.rs index 653d236..1633106 100644 --- a/scripts/tests/src/tests/limit_order/poisoning.rs +++ b/scripts/tests/src/tests/limit_order/poisoning.rs @@ -9,7 +9,7 @@ fn unrelated_non_empty_args_output_lock_poisons_match() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -28,7 +28,7 @@ fn unrelated_non_empty_args_output_lock_poisons_match() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -37,7 +37,7 @@ fn unrelated_non_empty_args_output_lock_poisons_match() { .lock(funding_lock) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(poisoned_lock) .build(), ]) @@ -52,7 +52,7 @@ fn unrelated_non_empty_args_output_lock_poisons_match() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); } @@ -67,7 +67,7 @@ fn order_shaped_non_empty_args_output_poisons_match() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -86,7 +86,7 @@ fn order_shaped_non_empty_args_output_poisons_match() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type.clone()).pack()) .build(), @@ -95,7 +95,7 @@ fn order_shaped_non_empty_args_output_poisons_match() { .lock(funding_lock) .build(), CellOutput::new_builder() - .capacity(deposit_capacity(&poisoned_lock, &helper_type, 73, 300 * CKB).pack()) + .capacity(deposit_capacity(&poisoned_lock, &helper_type, 89, 300 * CKB).pack()) .lock(poisoned_lock) .type_(Some(helper_type).pack()) .build(), @@ -111,7 +111,7 @@ fn order_shaped_non_empty_args_output_poisons_match() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); } @@ -127,7 +127,7 @@ fn non_empty_args_master_sibling_poisons_match() { let input_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -142,7 +142,7 @@ fn non_empty_args_master_sibling_poisons_match() { ); let poisoned_master_input = context.create_cell( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(owner_lock) .type_(Some(poisoned_master_type).pack()) .build(), @@ -155,7 +155,7 @@ fn non_empty_args_master_sibling_poisons_match() { .input(CellInput::new_builder().previous_output(poisoned_master_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_520 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -174,6 +174,6 @@ fn non_empty_args_master_sibling_poisons_match() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); } diff --git a/scripts/tests/src/tests/limit_order/real_lineage.rs b/scripts/tests/src/tests/limit_order/real_lineage.rs index 26f5848..da25a94 100644 --- a/scripts/tests/src/tests/limit_order/real_lineage.rs +++ b/scripts/tests/src/tests/limit_order/real_lineage.rs @@ -28,7 +28,7 @@ fn real_order_match_cannot_rewrite_master_outpoint_to_an_arbitrary_master() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } @@ -59,7 +59,7 @@ fn real_limit_order_can_transition_from_mint_to_match_without_consuming_master() let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("a real minted order should be able to move into a match-state output without consuming its master"); } @@ -89,6 +89,6 @@ fn real_limit_order_match_rejects_rewriting_order_info() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_DIFFERENT_INFO); } diff --git a/scripts/tests/src/tests/limit_order/remint.rs b/scripts/tests/src/tests/limit_order/remint.rs index f3d4f82..c5aa3c0 100644 --- a/scripts/tests/src/tests/limit_order/remint.rs +++ b/scripts/tests/src/tests/limit_order/remint.rs @@ -11,7 +11,7 @@ fn can_atomically_melt_and_remint_with_negative_distance_and_filler() { build_real_limit_order_and_master(&mut context, owner_lock.clone(), helper_type.clone()); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity(100u64.pack()) + .capacity((100 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -24,12 +24,12 @@ fn can_atomically_melt_and_remint_with_negative_distance_and_filler() { .input(CellInput::new_builder().previous_output(funding_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) .lock(owner_lock.clone()) .type_(Some(limit_order.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(100u64.pack()) + .capacity((100 * CKB).pack()) .lock(filler_lock) .build(), CellOutput::new_builder() @@ -43,7 +43,7 @@ fn can_atomically_melt_and_remint_with_negative_distance_and_filler() { let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("limit_order should allow canceling one pair while minting a new sparse negative-distance pair in the same tx"); let tx_hash = create_tx.hash(); @@ -73,6 +73,6 @@ fn can_atomically_melt_and_remint_with_negative_distance_and_filler() { .build(); let melt_tx = context.complete_tx(melt_tx); context - .verify_tx(&melt_tx, MAX_CYCLES) + .verify(&melt_tx, MAX_CYCLES) .expect("the reminted sparse pair should remain a valid melt target"); } diff --git a/scripts/tests/src/tests/limit_order/same_master.rs b/scripts/tests/src/tests/limit_order/same_master.rs index 11bf748..40461f1 100644 --- a/scripts/tests/src/tests/limit_order/same_master.rs +++ b/scripts/tests/src/tests/limit_order/same_master.rs @@ -9,7 +9,7 @@ fn match_rejects_two_outputs_sharing_one_master() { let input_order_out_point = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -20,14 +20,14 @@ fn match_rejects_two_outputs_sharing_one_master() { .input(CellInput::new_builder().previous_output(input_order_out_point).build()) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_400 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_400 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), ) .output( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 100 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 100 * CKB).pack()) .lock(limit_order) .type_(Some(helper_type).pack()) .build(), @@ -42,7 +42,7 @@ fn match_rejects_two_outputs_sharing_one_master() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_SAME_MASTER); } @@ -55,7 +55,7 @@ fn same_master_collision_on_inputs_is_rejected() { let first_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_500 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -63,7 +63,7 @@ fn same_master_collision_on_inputs_is_rejected() { ); let second_order = context.create_cell( CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 73, 1_400 * CKB).pack()) + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_400 * CKB).pack()) .lock(limit_order.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -83,7 +83,7 @@ fn same_master_collision_on_inputs_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_SAME_MASTER); } @@ -100,7 +100,7 @@ fn duplicate_master_input_shape_is_blocked_before_script_invariants() { .input(CellInput::new_builder().previous_output(real_master_out_point).build()) .output( CellOutput::new_builder() - .capacity(400u64.pack()) + .capacity((400 * CKB).pack()) .lock(owner_lock) .build(), ) @@ -111,6 +111,6 @@ fn duplicate_master_input_shape_is_blocked_before_script_invariants() { // Duplicate inputs are rejected by transaction-level validation before the contract can reach // its internal DuplicatedMaster branch, so there is no stable limit_order error code to assert. context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect_err("duplicating a master input should be blocked before a reachable DuplicatedMaster path"); } diff --git a/scripts/tests/src/tests/owned_owner/dao_crosswiring.rs b/scripts/tests/src/tests/owned_owner/dao_crosswiring.rs index a3eaa17..6595508 100644 --- a/scripts/tests/src/tests/owned_owner/dao_crosswiring.rs +++ b/scripts/tests/src/tests/owned_owner/dao_crosswiring.rs @@ -34,7 +34,7 @@ fn crosswired_batch_is_blocked_by_dao_index_rules() { link_cell_to_header(&mut context, &deposit2, &header2); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user1_lock, &xudt, 16).pack()) .lock(user1_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -52,7 +52,7 @@ fn crosswired_batch_is_blocked_by_dao_index_rules() { .type_(Some(dao.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user1_lock, &owned_owner, 4).pack()) .lock(user1_lock) .type_(Some(owned_owner.clone()).pack()) .build(), @@ -62,7 +62,7 @@ fn crosswired_batch_is_blocked_by_dao_index_rules() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user2_lock, &owned_owner, 4).pack()) .lock(user2_lock) .type_(Some(owned_owner).pack()) .build(), @@ -81,8 +81,8 @@ fn crosswired_batch_is_blocked_by_dao_index_rules() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, -20); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); + assert_script_error(err, ERROR_DAO_INVALID_WITHDRAWING_CELL); } // This two-way batch keeps DAO index rules satisfied, so weak phase 1 owner locks are enough to rotate later claim ownership. @@ -119,7 +119,7 @@ fn weak_lock_valid_dao_batch_can_crosswire_claims() { link_cell_to_header(&mut context, &deposit2, &header2); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user1_lock, &xudt, 16).pack()) .lock(user1_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -130,6 +130,7 @@ fn weak_lock_valid_dao_batch_can_crosswire_claims() { .input(CellInput::new_builder().previous_output(deposit1).build()) .input(CellInput::new_builder().previous_output(deposit2).build()) .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) .outputs(vec![ CellOutput::new_builder() .capacity(total1.pack()) @@ -142,12 +143,12 @@ fn weak_lock_valid_dao_batch_can_crosswire_claims() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user1_lock, &owned_owner, 4).pack()) .lock(user1_lock) .type_(Some(owned_owner.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user2_lock, &owned_owner, 4).pack()) .lock(user2_lock) .type_(Some(owned_owner).pack()) .build(), @@ -167,7 +168,7 @@ fn weak_lock_valid_dao_batch_can_crosswire_claims() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("under weak owner locks, owned_owner accepts crosswired owner assignments when DAO index rules are still satisfied"); } @@ -207,7 +208,7 @@ fn weak_lock_crosswired_batch_reassigns_phase2_claims() { link_cell_to_header(&mut context, &deposit2, &deposit_header2); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user1_lock, &xudt, 16).pack()) .lock(user1_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -218,6 +219,7 @@ fn weak_lock_crosswired_batch_reassigns_phase2_claims() { .input(CellInput::new_builder().previous_output(deposit1).build()) .input(CellInput::new_builder().previous_output(deposit2).build()) .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) .outputs(vec![ CellOutput::new_builder() .capacity(total1.pack()) @@ -230,12 +232,12 @@ fn weak_lock_crosswired_batch_reassigns_phase2_claims() { .type_(Some(dao.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user1_lock, &owned_owner, 4).pack()) .lock(user1_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user2_lock, &owned_owner, 4).pack()) .lock(user2_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), @@ -254,7 +256,7 @@ fn weak_lock_crosswired_batch_reassigns_phase2_claims() { .build(); let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("under weak owner locks, the crosswired phase1 batch should verify"); let batch_hash = create_tx.hash(); @@ -299,7 +301,7 @@ fn weak_lock_crosswired_batch_reassigns_phase2_claims() { .build(); let claim_with_crosswired_pair = context.complete_tx(claim_with_crosswired_pair); context - .verify_tx(&claim_with_crosswired_pair, MAX_CYCLES) + .verify(&claim_with_crosswired_pair, MAX_CYCLES) .expect("under weak owner locks, user1's owner cell should successfully claim the crosswired second withdrawal request"); let claim_with_intended_pair = TransactionBuilder::default() @@ -327,7 +329,7 @@ fn weak_lock_crosswired_batch_reassigns_phase2_claims() { .witness(header_dep_index_witness(1).pack()) .build(); let claim_with_intended_pair = context.complete_tx(claim_with_intended_pair); - let err = context.verify_tx(&claim_with_intended_pair, MAX_CYCLES).unwrap_err(); + let err = context.verify(&claim_with_intended_pair, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); } @@ -359,7 +361,7 @@ fn weak_lock_three_way_crosswire_rotates_claims() { link_cell_to_header(&mut context, &deposit3, &deposit_header3); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user1_lock, &xudt, 16).pack()) .lock(user1_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -371,13 +373,14 @@ fn weak_lock_three_way_crosswire_rotates_claims() { .input(CellInput::new_builder().previous_output(deposit2).build()) .input(CellInput::new_builder().previous_output(deposit3).build()) .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) .outputs(vec![ CellOutput::new_builder().capacity(total1.pack()).lock(owned_owner.clone()).type_(Some(dao.clone()).pack()).build(), CellOutput::new_builder().capacity(total2.pack()).lock(owned_owner.clone()).type_(Some(dao.clone()).pack()).build(), CellOutput::new_builder().capacity(total3.pack()).lock(owned_owner.clone()).type_(Some(dao.clone()).pack()).build(), - CellOutput::new_builder().capacity(200u64.pack()).lock(user1_lock.clone()).type_(Some(owned_owner.clone()).pack()).build(), - CellOutput::new_builder().capacity(200u64.pack()).lock(user2_lock.clone()).type_(Some(owned_owner.clone()).pack()).build(), - CellOutput::new_builder().capacity(200u64.pack()).lock(user3_lock).type_(Some(owned_owner).pack()).build(), + CellOutput::new_builder().capacity((200 * CKB).pack()).lock(user1_lock.clone()).type_(Some(owned_owner.clone()).pack()).build(), + CellOutput::new_builder().capacity((200 * CKB).pack()).lock(user2_lock.clone()).type_(Some(owned_owner.clone()).pack()).build(), + CellOutput::new_builder().capacity((200 * CKB).pack()).lock(user3_lock).type_(Some(owned_owner).pack()).build(), ]) .outputs_data( vec![ @@ -397,7 +400,7 @@ fn weak_lock_three_way_crosswire_rotates_claims() { let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("under weak owner locks, owned_owner accepts a three-way crosswired withdrawal batch when DAO index rules still hold"); let batch_hash = create_tx.hash(); @@ -440,7 +443,7 @@ fn weak_lock_three_way_crosswire_rotates_claims() { .build(); let claim_with_rotated_pair = context.complete_tx(claim_with_rotated_pair); context - .verify_tx(&claim_with_rotated_pair, MAX_CYCLES) + .verify(&claim_with_rotated_pair, MAX_CYCLES) .expect("under weak owner locks, user1 should successfully claim user2's withdrawal request from a three-way crosswired batch"); let claim_with_intended_pair = TransactionBuilder::default() @@ -463,6 +466,6 @@ fn weak_lock_three_way_crosswire_rotates_claims() { .witness(witness.pack()) .build(); let claim_with_intended_pair = context.complete_tx(claim_with_intended_pair); - let err = context.verify_tx(&claim_with_intended_pair, MAX_CYCLES).unwrap_err(); + let err = context.verify(&claim_with_intended_pair, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); } diff --git a/scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs b/scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs index a751429..841dcb5 100644 --- a/scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs +++ b/scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs @@ -13,10 +13,13 @@ fn foreign_dao_withdrawal_can_be_wrapped_and_claimed() { let deposit_capacity_value = 123_456_780_000u64; let deposit_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); + // For deposits since block 10,000,000 the node keeps a withdrawal request's lock the same size as + // its deposit's, so only a deposit whose lock has Owned Owner's size (empty args) can be wrapped. + let wrappable_lock = always_success_lock(&mut context); let deposit_input = context.create_cell( CellOutput::new_builder() .capacity(deposit_capacity_value.pack()) - .lock(user_lock.clone()) + .lock(wrappable_lock) .type_(Some(dao.clone()).pack()) .build(), dao_deposit_data(), @@ -24,7 +27,7 @@ fn foreign_dao_withdrawal_can_be_wrapped_and_claimed() { link_cell_to_header(&mut context, &deposit_input, &deposit_header); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -40,7 +43,7 @@ fn foreign_dao_withdrawal_can_be_wrapped_and_claimed() { .type_(Some(dao.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) .lock(user_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), @@ -57,7 +60,7 @@ fn foreign_dao_withdrawal_can_be_wrapped_and_claimed() { let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("owned_owner should accept a foreign DAO withdrawal request pair without any iCKB burn"); let tx_hash = create_tx.hash(); @@ -108,6 +111,6 @@ fn foreign_dao_withdrawal_can_be_wrapped_and_claimed() { let claim_tx = context.complete_tx(claim_tx); context - .verify_tx(&claim_tx, MAX_CYCLES) + .verify(&claim_tx, MAX_CYCLES) .expect("the foreign DAO withdrawal wrapped in owned_owner should remain spendable in DAO phase2"); } diff --git a/scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs b/scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs index 431a73e..0679fa7 100644 --- a/scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs +++ b/scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs @@ -22,7 +22,7 @@ fn phase1_accepts_unspendable_foreign_owner_lock() { link_cell_to_header(&mut context, &deposit_input, &deposit_header); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -39,7 +39,7 @@ fn phase1_accepts_unspendable_foreign_owner_lock() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&poisoned_lock, &owned_owner, 4).pack()) .lock(poisoned_lock) .type_(Some(owned_owner.clone()).pack()) .build(), @@ -50,7 +50,7 @@ fn phase1_accepts_unspendable_foreign_owner_lock() { let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("owned_owner creation accepts an owner cell whose lock never executed on creation"); let tx_hash = create_tx.hash(); @@ -92,7 +92,7 @@ fn phase1_accepts_unspendable_foreign_owner_lock() { .build(); let melt_tx = context.complete_tx(melt_tx); - let err = context.verify_tx(&melt_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&melt_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); } @@ -117,7 +117,7 @@ fn phase1_accepts_limit_order_owner_lock_but_claim_strands() { link_cell_to_header(&mut context, &deposit_input, &deposit_header); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -134,7 +134,7 @@ fn phase1_accepts_limit_order_owner_lock_but_claim_strands() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&benign_foreign_lock, &owned_owner, 4).pack()) .lock(benign_foreign_lock) .type_(Some(owned_owner.clone()).pack()) .build(), @@ -145,7 +145,7 @@ fn phase1_accepts_limit_order_owner_lock_but_claim_strands() { let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("owned_owner creation accepts an empty-args limit_order owner lock at creation"); let tx_hash = create_tx.hash(); @@ -187,7 +187,7 @@ fn phase1_accepts_limit_order_owner_lock_but_claim_strands() { .build(); let melt_tx = context.complete_tx(melt_tx); - let err = context.verify_tx(&melt_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&melt_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_ENCODING); } @@ -217,7 +217,7 @@ fn limit_order_backed_owner_is_blocked_in_phase1() { link_cell_to_header(&mut context, &deposit_input, &deposit_header); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&burn_lock, &xudt, 16).pack()) .lock(burn_lock) .type_(Some(xudt).pack()) .build(), @@ -226,7 +226,7 @@ fn limit_order_backed_owner_is_blocked_in_phase1() { let master_out_point = context.create_cell( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&attacker_lock, &limit_order, 0).pack()) .lock(attacker_lock.clone()) .type_(Some(limit_order.clone()).pack()) .build(), @@ -254,6 +254,6 @@ fn limit_order_backed_owner_is_blocked_in_phase1() { .build(); let create_tx = context.complete_tx(create_tx); - let err = context.verify_tx(&create_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&create_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_DAO_INCORRECT_CAPACITY); } diff --git a/scripts/tests/src/tests/owned_owner/live_claim_rotation.rs b/scripts/tests/src/tests/owned_owner/live_claim_rotation.rs index 670b6e2..9e425fe 100644 --- a/scripts/tests/src/tests/owned_owner/live_claim_rotation.rs +++ b/scripts/tests/src/tests/owned_owner/live_claim_rotation.rs @@ -27,7 +27,7 @@ fn live_claim_cannot_roll_into_fresh_pair() { context.create_cell_with_out_point( owner_input.clone(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&old_owner_lock, &owned_owner, 4).pack()) .lock(old_owner_lock) .type_(Some(owned_owner.clone()).pack()) .build(), @@ -52,7 +52,7 @@ fn live_claim_cannot_roll_into_fresh_pair() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&new_owner_lock, &owned_owner, 4).pack()) .lock(new_owner_lock) .type_(Some(owned_owner).pack()) .build(), @@ -70,7 +70,7 @@ fn live_claim_cannot_roll_into_fresh_pair() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_DAO_NEWLY_CREATED_CELL); } @@ -110,7 +110,7 @@ fn live_claims_cannot_rotate_into_new_pairs() { link_cell_to_header(&mut context, &deposit2, &deposit_header2); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user1_lock, &xudt, 16).pack()) .lock(user1_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -121,6 +121,7 @@ fn live_claims_cannot_rotate_into_new_pairs() { .input(CellInput::new_builder().previous_output(deposit1).build()) .input(CellInput::new_builder().previous_output(deposit2).build()) .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) .outputs(vec![ CellOutput::new_builder() .capacity(total1.pack()) @@ -133,12 +134,12 @@ fn live_claims_cannot_rotate_into_new_pairs() { .type_(Some(dao.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user1_lock, &owned_owner, 4).pack()) .lock(user1_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user2_lock, &owned_owner, 4).pack()) .lock(user2_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), @@ -157,7 +158,7 @@ fn live_claims_cannot_rotate_into_new_pairs() { .build(); let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("initial live owned_owner pairs should verify"); let batch_hash = create_tx.hash(); @@ -220,12 +221,12 @@ fn live_claims_cannot_rotate_into_new_pairs() { .type_(Some(dao.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user1_lock, &owned_owner, 4).pack()) .lock(user1_lock) .type_(Some(owned_owner.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user2_lock, &owned_owner, 4).pack()) .lock(user2_lock) .type_(Some(owned_owner).pack()) .build(), @@ -248,6 +249,6 @@ fn live_claims_cannot_rotate_into_new_pairs() { .build(); let rotate_tx = context.complete_tx(rotate_tx); - let err = context.verify_tx(&rotate_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&rotate_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_DAO_NEWLY_CREATED_CELL); } diff --git a/scripts/tests/src/tests/owned_owner/melt_pairing_and_witness.rs b/scripts/tests/src/tests/owned_owner/melt_pairing_and_witness.rs index ef91d8b..a161878 100644 --- a/scripts/tests/src/tests/owned_owner/melt_pairing_and_witness.rs +++ b/scripts/tests/src/tests/owned_owner/melt_pairing_and_witness.rs @@ -26,7 +26,7 @@ fn melt_accepts_owner_distance_trailing_bytes_on_input() { context.create_cell_with_out_point( owner_input.clone(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 6).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner).pack()) .build(), @@ -64,7 +64,7 @@ fn melt_accepts_owner_distance_trailing_bytes_on_input() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("owned_owner melt accepts trailing bytes after a valid input owner distance"); } @@ -94,7 +94,7 @@ fn valid_melt_pair_passes() { context.create_cell_with_out_point( owner_input.clone(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner).pack()) .build(), @@ -132,7 +132,7 @@ fn valid_melt_pair_passes() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("owned_owner should accept a valid melt pair"); } @@ -162,7 +162,7 @@ fn melt_rejects_misbound_deposit_header_index() { context.create_cell_with_out_point( owner_input.clone(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner).pack()) .build(), @@ -192,7 +192,7 @@ fn melt_rejects_misbound_deposit_header_index() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_DAO_INVALID_WITHDRAW_BLOCK); } @@ -222,7 +222,7 @@ fn melt_rejects_short_header_dep_index_witness() { context.create_cell_with_out_point( owner_input.clone(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner).pack()) .build(), @@ -253,7 +253,7 @@ fn melt_rejects_short_header_dep_index_witness() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, -11); } @@ -283,7 +283,7 @@ fn melt_rejects_header_dep_index_witness_in_output_type() { context.create_cell_with_out_point( owner_input.clone(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner).pack()) .build(), @@ -314,7 +314,7 @@ fn melt_rejects_header_dep_index_witness_in_output_type() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, -11); } @@ -343,7 +343,7 @@ fn melt_rejects_truncated_owner_distance_on_input() { context.create_cell_with_out_point( owner_input.clone(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner).pack()) .build(), @@ -374,7 +374,7 @@ fn melt_rejects_truncated_owner_distance_on_input() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_ENCODING); } @@ -390,7 +390,7 @@ fn pairs_cannot_be_swapped_during_melt() { let owned1 = context.create_cell( CellOutput::new_builder() - .capacity(1000u64.pack()) + .capacity((1000 * CKB).pack()) .lock(owned_owner.clone()) .type_(Some(dao.clone()).pack()) .build(), @@ -398,7 +398,7 @@ fn pairs_cannot_be_swapped_during_melt() { ); let owner1 = context.create_cell( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user1_lock, &owned_owner, 4).pack()) .lock(user1_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), @@ -406,7 +406,7 @@ fn pairs_cannot_be_swapped_during_melt() { ); let owned2 = context.create_cell( CellOutput::new_builder() - .capacity(1000u64.pack()) + .capacity((1000 * CKB).pack()) .lock(owned_owner.clone()) .type_(Some(dao).pack()) .build(), @@ -414,7 +414,7 @@ fn pairs_cannot_be_swapped_during_melt() { ); let owner2 = context.create_cell( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user2_lock, &owned_owner, 4).pack()) .lock(user2_lock.clone()) .type_(Some(owned_owner).pack()) .build(), @@ -427,13 +427,13 @@ fn pairs_cannot_be_swapped_during_melt() { .input(CellInput::new_builder().previous_output(owned2).build()) .input(CellInput::new_builder().previous_output(owner1).build()) .outputs(vec![ - CellOutput::new_builder().capacity(600u64.pack()).lock(user1_lock).build(), - CellOutput::new_builder().capacity(600u64.pack()).lock(user2_lock).build(), + CellOutput::new_builder().capacity((600 * CKB).pack()).lock(user1_lock).build(), + CellOutput::new_builder().capacity((600 * CKB).pack()).lock(user2_lock).build(), ]) .outputs_data(vec![Bytes::new(), Bytes::new()].pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); } diff --git a/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs b/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs index de75bbd..4cf5b29 100644 --- a/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs +++ b/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs @@ -15,10 +15,13 @@ fn weak_lock_mixed_foreign_and_ickb_batch_can_crosswire_claims() { let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let foreign_deposit_capacity = 123_456_780_000u64; + // For deposits since block 10,000,000 the node keeps a withdrawal request's lock the same size as + // its deposit's, so only a foreign deposit whose lock has Owned Owner's size (empty args) can be wrapped. + let wrappable_lock = always_success_lock(&mut context); let foreign_deposit_input = context.create_cell( CellOutput::new_builder() .capacity(foreign_deposit_capacity.pack()) - .lock(foreign_owner_lock.clone()) + .lock(wrappable_lock) .type_(Some(dao.clone()).pack()) .build(), dao_deposit_data(), @@ -39,7 +42,7 @@ fn weak_lock_mixed_foreign_and_ickb_batch_can_crosswire_claims() { let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&protocol_owner_lock, &xudt, 16).pack()) .lock(protocol_owner_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -50,6 +53,7 @@ fn weak_lock_mixed_foreign_and_ickb_batch_can_crosswire_claims() { .input(CellInput::new_builder().previous_output(foreign_deposit_input).build()) .input(CellInput::new_builder().previous_output(protocol_deposit_input).build()) .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) .outputs(vec![ CellOutput::new_builder() .capacity(foreign_deposit_capacity.pack()) @@ -62,12 +66,12 @@ fn weak_lock_mixed_foreign_and_ickb_batch_can_crosswire_claims() { .type_(Some(dao.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&foreign_owner_lock, &owned_owner, 4).pack()) .lock(foreign_owner_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&protocol_owner_lock, &owned_owner, 4).pack()) .lock(protocol_owner_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), @@ -87,7 +91,7 @@ fn weak_lock_mixed_foreign_and_ickb_batch_can_crosswire_claims() { let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("owned_owner should accept a weak-lock mixed foreign-plus-iCKB withdrawal batch with crosswired later claim assignments"); let batch_hash = create_tx.hash(); @@ -150,7 +154,7 @@ fn weak_lock_mixed_foreign_and_ickb_batch_can_crosswire_claims() { .build(); let claim_with_crosswired_foreign_owner = context.complete_tx(claim_with_crosswired_foreign_owner); context - .verify_tx(&claim_with_crosswired_foreign_owner, MAX_CYCLES) + .verify(&claim_with_crosswired_foreign_owner, MAX_CYCLES) .expect("under weak owner locks, the foreign owner cell should be able to claim the real iCKB withdrawal once the mixed batch crosswires the later claim assignment"); let claim_with_intended_protocol_owner = TransactionBuilder::default() @@ -183,7 +187,7 @@ fn weak_lock_mixed_foreign_and_ickb_batch_can_crosswire_claims() { .build(); let claim_with_intended_protocol_owner = context.complete_tx(claim_with_intended_protocol_owner); let err = context - .verify_tx(&claim_with_intended_protocol_owner, MAX_CYCLES) + .verify(&claim_with_intended_protocol_owner, MAX_CYCLES) .unwrap_err(); assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); } diff --git a/scripts/tests/src/tests/owned_owner/owner_distance_encoding.rs b/scripts/tests/src/tests/owned_owner/owner_distance_encoding.rs index 3e12af9..742195b 100644 --- a/scripts/tests/src/tests/owned_owner/owner_distance_encoding.rs +++ b/scripts/tests/src/tests/owned_owner/owner_distance_encoding.rs @@ -14,7 +14,7 @@ fn truncated_owner_distance_output_is_rejected() { let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -31,7 +31,7 @@ fn truncated_owner_distance_output_is_rejected() { link_cell_to_header(&mut context, &deposit_input, &deposit_header); let owner_output = CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(); @@ -50,7 +50,7 @@ fn truncated_owner_distance_output_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_ENCODING); } @@ -66,7 +66,7 @@ fn zero_length_owner_distance_output_is_rejected_as_encoding() { let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -83,7 +83,7 @@ fn zero_length_owner_distance_output_is_rejected_as_encoding() { link_cell_to_header(&mut context, &deposit_input, &deposit_header); let owner_output = CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(); @@ -102,7 +102,7 @@ fn zero_length_owner_distance_output_is_rejected_as_encoding() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_ENCODING); } @@ -118,7 +118,7 @@ fn owner_distance_trailing_bytes_are_ignored() { let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -135,7 +135,7 @@ fn owner_distance_trailing_bytes_are_ignored() { link_cell_to_header(&mut context, &deposit_input, &deposit_header); let owner_output = CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 6).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(); @@ -161,6 +161,6 @@ fn owner_distance_trailing_bytes_are_ignored() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("owned_owner should ignore trailing bytes in owner distance data"); } diff --git a/scripts/tests/src/tests/owned_owner/pair_formation.rs b/scripts/tests/src/tests/owned_owner/pair_formation.rs index 0ef1ba5..2559975 100644 --- a/scripts/tests/src/tests/owned_owner/pair_formation.rs +++ b/scripts/tests/src/tests/owned_owner/pair_formation.rs @@ -21,7 +21,7 @@ fn valid_output_pair_passes() { link_cell_to_header(&mut context, &deposit_input, &deposit_header); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -33,7 +33,7 @@ fn valid_output_pair_passes() { .type_(Some(dao).pack()) .build(); let owner_output = CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock) .type_(Some(owned_owner).pack()) .build(); @@ -48,7 +48,7 @@ fn valid_output_pair_passes() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("owned_owner should accept a matched output pair"); } @@ -82,7 +82,7 @@ fn withdrawal_shape_cannot_be_created_without_any_dao_input() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) .lock(user_lock) .type_(Some(owned_owner).pack()) .build(), @@ -97,7 +97,7 @@ fn withdrawal_shape_cannot_be_created_without_any_dao_input() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_DAO_NEWLY_CREATED_CELL); } @@ -123,7 +123,7 @@ fn two_owner_cells_for_one_owned_output_are_rejected() { link_cell_to_header(&mut context, &deposit_input, &deposit_header); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -131,7 +131,7 @@ fn two_owner_cells_for_one_owned_output_are_rejected() { ); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -148,12 +148,12 @@ fn two_owner_cells_for_one_owned_output_are_rejected() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock) .type_(Some(owned_owner).pack()) .build(), @@ -170,7 +170,7 @@ fn two_owner_cells_for_one_owned_output_are_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); } @@ -195,7 +195,7 @@ fn orphan_withdrawal_request_can_be_created_but_not_claimed() { link_cell_to_header(&mut context, &deposit_input, &deposit_header); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -218,7 +218,7 @@ fn orphan_withdrawal_request_can_be_created_but_not_claimed() { let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("phase1 accepts an orphan withdrawal request because the owned_owner output lock never executes"); let orphan_out_point = OutPoint::new(create_tx.hash(), 0); @@ -251,7 +251,7 @@ fn orphan_withdrawal_request_can_be_created_but_not_claimed() { .build(); let claim_tx = context.complete_tx(claim_tx); - let err = context.verify_tx(&claim_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&claim_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); } @@ -265,7 +265,7 @@ fn orphan_owner_output_is_rejected() { let funding_input = context.create_cell( CellOutput::new_builder() - .capacity(500u64.pack()) + .capacity((500 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -274,7 +274,7 @@ fn orphan_owner_output_is_rejected() { .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock) .type_(Some(owned_owner).pack()) .build(), @@ -283,6 +283,6 @@ fn orphan_owner_output_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); } diff --git a/scripts/tests/src/tests/owned_owner/phase1_poisoning.rs b/scripts/tests/src/tests/owned_owner/phase1_poisoning.rs index 4cf84cf..862f705 100644 --- a/scripts/tests/src/tests/owned_owner/phase1_poisoning.rs +++ b/scripts/tests/src/tests/owned_owner/phase1_poisoning.rs @@ -30,12 +30,12 @@ fn unrelated_non_empty_args_output_lock_poisons_withdrawal() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock) .type_(Some(owned_owner).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(poisoned_lock) .build(), ]) @@ -51,7 +51,7 @@ fn unrelated_non_empty_args_output_lock_poisons_withdrawal() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); } @@ -79,6 +79,7 @@ fn foreign_typed_output_is_ignored() { let tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(deposit_input).build()) .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) .outputs(vec![ CellOutput::new_builder() .capacity(deposit_total_capacity.pack()) @@ -86,12 +87,12 @@ fn foreign_typed_output_is_ignored() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock) .type_(Some(owned_owner).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(foreign_lock) .type_(Some(foreign_type).pack()) .build(), @@ -109,7 +110,7 @@ fn foreign_typed_output_is_ignored() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("owned_owner should ignore unrelated foreign typed outputs during a valid withdrawal batch"); } @@ -146,7 +147,7 @@ fn owned_shaped_non_empty_args_output_poisons_withdrawal() { .type_(Some(dao.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock) .type_(Some(owned_owner.clone()).pack()) .build(), @@ -168,7 +169,7 @@ fn owned_shaped_non_empty_args_output_poisons_withdrawal() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); } @@ -196,7 +197,7 @@ fn non_empty_args_owner_sibling_poisons_withdrawal() { ); let poisoned_owner_input = context.create_cell( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(owner_lock.clone()) .type_(Some(poisoned_owner_type).pack()) .build(), @@ -214,7 +215,7 @@ fn non_empty_args_owner_sibling_poisons_withdrawal() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock) .type_(Some(owned_owner).pack()) .build(), @@ -226,6 +227,6 @@ fn non_empty_args_owner_sibling_poisons_withdrawal() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); } diff --git a/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs b/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs index 574474c..df51a64 100644 --- a/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs +++ b/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs @@ -15,7 +15,7 @@ fn adjacent_positive_distance_pair_can_complete_phase2_claim() { let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity(100u64.pack()) + .capacity((200 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), @@ -31,7 +31,7 @@ fn adjacent_positive_distance_pair_can_complete_phase2_claim() { link_cell_to_header(&mut context, &deposit_input, &deposit_header); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -44,11 +44,11 @@ fn adjacent_positive_distance_pair_can_complete_phase2_claim() { .input(CellInput::new_builder().previous_output(deposit_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(100u64.pack()) + .capacity((100 * CKB).pack()) .lock(filler_lock) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), @@ -71,7 +71,7 @@ fn adjacent_positive_distance_pair_can_complete_phase2_claim() { let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("owned_owner should accept an adjacent positive-distance phase1 pair"); let tx_hash = create_tx.hash(); @@ -120,7 +120,7 @@ fn adjacent_positive_distance_pair_can_complete_phase2_claim() { let claim_tx = context.complete_tx(claim_tx); context - .verify_tx(&claim_tx, MAX_CYCLES) + .verify(&claim_tx, MAX_CYCLES) .expect("an adjacent positive-distance pair should remain spendable in DAO phase2"); } @@ -139,14 +139,14 @@ fn sparse_positive_distance_pair_can_complete_phase2_claim_at_exact_capacity() { let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let funding_input = context.create_cell( CellOutput::new_builder() - .capacity(100u64.pack()) + .capacity((200 * CKB).pack()) .lock(funding_lock) .build(), Bytes::new(), ); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -168,12 +168,12 @@ fn sparse_positive_distance_pair_can_complete_phase2_claim_at_exact_capacity() { .input(CellInput::new_builder().previous_output(deposit_input).build()) .outputs(vec![ CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(100u64.pack()) + .capacity((100 * CKB).pack()) .lock(filler_lock) .build(), CellOutput::new_builder() @@ -195,7 +195,7 @@ fn sparse_positive_distance_pair_can_complete_phase2_claim_at_exact_capacity() { let create_tx = context.complete_tx(create_tx); context - .verify_tx(&create_tx, MAX_CYCLES) + .verify(&create_tx, MAX_CYCLES) .expect("owned_owner should accept a sparse positive-distance pair when DAO index rules are still satisfied"); let tx_hash = create_tx.hash(); @@ -243,6 +243,6 @@ fn sparse_positive_distance_pair_can_complete_phase2_claim_at_exact_capacity() { .build(); let claim_tx = context.complete_tx(claim_tx); context - .verify_tx(&claim_tx, MAX_CYCLES) + .verify(&claim_tx, MAX_CYCLES) .expect("a sparse positive-distance pair should remain spendable in DAO phase2 at the exact claim capacity"); } diff --git a/scripts/tests/src/tests/owned_owner/script_misuse.rs b/scripts/tests/src/tests/owned_owner/script_misuse.rs index 3714e7d..e84618e 100644 --- a/scripts/tests/src/tests/owned_owner/script_misuse.rs +++ b/scripts/tests/src/tests/owned_owner/script_misuse.rs @@ -23,7 +23,7 @@ fn zero_distance_owner_output_is_rejected() { .type_(Some(dao).pack()) .build(); let owner_output = CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock) .type_(Some(owned_owner).pack()) .build(); @@ -35,7 +35,7 @@ fn zero_distance_owner_output_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); } @@ -65,7 +65,7 @@ fn zero_distance_owner_input_is_rejected() { context.create_cell_with_out_point( owner_input.clone(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner).pack()) .build(), @@ -96,7 +96,7 @@ fn zero_distance_owner_input_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); } @@ -123,7 +123,7 @@ fn non_withdrawal_owned_cell_is_rejected() { .type_(Some(dao).pack()) .build(); let owner_output = CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock) .type_(Some(owned_owner).pack()) .build(); @@ -135,7 +135,7 @@ fn non_withdrawal_owned_cell_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_OWNED_OWNER_NOT_WITHDRAW_REQUEST); } @@ -146,13 +146,13 @@ fn lock_only_owned_owner_non_dao_output_can_be_created_but_not_spent() { let funding_lock = always_success_lock(&mut context); let owned_owner = owned_owner_script(&mut context); let helper_type = helper_type_script(&mut context); - let funding_input = context.create_cell(CellOutput::new_builder().capacity(500u64.pack()).lock(funding_lock).build(), Bytes::new()); + let funding_input = context.create_cell(CellOutput::new_builder().capacity((500 * CKB).pack()).lock(funding_lock).build(), Bytes::new()); let create_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(owned_owner.clone()) .type_(Some(helper_type.clone()).pack()) .build(), @@ -160,11 +160,11 @@ fn lock_only_owned_owner_non_dao_output_can_be_created_but_not_spent() { .output_data(Bytes::new().pack()) .build(); let create_tx = context.complete_tx(create_tx); - context.verify_tx(&create_tx, MAX_CYCLES).expect("lock-only owned_owner misuse cell can be created because output locks do not execute"); + context.verify(&create_tx, MAX_CYCLES).expect("lock-only owned_owner misuse cell can be created because output locks do not execute"); let forged_out_point = context.create_cell( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity((200 * CKB).pack()) .lock(owned_owner) .type_(Some(helper_type).pack()) .build(), @@ -172,11 +172,11 @@ fn lock_only_owned_owner_non_dao_output_can_be_created_but_not_spent() { ); let spend_tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(forged_out_point).build()) - .output(CellOutput::new_builder().capacity(200u64.pack()).lock(always_success_lock(&mut context)).build()) + .output(CellOutput::new_builder().capacity((200 * CKB).pack()).lock(always_success_lock(&mut context)).build()) .output_data(Bytes::new().pack()) .build(); let spend_tx = context.complete_tx(spend_tx); - let err = context.verify_tx(&spend_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&spend_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_OWNED_OWNER_NOT_WITHDRAW_REQUEST); } @@ -201,7 +201,7 @@ fn lock_only_owned_owner_dao_deposit_output_can_be_created_but_not_spent() { .output_data(dao_deposit_data().pack()) .build(); let create_tx = context.complete_tx(create_tx); - context.verify_tx(&create_tx, MAX_CYCLES).expect("DAO deposit with owned_owner only on the output lock can be created"); + context.verify(&create_tx, MAX_CYCLES).expect("DAO deposit with owned_owner only on the output lock can be created"); let forged_out_point = context.create_cell( CellOutput::new_builder() @@ -217,7 +217,7 @@ fn lock_only_owned_owner_dao_deposit_output_can_be_created_but_not_spent() { .output_data(Bytes::new().pack()) .build(); let spend_tx = context.complete_tx(spend_tx); - let err = context.verify_tx(&spend_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&spend_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_OWNED_OWNER_NOT_WITHDRAW_REQUEST); } @@ -229,12 +229,12 @@ fn cell_using_owned_owner_as_both_lock_and_type_is_rejected() { let funding_lock = always_success_lock(&mut context); let owned_owner = owned_owner_script(&mut context); - let funding_input = context.create_cell(CellOutput::new_builder().capacity(500u64.pack()).lock(funding_lock).build(), Bytes::new()); + let funding_input = context.create_cell(CellOutput::new_builder().capacity((500 * CKB).pack()).lock(funding_lock).build(), Bytes::new()); let tx = TransactionBuilder::default() .input(CellInput::new_builder().previous_output(funding_input).build()) .output( CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owned_owner, &owned_owner, 4).pack()) .lock(owned_owner.clone()) .type_(Some(owned_owner).pack()) .build(), @@ -243,6 +243,6 @@ fn cell_using_owned_owner_as_both_lock_and_type_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_OWNED_OWNER_SCRIPT_MISUSE); } diff --git a/scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs b/scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs index 3184bdf..941ae62 100644 --- a/scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs +++ b/scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs @@ -26,7 +26,7 @@ fn weak_lock_can_reassign_withdrawal_owner_output() { .type_(Some(dao).pack()) .build(); let owner_output = CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&attacker_lock, &owned_owner, 4).pack()) .lock(attacker_lock) .type_(Some(owned_owner).pack()) .build(); @@ -41,7 +41,7 @@ fn weak_lock_can_reassign_withdrawal_owner_output() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("weak lock should allow reassigning the withdrawal owner output"); } @@ -75,7 +75,7 @@ fn sighash_lock_binds_withdrawal_owner_output_to_the_signed_transaction() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), @@ -89,7 +89,7 @@ fn sighash_lock_binds_withdrawal_owner_output_to_the_signed_transaction() { let tx = sign_tx_by_input_group(context.complete_tx(tx), &privkey, 1, 1); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("signed withdrawal request should verify"); let tampered_tx = tx @@ -101,13 +101,13 @@ fn sighash_lock_binds_withdrawal_owner_output_to_the_signed_transaction() { .type_(Some(dao_script(&mut context)).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&attacker_lock, &owned_owner_script(&mut context), 4).pack()) .lock(attacker_lock) .type_(Some(owned_owner_script(&mut context)).pack()) .build(), ]) .build(); - let err = context.verify_tx(&tampered_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } @@ -147,7 +147,7 @@ fn mixed_sighash_and_weak_udts_bind_all_withdrawal_outputs_once_signed() { link_cell_to_header(&mut context, &deposit2, &header2); let strong_udt = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -155,7 +155,7 @@ fn mixed_sighash_and_weak_udts_bind_all_withdrawal_outputs_once_signed() { ); let weak_udt = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&weak_lock, &xudt, 16).pack()) .lock(weak_lock) .type_(Some(xudt).pack()) .build(), @@ -179,12 +179,12 @@ fn mixed_sighash_and_weak_udts_bind_all_withdrawal_outputs_once_signed() { .type_(Some(dao.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner).pack()) .build(), @@ -209,7 +209,7 @@ fn mixed_sighash_and_weak_udts_bind_all_withdrawal_outputs_once_signed() { let tx = sign_tx_by_input_group(context.complete_tx(tx), &privkey, 2, 1); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("mixed strong+weak withdrawal batch should verify when signed"); let tampered_tx = tx @@ -226,18 +226,18 @@ fn mixed_sighash_and_weak_udts_bind_all_withdrawal_outputs_once_signed() { .type_(Some(dao_script(&mut context)).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&attacker_lock, &owned_owner_script(&mut context), 4).pack()) .lock(attacker_lock.clone()) .type_(Some(owned_owner_script(&mut context)).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&attacker_lock, &owned_owner_script(&mut context), 4).pack()) .lock(attacker_lock) .type_(Some(owned_owner_script(&mut context)).pack()) .build(), ]) .build(); - let err = context.verify_tx(&tampered_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } @@ -277,7 +277,7 @@ fn two_weak_udts_can_reassign_combined_withdrawal_owner_outputs() { link_cell_to_header(&mut context, &deposit2, &header2); let weak_udt_1 = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&weak_lock_1, &xudt, 16).pack()) .lock(weak_lock_1) .type_(Some(xudt.clone()).pack()) .build(), @@ -285,7 +285,7 @@ fn two_weak_udts_can_reassign_combined_withdrawal_owner_outputs() { ); let weak_udt_2 = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&weak_lock_2, &xudt, 16).pack()) .lock(weak_lock_2) .type_(Some(xudt).pack()) .build(), @@ -309,12 +309,12 @@ fn two_weak_udts_can_reassign_combined_withdrawal_owner_outputs() { .type_(Some(dao.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&attacker_lock, &owned_owner, 4).pack()) .lock(attacker_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&attacker_lock, &owned_owner, 4).pack()) .lock(attacker_lock) .type_(Some(owned_owner).pack()) .build(), @@ -334,6 +334,6 @@ fn two_weak_udts_can_reassign_combined_withdrawal_owner_outputs() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("all-weak withdrawal inputs can reassign both withdrawal owner outputs"); } diff --git a/scripts/tests/src/tests/owned_owner/withdrawal_amount_and_headers.rs b/scripts/tests/src/tests/owned_owner/withdrawal_amount_and_headers.rs index eba9e71..bf1b6e7 100644 --- a/scripts/tests/src/tests/owned_owner/withdrawal_amount_and_headers.rs +++ b/scripts/tests/src/tests/owned_owner/withdrawal_amount_and_headers.rs @@ -26,7 +26,7 @@ fn withdrawal_accepts_xudt_input_with_trailing_bytes() { udt_input_data.push(0xaa); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(udt_input_data.len() as u64).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, udt_input_data.len()).pack()) .lock(user_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -43,7 +43,7 @@ fn withdrawal_accepts_xudt_input_with_trailing_bytes() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) .lock(user_lock) .type_(Some(owned_owner).pack()) .build(), @@ -54,7 +54,7 @@ fn withdrawal_accepts_xudt_input_with_trailing_bytes() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("withdrawal should accept xudt input with trailing bytes"); } @@ -80,7 +80,7 @@ fn withdrawal_rejects_short_xudt_input_data() { let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(8).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 8).pack()) .lock(user_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -97,7 +97,7 @@ fn withdrawal_rejects_short_xudt_input_data() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) .lock(user_lock) .type_(Some(owned_owner).pack()) .build(), @@ -107,7 +107,7 @@ fn withdrawal_rejects_short_xudt_input_data() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_ENCODING); } @@ -133,7 +133,7 @@ fn withdrawal_rejects_zero_length_xudt_input_data() { let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(0).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 0).pack()) .lock(user_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -150,7 +150,7 @@ fn withdrawal_rejects_zero_length_xudt_input_data() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) .lock(user_lock) .type_(Some(owned_owner).pack()) .build(), @@ -160,7 +160,7 @@ fn withdrawal_rejects_zero_length_xudt_input_data() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_ENCODING); } @@ -185,7 +185,7 @@ fn withdrawal_without_deposit_header_dep_is_rejected() { link_cell_to_header(&mut context, &deposit_input, &deposit_header); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -202,7 +202,7 @@ fn withdrawal_without_deposit_header_dep_is_rejected() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) .lock(user_lock) .type_(Some(owned_owner).pack()) .build(), @@ -211,7 +211,7 @@ fn withdrawal_without_deposit_header_dep_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_ITEM_MISSING); } @@ -249,7 +249,7 @@ fn withdrawal_with_two_deposits_from_distinct_headers_passes() { link_cell_to_header(&mut context, &second_deposit, &second_header); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -260,6 +260,7 @@ fn withdrawal_with_two_deposits_from_distinct_headers_passes() { .input(CellInput::new_builder().previous_output(first_deposit).build()) .input(CellInput::new_builder().previous_output(second_deposit).build()) .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) .outputs(vec![ CellOutput::new_builder() .capacity(first_total_capacity.pack()) @@ -272,12 +273,12 @@ fn withdrawal_with_two_deposits_from_distinct_headers_passes() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) .lock(user_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) .lock(user_lock) .type_(Some(owned_owner).pack()) .build(), @@ -297,7 +298,7 @@ fn withdrawal_with_two_deposits_from_distinct_headers_passes() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("withdrawal should support multiple deposits from distinct headers"); } @@ -335,7 +336,7 @@ fn withdrawal_with_one_missing_deposit_header_dep_is_rejected() { link_cell_to_header(&mut context, &second_deposit, &second_header); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -358,12 +359,12 @@ fn withdrawal_with_one_missing_deposit_header_dep_is_rejected() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) .lock(user_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) .lock(user_lock) .type_(Some(owned_owner).pack()) .build(), @@ -381,7 +382,7 @@ fn withdrawal_with_one_missing_deposit_header_dep_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_ITEM_MISSING); } @@ -407,7 +408,7 @@ fn withdrawal_with_zero_accumulated_rate_deposit_header_is_rejected() { link_cell_to_header(&mut context, &deposit_input, &malformed_header); let udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) .lock(user_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -424,7 +425,7 @@ fn withdrawal_with_zero_accumulated_rate_deposit_header_is_rejected() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) .lock(user_lock) .type_(Some(owned_owner).pack()) .build(), @@ -434,7 +435,7 @@ fn withdrawal_with_zero_accumulated_rate_deposit_header_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SCRIPT_PANIC); } @@ -461,7 +462,7 @@ fn withdrawal_applies_soft_cap_discount_above_boundary() { let naive_udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt.clone()).pack()) .build(), @@ -477,7 +478,7 @@ fn withdrawal_applies_soft_cap_discount_above_boundary() { .type_(Some(dao.clone()).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock.clone()) .type_(Some(owned_owner.clone()).pack()) .build(), @@ -486,12 +487,12 @@ fn withdrawal_applies_soft_cap_discount_above_boundary() { .header_dep(deposit_header.hash()) .build(); let naive_tx = context.complete_tx(naive_tx); - let err = context.verify_tx(&naive_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&naive_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_AMOUNT_MISMATCH); let exact_udt_input = context.create_cell( CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) .lock(owner_lock.clone()) .type_(Some(xudt).pack()) .build(), @@ -507,7 +508,7 @@ fn withdrawal_applies_soft_cap_discount_above_boundary() { .type_(Some(dao).pack()) .build(), CellOutput::new_builder() - .capacity(200u64.pack()) + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) .lock(owner_lock) .type_(Some(owned_owner).pack()) .build(), @@ -517,6 +518,6 @@ fn withdrawal_applies_soft_cap_discount_above_boundary() { .build(); let exact_tx = context.complete_tx(exact_tx); context - .verify_tx(&exact_tx, MAX_CYCLES) + .verify(&exact_tx, MAX_CYCLES) .expect("withdrawal should require the soft-capped iCKB amount above the 100k boundary"); } diff --git a/scripts/tests/src/tests/replay/family_attacker_limit_order.rs b/scripts/tests/src/tests/replay/family_attacker_limit_order.rs index 8a2cc98..15d70e2 100644 --- a/scripts/tests/src/tests/replay/family_attacker_limit_order.rs +++ b/scripts/tests/src/tests/replay/family_attacker_limit_order.rs @@ -172,7 +172,7 @@ fn weak_lock_derived_five_claim_live_batch_can_flow_into_later_attacker_owned_li let later_tx = context.complete_tx(later_tx); context - .verify_tx(&later_tx, MAX_CYCLES) + .verify(&later_tx, MAX_CYCLES) .expect("weak-lock five-claim batch should reach the attacker-owned limit_order state"); let later_hash = later_tx.hash(); @@ -205,7 +205,7 @@ fn weak_lock_derived_five_claim_live_batch_can_flow_into_later_attacker_owned_li let melt_tx = context.complete_tx(melt_tx); context - .verify_tx(&melt_tx, MAX_CYCLES) + .verify(&melt_tx, MAX_CYCLES) .expect("attacker should melt the resulting attacker-owned limit_order state"); } @@ -481,7 +481,7 @@ fn weak_lock_derived_eight_claim_batch_can_flow_into_later_attacker_owned_limit_ let later_tx = context.complete_tx(later_tx); context - .verify_tx(&later_tx, MAX_CYCLES) + .verify(&later_tx, MAX_CYCLES) .expect("weak-lock mainnet batch should reach the attacker-owned limit_order state"); let later_hash = later_tx.hash(); @@ -514,6 +514,6 @@ fn weak_lock_derived_eight_claim_batch_can_flow_into_later_attacker_owned_limit_ let melt_tx = context.complete_tx(melt_tx); context - .verify_tx(&melt_tx, MAX_CYCLES) + .verify(&melt_tx, MAX_CYCLES) .expect("attacker should melt the resulting mainnet-shaped limit_order state"); } diff --git a/scripts/tests/src/tests/replay/family_mainnet_eight_claim.rs b/scripts/tests/src/tests/replay/family_mainnet_eight_claim.rs index fae9bcf..23a5d1e 100644 --- a/scripts/tests/src/tests/replay/family_mainnet_eight_claim.rs +++ b/scripts/tests/src/tests/replay/family_mainnet_eight_claim.rs @@ -169,7 +169,7 @@ fn weak_mainnet_eight_claim_batch_can_reassign_later_phase2_claimants() { let first_tx = context.complete_tx(first_tx); context - .verify_tx(&first_tx, MAX_CYCLES) + .verify(&first_tx, MAX_CYCLES) .expect("weak authorization should reassign the mainnet batch fresh owner outputs"); let batch_withdraw_header = rpc_header( @@ -223,7 +223,7 @@ fn weak_mainnet_eight_claim_batch_can_reassign_later_phase2_claimants() { let claim_tx = sign_tx_by_input_group(context.complete_tx(claim_tx), &attacker_privkey, 1, 1); context - .verify_tx(&claim_tx, MAX_CYCLES) + .verify(&claim_tx, MAX_CYCLES) .expect("reassigned mainnet batch owner output should allow a later phase2 claim"); } @@ -413,7 +413,7 @@ fn sighash_mainnet_eight_claim_batch_binds_fresh_owner_outputs() { let tx = sign_tx_by_input_group(context.complete_tx(tx), &privkey, 8, 2); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("one strong input group should still verify in the mainnet batch"); let tampered_tx = tx @@ -444,6 +444,6 @@ fn sighash_mainnet_eight_claim_batch_binds_fresh_owner_outputs() { tx.outputs().get(18).expect("change output"), ]) .build(); - let err = context.verify_tx(&tampered_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } diff --git a/scripts/tests/src/tests/replay/family_mixed_restake.rs b/scripts/tests/src/tests/replay/family_mixed_restake.rs index fb700e5..b6f5cfa 100644 --- a/scripts/tests/src/tests/replay/family_mixed_restake.rs +++ b/scripts/tests/src/tests/replay/family_mixed_restake.rs @@ -180,7 +180,7 @@ fn weak_live_mixed_restake_can_reassign_later_phase2_claimants() { let first_tx = context.complete_tx(first_tx); context - .verify_tx(&first_tx, MAX_CYCLES) + .verify(&first_tx, MAX_CYCLES) .expect("weak mixed restake should reassign the fresh owner output"); let fresh_withdraw_header = rpc_header( @@ -297,7 +297,7 @@ fn weak_live_mixed_restake_can_reassign_later_phase2_claimants() { let second_tx = context.complete_tx(second_tx); context - .verify_tx(&second_tx, MAX_CYCLES) + .verify(&second_tx, MAX_CYCLES) .expect("reassigned fresh owner output should enable the later phase2 claim"); } @@ -481,7 +481,7 @@ fn sighash_live_mixed_restake_binds_fresh_owner_output() { let tx = sign_tx_by_input_group(context.complete_tx(tx), &privkey, 1, 2); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("one strong input group should still verify in the live mixed restake shape"); let tampered_tx = tx @@ -498,6 +498,6 @@ fn sighash_live_mixed_restake_binds_fresh_owner_output() { tx.outputs().get(4).expect("change output"), ]) .build(); - let err = context.verify_tx(&tampered_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } diff --git a/scripts/tests/src/tests/replay/family_two_claim_restake.rs b/scripts/tests/src/tests/replay/family_two_claim_restake.rs index deb2e8f..75ed19c 100644 --- a/scripts/tests/src/tests/replay/family_two_claim_restake.rs +++ b/scripts/tests/src/tests/replay/family_two_claim_restake.rs @@ -215,7 +215,7 @@ fn weak_two_claim_live_restake_can_reassign_later_phase2_claimants() { let first_tx = context.complete_tx(first_tx); context - .verify_tx(&first_tx, MAX_CYCLES) + .verify(&first_tx, MAX_CYCLES) .expect("weak two-claim restake should reassign the fresh owner output"); let fresh_withdraw_header = rpc_header( @@ -309,7 +309,7 @@ fn weak_two_claim_live_restake_can_reassign_later_phase2_claimants() { let second_tx = context.complete_tx(second_tx); context - .verify_tx(&second_tx, MAX_CYCLES) + .verify(&second_tx, MAX_CYCLES) .expect("reassigned fresh owner output should enable the wider phase2 claim"); } @@ -530,7 +530,7 @@ fn sighash_two_claim_live_restake_binds_fresh_owner_output() { let tx = sign_tx_by_input_group(context.complete_tx(tx), &privkey, 1, 2); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("one strong input group should still verify in the two-claim restake"); let tampered_tx = tx @@ -547,6 +547,6 @@ fn sighash_two_claim_live_restake_binds_fresh_owner_output() { tx.outputs().get(4).expect("change output"), ]) .build(); - let err = context.verify_tx(&tampered_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } diff --git a/scripts/tests/src/tests/replay/lineage_21ccbca0.rs b/scripts/tests/src/tests/replay/lineage_21ccbca0.rs index 09c31e0..100aafa 100644 --- a/scripts/tests/src/tests/replay/lineage_21ccbca0.rs +++ b/scripts/tests/src/tests/replay/lineage_21ccbca0.rs @@ -77,7 +77,7 @@ fn testnet_tx_21ccbca0_phase1_and_limit_order_creation_shape() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("live testnet phase1 + limit_order creation shape should replay locally"); } @@ -195,7 +195,7 @@ fn testnet_tx_a4a8dc3d_mixed_phase2_and_limit_order_shape() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("live testnet mixed phase2 + limit_order shape should replay locally"); } @@ -374,6 +374,6 @@ fn testnet_tx_088a1019_batched_withdrawal_and_limit_order_shape() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("live testnet batched withdrawal + limit_order shape should replay locally"); } diff --git a/scripts/tests/src/tests/replay/lineage_30f8ed8a.rs b/scripts/tests/src/tests/replay/lineage_30f8ed8a.rs index f3a8099..2c01788 100644 --- a/scripts/tests/src/tests/replay/lineage_30f8ed8a.rs +++ b/scripts/tests/src/tests/replay/lineage_30f8ed8a.rs @@ -96,7 +96,7 @@ fn mainnet_tx_30f8ed8a_phase1_and_limit_order_shape() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("live mainnet phase1 + limit_order shape should replay locally"); } @@ -200,6 +200,6 @@ fn mainnet_tx_f9404724_mixed_phase2_and_limit_order_shape() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("live mainnet mixed phase2 + limit_order shape should replay locally"); } diff --git a/scripts/tests/src/tests/replay/lineage_86d442e2.rs b/scripts/tests/src/tests/replay/lineage_86d442e2.rs index 062e8f5..87d5870 100644 --- a/scripts/tests/src/tests/replay/lineage_86d442e2.rs +++ b/scripts/tests/src/tests/replay/lineage_86d442e2.rs @@ -92,7 +92,7 @@ fn mainnet_tx_8aaf4923_deposit_and_limit_order_match_shape() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("live mainnet deposit + limit_order match shape should replay locally"); } @@ -205,7 +205,7 @@ fn mainnet_tx_42fe6a4c_phase2_and_limit_order_match_shape() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("live mainnet phase2 plus limit_order match shape should replay locally"); } @@ -375,7 +375,7 @@ fn mainnet_tx_86d442e2_claim_and_restake_shape() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("live mainnet claim + restake shape should replay locally"); } @@ -539,6 +539,6 @@ fn mainnet_live_claims_cannot_rotate_into_new_owned_owner_pairs() { .build(); let rotate_tx = context.complete_tx(rotate_tx); - let err = context.verify_tx(&rotate_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&rotate_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_DAO_NEWLY_CREATED_CELL); } diff --git a/scripts/tests/src/tests/replay/lineage_b866945c.rs b/scripts/tests/src/tests/replay/lineage_b866945c.rs index 4232209..233637b 100644 --- a/scripts/tests/src/tests/replay/lineage_b866945c.rs +++ b/scripts/tests/src/tests/replay/lineage_b866945c.rs @@ -143,7 +143,7 @@ fn mainnet_tx_b866945c_claim_and_limit_order_match_shape() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("live mainnet one-pair claim plus limit_order match shape should replay locally"); } @@ -213,9 +213,10 @@ fn mainnet_tx_b866945c_is_input_poisoned_by_non_empty_args_owned_owner_sibling() bytes_from_hex("0xffffffff"), ); + // The one-byte args make the mainnet owner cell one CKB larger. let poisoned_owner_input = context.create_cell( CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) + .capacity((u64_from_hex("0x248202200") + CKB).pack()) .lock(user_lock.clone()) .type_(Some(poisoned_owned_owner).pack()) .build(), @@ -302,7 +303,7 @@ fn mainnet_tx_b866945c_is_input_poisoned_by_non_empty_args_owned_owner_sibling() .build(); let tx = context.complete_tx(tx); - let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); } @@ -472,6 +473,6 @@ fn mainnet_tx_dc92e6a3_mixed_deposit_phase2_and_limit_order_shape() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("live mainnet mixed deposit phase1 + phase2 + limit_order shape should replay locally"); } diff --git a/scripts/tests/src/tests/replay/lineage_b923f354.rs b/scripts/tests/src/tests/replay/lineage_b923f354.rs index b3a73ac..5f22a6e 100644 --- a/scripts/tests/src/tests/replay/lineage_b923f354.rs +++ b/scripts/tests/src/tests/replay/lineage_b923f354.rs @@ -88,7 +88,7 @@ fn mainnet_tx_b923f354_live_limit_order_match_shape() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("live mainnet pure limit_order match shape should replay locally"); } @@ -192,6 +192,6 @@ fn mainnet_tx_3d26da3b_limit_order_melt_shape() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("live mainnet limit_order melt shape should replay locally"); } diff --git a/scripts/tests/src/tests/replay/tx_5f6d0d5b.rs b/scripts/tests/src/tests/replay/tx_5f6d0d5b.rs index 2f6c782..e8aa441 100644 --- a/scripts/tests/src/tests/replay/tx_5f6d0d5b.rs +++ b/scripts/tests/src/tests/replay/tx_5f6d0d5b.rs @@ -151,6 +151,6 @@ fn mainnet_tx_5f6d0d5b_claim_deposit_and_limit_order_shape() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("live mainnet claim plus fresh deposit and limit_order shape should replay locally"); } diff --git a/scripts/tests/src/tests/replay/tx_9df44c51.rs b/scripts/tests/src/tests/replay/tx_9df44c51.rs index d726200..e5d2f21 100644 --- a/scripts/tests/src/tests/replay/tx_9df44c51.rs +++ b/scripts/tests/src/tests/replay/tx_9df44c51.rs @@ -112,6 +112,6 @@ fn mainnet_tx_9df44c51_withdrawal_and_owned_owner_shape() { let tx = context.complete_tx(tx); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("live mainnet withdrawal + owned_owner shape should replay locally"); } diff --git a/scripts/tests/src/tests/signing.rs b/scripts/tests/src/tests/signing.rs index 1208675..0289a69 100644 --- a/scripts/tests/src/tests/signing.rs +++ b/scripts/tests/src/tests/signing.rs @@ -220,14 +220,14 @@ fn sign_tx_by_input_group_covers_trailing_extra_witnesses_for_later_groups() { let passthrough_input = context.create_cell( CellOutput::new_builder() - .capacity(1_000u64.pack()) + .capacity((1_000 * CKB).pack()) .lock(passthrough_lock.clone()) .build(), Bytes::new(), ); let protected_input = context.create_cell( CellOutput::new_builder() - .capacity(1_000u64.pack()) + .capacity((1_000 * CKB).pack()) .lock(protected_lock) .build(), Bytes::new(), @@ -239,7 +239,7 @@ fn sign_tx_by_input_group_covers_trailing_extra_witnesses_for_later_groups() { .input(CellInput::new_builder().previous_output(protected_input).build()) .output( CellOutput::new_builder() - .capacity(1_800u64.pack()) + .capacity((1_800 * CKB).pack()) .lock(passthrough_lock) .build(), ) @@ -252,7 +252,7 @@ fn sign_tx_by_input_group_covers_trailing_extra_witnesses_for_later_groups() { let tx = sign_tx_by_input_group(context.complete_tx(tx), &privkey, 1, 1); context - .verify_tx(&tx, MAX_CYCLES) + .verify(&tx, MAX_CYCLES) .expect("later secp input group should verify when the trailing extra witness stays unchanged"); let tampered_tx = tx @@ -263,6 +263,6 @@ fn sign_tx_by_input_group_covers_trailing_extra_witnesses_for_later_groups() { Bytes::from_static(b"trailing-extra-updated").pack(), ]) .build(); - let err = context.verify_tx(&tampered_tx, MAX_CYCLES).unwrap_err(); + let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } From 39f19474cc163b8407dba111482a9006eec77c95 Mon Sep 17 00:00:00 2001 From: phroi <90913182+phroi@users.noreply.github.com> Date: Sat, 26 Sep 2026 15:15:38 +0200 Subject: [PATCH 04/13] test: replay the golden vectors against the release binaries The golden vectors had only ever been computed by copies of contract functions, never checked against the compiled scripts. The contract tests now include vector-gen/src/vectors.rs and replay its rows as real transactions: - each deposit vector mints exactly its expected iCKB at phase 2, while one shannon more or less fails with AmountMismatch; - each match vector gets the copied validate's verdict from the binary, which also parses the order the copies skip; - drift_checks runs with the suite, so a copy that stops matching its source fails here too. Two match rows shrink a fulfilled CKB->UDT order below its occupied capacity, which consensus forbids. They are skipped by name, so a new unconstructible row breaks the test instead of vanishing; this also records that AttemptToChangeFulfilled cannot be reached on chain. vector-gen's README records how to regenerate the stack's fixture, including the Prettier step that makes it byte-identical. --- scripts/Cargo.lock | 1 + scripts/tests/Cargo.toml | 1 + scripts/tests/README.md | 1 + scripts/tests/src/tests.rs | 2 + scripts/tests/src/tests/protocol_vectors.rs | 130 ++++++++++++++++++++ scripts/vector-gen/README.md | 14 +++ 6 files changed, 149 insertions(+) create mode 100644 scripts/tests/src/tests/protocol_vectors.rs create mode 100644 scripts/vector-gen/README.md diff --git a/scripts/Cargo.lock b/scripts/Cargo.lock index 3d441ab..f11b4ee 100644 --- a/scripts/Cargo.lock +++ b/scripts/Cargo.lock @@ -1595,6 +1595,7 @@ dependencies = [ "ckb-system-scripts", "ckb-testtool", "hex", + "primitive-types", ] [[package]] diff --git a/scripts/tests/Cargo.toml b/scripts/tests/Cargo.toml index 9148653..9bbd42d 100644 --- a/scripts/tests/Cargo.toml +++ b/scripts/tests/Cargo.toml @@ -10,3 +10,4 @@ ckb-testtool = "0.11" ckb-dao-utils = "0.114" ckb-system-scripts = "0.5.4" hex = "0.4" +primitive-types = { version = "0.12.2", default-features = false } diff --git a/scripts/tests/README.md b/scripts/tests/README.md index fd6aeb0..3348cb4 100644 --- a/scripts/tests/README.md +++ b/scripts/tests/README.md @@ -7,6 +7,7 @@ - `src/tests/signing.rs`: sighash signing helpers for whole-transaction-binding tests. - `src/tests/replay_helpers.rs`: live-shape parsers and batch builders used by replay-heavy cases. - `src/tests/helpers.rs`: focused unit tests for shared encoders. +- `src/tests/protocol_vectors.rs`: replays the golden vectors of `../vector-gen` (the values the contracts' own Rust logic gives each case) against the release binaries, except two named vectors that describe cells consensus cannot create. - `src/tests/ickb_logic.rs`, `owned_owner.rs`, `limit_order.rs`, `replay.rs`: thin suite roots that wire topic-focused files under `src/tests/ickb_logic/`, `owned_owner/`, `limit_order/`, and `replay/`. Some replay tests intentionally rebuild live transaction shapes instead of minimizing the fixture. Those cases keep the audit claims tied to realistic batching, witness layout, header dependencies, and cross-script interaction patterns. diff --git a/scripts/tests/src/tests.rs b/scripts/tests/src/tests.rs index d3ed784..1c39c14 100644 --- a/scripts/tests/src/tests.rs +++ b/scripts/tests/src/tests.rs @@ -17,6 +17,7 @@ mod helpers; mod ickb_logic; mod limit_order; mod owned_owner; +mod protocol_vectors; mod replay; mod replay_helpers; mod signing; @@ -157,6 +158,7 @@ const ERROR_LIMIT_ORDER_BOTH_RATIOS_NULL: i8 = 12; const ERROR_LIMIT_ORDER_MISSING_UDT_TYPE: i8 = 13; const ERROR_LIMIT_ORDER_INVALID_MATCH: i8 = 17; const ERROR_LIMIT_ORDER_DECREASING_VALUE: i8 = 18; +const ERROR_LIMIT_ORDER_ATTEMPT_TO_CHANGE_FULFILLED: i8 = 19; const ERROR_LIMIT_ORDER_INSUFFICIENT_MATCH: i8 = 20; const ERROR_SCRIPT_PANIC: i8 = -1; const ERROR_OWNED_OWNER_NOT_WITHDRAW_REQUEST: i8 = 6; diff --git a/scripts/tests/src/tests/protocol_vectors.rs b/scripts/tests/src/tests/protocol_vectors.rs new file mode 100644 index 0000000..f7abd1b --- /dev/null +++ b/scripts/tests/src/tests/protocol_vectors.rs @@ -0,0 +1,130 @@ +use super::*; + +// The protocol vectors compute their expected values with verbatim copies of contract functions +// (scripts/vector-gen). Replaying the rows here checks those values against the release binaries, +// including the order parsing and glue the copies leave out. +#[allow(dead_code)] +#[path = "../../../vector-gen/src/vectors.rs"] +mod vectors; + +use vectors::limit_order::Error as Verdict; + +#[test] +fn vector_copies_still_match_the_contract_sources() { + vectors::drift_checks(); +} + +// Phase 2 of every deposit vector: the receipt mints exactly the expected iCKB, one more or one less fails. +#[test] +fn every_deposit_vector_mints_exactly_its_expected_ickb() { + for row in vectors::deposit_rows() { + let mut context = Context::default(); + let funding_lock = always_success_lock(&mut context); + let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); + let receipt = context.create_cell( + CellOutput::new_builder() + .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) + .lock(funding_lock.clone()) + .type_(Some(ickb_logic).pack()) + .build(), + receipt_data(1, row.amount), + ); + let header = insert_header_for_cell(&mut context, &receipt, 0, row.ar); + + for minted in [row.expected_ickb, row.expected_ickb + 1, row.expected_ickb - 1] { + let tx = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(receipt.clone()).build()) + .output( + CellOutput::new_builder() + .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) + .lock(funding_lock.clone()) + .type_(Some(xudt.clone()).pack()) + .build(), + ) + .output_data(udt_data(minted).pack()) + .header_dep(header.clone()) + .build(); + let tx = context.complete_tx(tx); + let result = context.verify(&tx, MAX_CYCLES); + if minted == row.expected_ickb { + result.unwrap_or_else(|err| panic!("{}: {err}", row.note)); + } else { + let err = result.expect_err(&row.note); + assert_script_error(err, ERROR_AMOUNT_MISMATCH); + } + } + } +} + +// Every constructible match vector as a real order continuation: the binary returns the verdict of the copied validate. +#[test] +fn every_limit_order_vector_gets_the_verdict_of_the_copied_validate() { + let mut unconstructible = Vec::new(); + for row in vectors::limit_rows() { + let mut context = Context::default(); + let (limit_order, helper_type) = limit_order_and_helper_type_scripts(&mut context); + let occupied = deposit_capacity(&limit_order, &helper_type, 89, 0); + let (in_ckb, in_udt, in_unoccupied) = row.input; + let (out_ckb, out_udt, out_unoccupied) = row.output; + // Vectors model a small occupied capacity; a real order cell occupies more. validate only + // compares input with output, so shifting both by the same occupied capacity keeps the verdict. + // Input and output share lock, type and data length, so a row whose two sides imply different + // occupied capacities describes cells consensus cannot create. + if in_ckb - in_unoccupied != out_ckb - out_unoccupied { + unconstructible.push(row.note); + continue; + } + let order = |unoccupied: u64, udt: u128| { + ( + CellOutput::new_builder() + .capacity((occupied + unoccupied).pack()) + .lock(limit_order.clone()) + .type_(Some(helper_type.clone()).pack()) + .build(), + order_data_custom( + udt, + 1, + [0u8; 32], + 5u32.to_le_bytes(), + row.ckb_to_udt.unwrap_or((0, 0)), + row.udt_to_ckb.unwrap_or((0, 0)), + row.ckb_min_match_log, + ), + ) + }; + let (input_cell, input_data) = order(in_unoccupied, in_udt); + let (output_cell, output_data) = order(out_unoccupied, out_udt); + let input = context.create_cell(input_cell, input_data); + + // ckb-testtool runs scripts only, so the transaction needs no capacity balancing. + let tx = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(input).build()) + .output(output_cell) + .output_data(output_data.pack()) + .build(); + let tx = context.complete_tx(tx); + let result = context.verify(&tx, MAX_CYCLES); + let expected = match row.verdict { + Ok(()) => { + result.unwrap_or_else(|err| panic!("{}: {err}", row.note)); + continue; + } + Err(Verdict::DifferentInfo) => ERROR_LIMIT_ORDER_DIFFERENT_INFO, + Err(Verdict::InvalidMatch) => ERROR_LIMIT_ORDER_INVALID_MATCH, + Err(Verdict::DecreasingValue) => ERROR_LIMIT_ORDER_DECREASING_VALUE, + Err(Verdict::AttemptToChangeFulfilled) => ERROR_LIMIT_ORDER_ATTEMPT_TO_CHANGE_FULFILLED, + Err(Verdict::InsufficientMatch) => ERROR_LIMIT_ORDER_INSUFFICIENT_MATCH, + }; + let err = result.expect_err(row.note); + assert_script_error(err, expected); + } + // Both shrink a fulfilled CKB->UDT order below its occupied capacity, the only way to reach + // AttemptToChangeFulfilled on that side: on chain that error is unreachable. + assert_eq!( + unconstructible, + [ + "ckb2udt: value-preserving change of fulfilled order rejected", + "check order: DecreasingValue precedes AttemptToChangeFulfilled", + ] + ); +} diff --git a/scripts/vector-gen/README.md b/scripts/vector-gen/README.md new file mode 100644 index 0000000..a112d76 --- /dev/null +++ b/scripts/vector-gen/README.md @@ -0,0 +1,14 @@ +# vector-gen + +Golden protocol vectors for the iCKB stack's TypeScript contract oracle: the values the contracts' own Rust logic gives each case. The cases and their expected values live in `src/vectors.rs`; `src/main.rs` writes them as JSON. + +`src/vectors.rs` compiles `c256.rs` and `ickb_logic/constants.rs` straight from the contract sources and holds byte-exact copies of the private `deposit_to_ickb` and `validate`; `drift_checks` fails if a copy stops matching its source. The contract tests include the same file and replay its rows against the release binaries (`../tests/src/tests/protocol_vectors.rs`), skipping by name the two that describe cells consensus cannot create, so `cargo test -p tests` checks the vectors but does not build this writer. + +The crate stays outside the contracts workspace (see `Cargo.toml`). To regenerate the stack's fixture from a checkout next to this one: + +```sh +cargo run --release --locked -- ../../../stack/testkit/fixtures/protocol_vectors.json +cd ../../../stack && pnpm exec prettier --write testkit/fixtures/protocol_vectors.json +``` + +The writer emits one object per line; the stack keeps the file Prettier-formatted, so only the second step makes the result byte-identical to the committed fixture. From ff7c5d069228d80988ecdc9f6d3a3a5e2af0a540 Mon Sep 17 00:00:00 2001 From: phroi <90913182+phroi@users.noreply.github.com> Date: Sat, 26 Sep 2026 15:15:41 +0200 Subject: [PATCH 05/13] test: iCKB Logic regressions for claims the review had not executed Each test backs a report conclusion that had no executable evidence: - receiptless deposits of 500 CKB and 0 CKB unoccupied are created without the deposit bounds, which iCKB Logic checks only when a receipt makes it run, and are withdrawn at exactly their iCKB value; - withdrawing a 1,000 CKB deposit returns more CKB per iCKB than a 100k CKB one, because the claim also returns the occupied capacity the valuation leaves out; - under a non-genesis AR, ten shannons past the shifted soft-cap edge mint cap+9, which only normalization before the haircut yields; - a withdrawal request locked by iCKB Logic fails with ScriptMisuse, with a user-locked control; - withdrawing and re-depositing in one transaction verifies with the request at the deposit's index and fails with DAO error -20 when the two swap; - a deposit and receipt created in the same block and spent together mint nothing, while minting 1 fails with AmountMismatch; - a phase 2 conversion with 512 unrelated outputs stays within the cycle budget. --- scripts/tests/src/tests.rs | 56 +++++++ .../tests/ickb_logic/creation_blind_spots.rs | 55 +++++++ .../tests/ickb_logic/economic_precision.rs | 88 ++++++++++ .../ickb_logic/mixed_flow_composition.rs | 150 ++++++++++++++++++ .../receiptless_deposit_blind_spot.rs | 86 ++++++++++ 5 files changed, 435 insertions(+) diff --git a/scripts/tests/src/tests.rs b/scripts/tests/src/tests.rs index 1c39c14..bed5246 100644 --- a/scripts/tests/src/tests.rs +++ b/scripts/tests/src/tests.rs @@ -189,6 +189,62 @@ fn load_binary(name: &str) -> Bytes { Loader::default().load_binary(name) } +#[test] +fn type_role_scan_with_512_unrelated_outputs_stays_within_test_cycle_budget() { + const PADDING_OUTPUTS: usize = 512; + + let mut context = Context::default(); + let user_lock = always_success_lock(&mut context); + let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); + let deposit_amount = 1_000 * CKB; + let deposit_header = gen_header(1554, GENESIS_AR, 35, 1000, 1000); + let receipt_input = context.create_cell( + CellOutput::new_builder() + .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) + .lock(user_lock.clone()) + .type_(Some(ickb_logic).pack()) + .build(), + receipt_data(1, deposit_amount), + ); + link_cell_to_header(&mut context, &receipt_input, &deposit_header); + let funding_input = context.create_cell( + CellOutput::new_builder() + .capacity(((PADDING_OUTPUTS as u64 + 1) * 100 * CKB).pack()) + .lock(user_lock.clone()) + .build(), + Bytes::new(), + ); + + let mut outputs = vec![CellOutput::new_builder() + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) + .lock(user_lock.clone()) + .type_(Some(xudt).pack()) + .build()]; + let mut outputs_data = vec![udt_data(u128::from(deposit_amount))]; + for _ in 0..PADDING_OUTPUTS { + outputs.push( + CellOutput::new_builder() + .capacity((100 * CKB).pack()) + .lock(user_lock.clone()) + .build(), + ); + outputs_data.push(Bytes::new()); + } + + let tx = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(receipt_input).build()) + .input(CellInput::new_builder().previous_output(funding_input).build()) + .outputs(outputs) + .outputs_data(outputs_data.pack()) + .header_dep(deposit_header.hash()) + .build(); + let tx = context.complete_tx(tx); + // verify fails with ExceededMaximumCycles above the budget, so passing is the bound. + context + .verify(&tx, MAX_CYCLES) + .expect("type-role scan with 512 unrelated outputs should stay within the test cycle budget"); +} + // Harness sanity checks. #[test] fn release_binary_hashes_match_deployment_references() { diff --git a/scripts/tests/src/tests/ickb_logic/creation_blind_spots.rs b/scripts/tests/src/tests/ickb_logic/creation_blind_spots.rs index 4c9b98d..dee0999 100644 --- a/scripts/tests/src/tests/ickb_logic/creation_blind_spots.rs +++ b/scripts/tests/src/tests/ickb_logic/creation_blind_spots.rs @@ -106,3 +106,58 @@ fn non_empty_args_ickb_logic_lock_output_can_be_created_but_not_spent() { let err = context.verify(&spend_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_NOT_EMPTY_ARGS); } + +// A withdrawal request keeps the deposit's DAO type but carries non-zero data, so it is no deposit; +// locked by ickb_logic it matches no valid shape and the script rejects it rather than treating it as Unknown. +#[test] +fn withdrawal_request_locked_by_ickb_logic_is_script_misuse() { + let mut context = Context::default(); + let user_lock = always_success_lock(&mut context); + let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); + + let deposit_amount = 1_500 * CKB; + let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, deposit_amount); + let deposit_input = context.create_cell( + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(ickb_logic.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + dao_deposit_data(), + ); + let deposit_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); + link_cell_to_header(&mut context, &deposit_input, &deposit_header); + let udt_input = context.create_cell( + CellOutput::new_builder() + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) + .lock(user_lock.clone()) + .type_(Some(xudt).pack()) + .build(), + udt_data(u128::from(deposit_amount)), + ); + + let withdraw_tx = |request_lock: &Script| { + TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(deposit_input.clone()).build()) + .input(CellInput::new_builder().previous_output(udt_input.clone()).build()) + .output( + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(request_lock.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + ) + .output_data(withdrawal_request_data(1554).pack()) + .header_dep(deposit_header.hash()) + .build() + }; + + let control = context.complete_tx(withdraw_tx(&user_lock)); + context + .verify(&control, MAX_CYCLES) + .expect("the same request under a user lock is a valid phase1 withdrawal"); + + let misuse = context.complete_tx(withdraw_tx(&ickb_logic)); + let err = context.verify(&misuse, MAX_CYCLES).unwrap_err(); + assert_script_error(err, ERROR_SCRIPT_MISUSE); +} diff --git a/scripts/tests/src/tests/ickb_logic/economic_precision.rs b/scripts/tests/src/tests/ickb_logic/economic_precision.rs index a1a1ae1..b44539f 100644 --- a/scripts/tests/src/tests/ickb_logic/economic_precision.rs +++ b/scripts/tests/src/tests/ickb_logic/economic_precision.rs @@ -88,6 +88,65 @@ fn reported_rounding_claim_is_blocked_by_actual_shannon_precision() { assert_script_error(err, ERROR_AMOUNT_MISMATCH); } +// Pin the shifted soft-cap edge under a non-genesis AR: normalization reaches the cap at 110k CKB. Ten shannons past it, normalizing first mints cap+9 while applying the haircut first would mint cap+8, so the passing cap+9 mint proves normalization precedes the per-deposit haircut; eleven past it, cap+10 must fail. +#[test] +fn non_genesis_ar_soft_cap_boundary_preserves_integer_operation_order() { + let mut context = Context::default(); + let owner_lock = always_success_lock(&mut context); + let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); + + let ar = 11_000_000_000_000_000u64; + let soft_cap = 100_000 * CKB as u128; + let shifted_boundary = 110_000 * CKB; + let normalized = |amount: u64| { + u128::from(amount) * u128::from(GENESIS_AR) / u128::from(ar) + }; + + assert_eq!(normalized(shifted_boundary), soft_cap); + assert_eq!(normalized(shifted_boundary + 10), soft_cap + 9); + assert_eq!(normalized(shifted_boundary + 11), soft_cap + 10); + assert_eq!(soft_capped_ickb(shifted_boundary + 10, ar), soft_cap + 9); + assert_eq!(soft_capped_ickb(shifted_boundary + 11, ar), soft_cap + 9); + + let mut assert_mint = |block_number: u64, amount: u64, minted: u128, should_pass: bool| { + let receipt = context.create_cell( + CellOutput::new_builder() + .capacity(occupied_capacity(&owner_lock, &ickb_logic, 12).pack()) + .lock(owner_lock.clone()) + .type_(Some(ickb_logic.clone()).pack()) + .build(), + receipt_data(1, amount), + ); + let receipt_header = gen_header(block_number, ar, 1, 1, 1000); + link_cell_to_header(&mut context, &receipt, &receipt_header); + let tx = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(receipt).build()) + .output( + CellOutput::new_builder() + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) + .lock(owner_lock.clone()) + .type_(Some(xudt.clone()).pack()) + .build(), + ) + .output_data(udt_data(minted).pack()) + .header_dep(receipt_header.hash()) + .build(); + let tx = context.complete_tx(tx); + let result = context.verify(&tx, MAX_CYCLES); + + if should_pass { + result.expect("exact mint at the AR-shifted soft-cap boundary should verify"); + } else { + assert_script_error(result.unwrap_err(), ERROR_AMOUNT_MISMATCH); + } + }; + + assert_mint(1, shifted_boundary, soft_cap, true); + assert_mint(2, shifted_boundary + 10, soft_cap + 9, true); + assert_mint(3, shifted_boundary + 11, soft_cap + 10, false); + assert_mint(4, shifted_boundary + 11, soft_cap + 9, true); +} + // Build phase1 deposit-to-withdrawal conversions around the same rounding claim: burning a rounded-down iCKB amount fails, but burning the exact header-normalized amount passes, so withdrawal initiation also enforces shannon-precise value matching. #[test] fn reported_rounding_withdrawal_claim_is_blocked_by_actual_shannon_precision() { @@ -358,3 +417,32 @@ fn burn_and_claim( (burned_ickb, claim_capacity, deposit_occupied_capacity) } + +// The iCKB value counts only unoccupied capacity, while the DAO claim also returns the occupied 82 CKB: +// per iCKB burned, a small deposit returns more CKB than a standard one. This is the whitepaper's +// intended penalty on small deposits, collected by whoever withdraws them. +#[test] +fn smaller_deposits_return_more_ckb_per_ickb_burned_by_their_occupied_capacity() { + let mut context = Context::default(); + let user_lock = always_success_lock(&mut context); + let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); + let withdraw_ar = 12_000_000_000_000_000u64; + let withdraw_header = gen_header(2_000_610, withdraw_ar, 575, 2_000_000, 1100); + let deposit_ar = 11_000_000_000_000_000u64; + + let mut ckb_per_ickb = |amount: u64, deposit_number: u64| { + // The verified claim is the unoccupied capacity grown by the AR ratio, plus the occupied capacity. + let (burned, claimed, _) = burn_and_claim( + &mut context, + (&user_lock, &ickb_logic, &dao, &xudt), + (&withdraw_header, withdraw_ar), + (amount, deposit_number, deposit_ar), + ); + (claimed, burned) + }; + let (small_claim, small_burn) = ckb_per_ickb(1_000 * CKB, 1554); + let (standard_claim, standard_burn) = ckb_per_ickb(100_000 * CKB, 1555); + + // Compare claim / burn without division: small_claim * standard_burn > standard_claim * small_burn. + assert!(u128::from(small_claim) * standard_burn > u128::from(standard_claim) * small_burn); +} diff --git a/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs b/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs index bcdb77c..77222f2 100644 --- a/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs +++ b/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs @@ -234,3 +234,153 @@ fn all_three_scripts_can_compose_in_one_live_state_transition() { .verify(&tx, MAX_CYCLES) .expect("a live receipt, live deposit, and live limit order should compose in one valid transaction"); } + +// Scenario 4F: withdrawing a deposit and re-depositing its value in one transaction must leave the +// withdrawal request at the deposit's index. Putting the fresh deposit there instead would restart +// the deposit's age in place; NervosDAO phase 1 rejects that layout. +#[test] +fn fresh_deposit_cannot_replace_a_withdrawn_deposit_at_its_index() { + let mut context = Context::default(); + let user_lock = always_success_lock(&mut context); + let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); + + let amount = 1_500 * CKB; + let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, amount); + let deposit_input = context.create_cell( + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(ickb_logic.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + dao_deposit_data(), + ); + let deposit_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); + link_cell_to_header(&mut context, &deposit_input, &deposit_header); + let udt_input = context.create_cell( + CellOutput::new_builder() + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) + .lock(user_lock.clone()) + .type_(Some(xudt).pack()) + .build(), + udt_data(u128::from(amount)), + ); + let funding_input = context.create_cell( + CellOutput::new_builder() + .capacity((2 * deposit_total_capacity).pack()) + .lock(user_lock.clone()) + .build(), + Bytes::new(), + ); + + let request = ( + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(user_lock.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + withdrawal_request_data(1554), + ); + let fresh_deposit = ( + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(ickb_logic.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + dao_deposit_data(), + ); + let receipt = ( + CellOutput::new_builder() + .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) + .lock(user_lock.clone()) + .type_(Some(ickb_logic.clone()).pack()) + .build(), + receipt_data(1, amount), + ); + + let tx = |outputs: Vec<(CellOutput, Bytes)>| { + let (cells, data): (Vec<_>, Vec<_>) = outputs.into_iter().unzip(); + let tx: TransactionView = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(deposit_input.clone()).build()) + .input(CellInput::new_builder().previous_output(udt_input.clone()).build()) + .input(CellInput::new_builder().previous_output(funding_input.clone()).build()) + .outputs(cells) + .outputs_data(data.pack()) + .header_dep(deposit_header.hash()) + .build(); + tx + }; + + let withdraw_and_redeposit = context.complete_tx(tx(vec![request.clone(), fresh_deposit.clone(), receipt.clone()])); + context + .verify(&withdraw_and_redeposit, MAX_CYCLES) + .expect("withdrawing with the request at the deposit's index and re-depositing elsewhere verifies"); + + // Same cells with the two DAO outputs swapped: the fresh deposit takes the withdrawn deposit's index. + let reset_in_place = context.complete_tx(tx(vec![fresh_deposit, request, receipt])); + let err = context.verify(&reset_in_place, MAX_CYCLES).unwrap_err(); + assert_script_error(err, ERROR_DAO_INVALID_WITHDRAWING_CELL); +} + +// Scenario 6G: a deposit and its receipt created in the same block read the same accumulated rate, +// so a later transaction spending both (receipt to phase 2, deposit to withdrawal) mints nothing. +#[test] +fn same_block_receipt_and_deposit_mint_nothing_when_spent_together() { + let mut context = Context::default(); + let user_lock = always_success_lock(&mut context); + let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); + + let amount = 1_500 * CKB; + let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, amount); + let creation_header = gen_header(1554, SYNTHETIC_WITHDRAW_AR, 35, 1000, 1000); + let deposit_input = context.create_cell( + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(ickb_logic.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + dao_deposit_data(), + ); + let receipt_input = context.create_cell( + CellOutput::new_builder() + .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) + .lock(user_lock.clone()) + .type_(Some(ickb_logic.clone()).pack()) + .build(), + receipt_data(1, amount), + ); + link_cell_to_header(&mut context, &deposit_input, &creation_header); + link_cell_to_header(&mut context, &receipt_input, &creation_header); + + for minted in [0u128, 1] { + let mut builder = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(deposit_input.clone()).build()) + .input(CellInput::new_builder().previous_output(receipt_input.clone()).build()) + .output( + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(user_lock.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + ) + .output_data(withdrawal_request_data(1554).pack()) + .header_dep(creation_header.hash()); + if minted > 0 { + builder = builder + .output( + CellOutput::new_builder() + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) + .lock(user_lock.clone()) + .type_(Some(xudt.clone()).pack()) + .build(), + ) + .output_data(udt_data(minted).pack()); + } + let tx = context.complete_tx(builder.build()); + let result = context.verify(&tx, MAX_CYCLES); + if minted == 0 { + result.expect("the receipt's value exactly pays for the same-rate deposit"); + } else { + assert_script_error(result.unwrap_err(), ERROR_AMOUNT_MISMATCH); + } + } +} diff --git a/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs b/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs index 6698c00..b65412b 100644 --- a/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs +++ b/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs @@ -74,6 +74,92 @@ fn receiptless_dao_shaped_output_is_accepted_as_deposit() { .expect("later phase1 withdrawal request should accept the receiptless DAO-shaped output as a structurally valid deposit input"); } +// The deposit bounds live in ickb_logic's output check, which runs only when the creating tx also +// carries a receipt; a receiptless deposit of any size is created without it. Below the minimum (500 CKB +// and 0 CKB unoccupied), such a deposit is still withdrawn at its exact iCKB value. +#[test] +fn receiptless_deposits_below_the_minimum_are_created_and_withdrawn_at_value() { + for deposit_amount in [500 * CKB, 0] { + let mut context = Context::default(); + let user_lock = always_success_lock(&mut context); + let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); + let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, deposit_amount); + + let funding_input = context.create_cell( + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(user_lock.clone()) + .build(), + Bytes::new(), + ); + let create_tx = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(funding_input).build()) + .output( + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(ickb_logic.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + ) + .output_data(dao_deposit_data().pack()) + .build(); + let create_tx = context.complete_tx(create_tx); + context + .verify(&create_tx, MAX_CYCLES) + .expect("a receiptless deposit below the minimum is created without running the bounds check"); + + let deposit_input = context.create_cell( + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(ickb_logic.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + dao_deposit_data(), + ); + let deposit_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); + link_cell_to_header(&mut context, &deposit_input, &deposit_header); + + // At the genesis AR a deposit below the soft cap is worth exactly its unoccupied capacity. + let mut burns = vec![u128::from(deposit_amount)]; + if deposit_amount > 0 { + burns.push(u128::from(deposit_amount) - 1); + } + for burned in burns { + let mut builder = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(deposit_input.clone()).build()); + if burned > 0 { + let udt_input = context.create_cell( + CellOutput::new_builder() + .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) + .lock(user_lock.clone()) + .type_(Some(xudt.clone()).pack()) + .build(), + udt_data(burned), + ); + builder = builder.input(CellInput::new_builder().previous_output(udt_input).build()); + } + let withdraw_tx = builder + .output( + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(user_lock.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + ) + .output_data(withdrawal_request_data(1554).pack()) + .header_dep(deposit_header.hash()) + .build(); + let withdraw_tx = context.complete_tx(withdraw_tx); + let result = context.verify(&withdraw_tx, MAX_CYCLES); + if burned == u128::from(deposit_amount) { + result.expect("burning exactly the deposit's value withdraws it"); + } else { + assert_script_error(result.unwrap_err(), ERROR_AMOUNT_MISMATCH); + } + } + } +} + // Build one tx that combines a legitimate split receipt with a separately funded receiptless aggregate deposit and rolls the aggregate into withdrawal: only the soft-cap spread should mint as xUDT, so the exact delta passes and any extra principal remains excluded. #[test] fn split_receipt_against_receiptless_aggregate_mints_only_spread() { From b622548518627d4ee8bd362e179909610577eda6 Mon Sep 17 00:00:00 2001 From: phroi <90913182+phroi@users.noreply.github.com> Date: Sat, 26 Sep 2026 15:15:45 +0200 Subject: [PATCH 06/13] test: Owned Owner regressions for pairing and a signed sparse claim - Two owned withdrawal requests with a single owner cell fail with Mismatch, the reverse of the existing two-owners-for-one-request case. - Phase 1 consumes two noncontiguous inputs under the same secp lock, then phase 2 spends the signed owner cell and completes the DAO claim; a signing test shows the noncontiguous group signature verifies and a tampered witness does not. The signing helper is generalized from a contiguous input range to any input indices for it. --- .../src/tests/owned_owner/pair_formation.rs | 77 +++++++++++ .../owned_owner/positive_distance_claims.rs | 123 ++++++++++++++++++ scripts/tests/src/tests/signing.rs | 79 ++++++++++- 3 files changed, 278 insertions(+), 1 deletion(-) diff --git a/scripts/tests/src/tests/owned_owner/pair_formation.rs b/scripts/tests/src/tests/owned_owner/pair_formation.rs index 2559975..0507648 100644 --- a/scripts/tests/src/tests/owned_owner/pair_formation.rs +++ b/scripts/tests/src/tests/owned_owner/pair_formation.rs @@ -174,6 +174,83 @@ fn two_owner_cells_for_one_owned_output_are_rejected() { assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); } +// The reverse of the case above: two owned withdrawal requests and a single owner cell. +// Expectation: Owned Owner rejects the request left without an owner. +#[test] +fn two_owned_outputs_for_one_owner_cell_are_rejected() { + let mut context = Context::default(); + let owner_lock = named_always_success_lock(&mut context, b"owner"); + let funding_lock = named_always_success_lock(&mut context, b"funding"); + let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); + + let deposit_amount = 1_000 * CKB; + let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); + let mut deposit = || { + let input = context.create_cell( + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(ickb_logic.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + dao_deposit_data(), + ); + link_cell_to_header(&mut context, &input, &deposit_header); + input + }; + let (first_deposit, second_deposit) = (deposit(), deposit()); + let udt_input = context.create_cell( + CellOutput::new_builder() + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) + .lock(owner_lock.clone()) + .type_(Some(xudt).pack()) + .build(), + udt_data(2 * u128::from(deposit_amount)), + ); + let funding_input = context.create_cell( + CellOutput::new_builder() + .capacity((200 * CKB).pack()) + .lock(funding_lock) + .build(), + Bytes::new(), + ); + + let owned_request = || { + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(owned_owner.clone()) + .type_(Some(dao.clone()).pack()) + .build() + }; + let tx = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(first_deposit).build()) + .input(CellInput::new_builder().previous_output(second_deposit).build()) + .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(CellInput::new_builder().previous_output(funding_input).build()) + .outputs(vec![ + owned_request(), + owned_request(), + CellOutput::new_builder() + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) + .lock(owner_lock) + .type_(Some(owned_owner.clone()).pack()) + .build(), + ]) + .outputs_data( + vec![ + withdrawal_request_data(1554), + withdrawal_request_data(1554), + owner_distance_data(-2), + ] + .pack(), + ) + .header_dep(deposit_header.hash()) + .build(); + + let tx = context.complete_tx(tx); + let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); + assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); +} + // Output-lock creation can admit an orphan withdrawal request, but the later claim still fails once Owned Owner executes. #[test] fn orphan_withdrawal_request_can_be_created_but_not_claimed() { diff --git a/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs b/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs index df51a64..94db1fd 100644 --- a/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs +++ b/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs @@ -246,3 +246,126 @@ fn sparse_positive_distance_pair_can_complete_phase2_claim_at_exact_capacity() { .verify(&claim_tx, MAX_CYCLES) .expect("a sparse positive-distance pair should remain spendable in DAO phase2 at the exact claim capacity"); } + +// Scenario: phase 1 consumes two noncontiguous inputs protected by the same secp lock, then phase 2 spends the signed owner cell. +// Expectation: both signed transactions verify and the sparse Owned Owner pair completes its DAO claim. +#[test] +fn secp_protected_sparse_pair_can_complete_signed_phase2_claim() { + let mut context = Context::default(); + let (privkey, owner_lock, secp_data_dep) = secp_lock(&mut context); + let filler_lock = named_always_success_lock(&mut context, b"filler"); + let (ickb_logic, owned_owner, dao, xudt) = ickb_logic_owned_owner_dao_and_xudt_scripts(&mut context); + + let deposit_amount = 1_000 * CKB; + let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); + let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); + let funding_input = context.create_cell( + CellOutput::new_builder() + .capacity((100 * CKB).pack()) + .lock(owner_lock.clone()) + .build(), + Bytes::new(), + ); + let filler_input = context.create_cell( + CellOutput::new_builder() + .capacity((100 * CKB).pack()) + .lock(filler_lock.clone()) + .build(), + Bytes::new(), + ); + let deposit_input = context.create_cell( + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(ickb_logic) + .type_(Some(dao.clone()).pack()) + .build(), + dao_deposit_data(), + ); + link_cell_to_header(&mut context, &deposit_input, &deposit_header); + let udt_input = context.create_cell( + CellOutput::new_builder() + .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) + .lock(owner_lock.clone()) + .type_(Some(xudt).pack()) + .build(), + udt_data(u128::from(deposit_amount)), + ); + + let create_tx = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(CellInput::new_builder().previous_output(filler_input).build()) + .input(CellInput::new_builder().previous_output(deposit_input).build()) + .input(CellInput::new_builder().previous_output(udt_input).build()) + .outputs(vec![ + CellOutput::new_builder() + .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) + .lock(owner_lock.clone()) + .type_(Some(owned_owner.clone()).pack()) + .build(), + CellOutput::new_builder() + .capacity((100 * CKB).pack()) + .lock(filler_lock) + .build(), + CellOutput::new_builder() + .capacity(deposit_total_capacity.pack()) + .lock(owned_owner.clone()) + .type_(Some(dao.clone()).pack()) + .build(), + ]) + .outputs_data( + vec![ + owner_distance_data(2), + Bytes::new(), + withdrawal_request_data(1554), + ] + .pack(), + ) + .header_dep(deposit_header.hash()) + .witness(empty_witness().pack()) + .witness(Bytes::new().pack()) + .witness(Bytes::new().pack()) + .witness(Bytes::new().pack()) + .cell_dep(secp_data_dep.clone()) + .build(); + let create_tx = sign_tx_by_input_indices(context.complete_tx(create_tx), &privkey, &[0, 3]); + context + .verify(&create_tx, MAX_CYCLES) + .expect("signed phase1 creation with a noncontiguous secp group should verify"); + + let owner_out_point = seed_verified_output(&mut context, &create_tx, 0, owner_distance_data(2)); + let owned_out_point = seed_verified_output(&mut context, &create_tx, 2, withdrawal_request_data(1554)); + link_cell_to_header(&mut context, &owned_out_point, &withdraw_header); + context.insert_header(deposit_header.clone()); + + let exact_capacity = dao_maximum_withdraw_capacity( + &create_tx.outputs().get(2).expect("owned output"), + withdrawal_request_data(1554).len(), + GENESIS_AR as u64, + SYNTHETIC_WITHDRAW_AR, + ); + let claim_tx = TransactionBuilder::default() + .input( + CellInput::new_builder() + .previous_output(owned_out_point) + .since(0x2003e800000002f4u64.pack()) + .build(), + ) + .input(CellInput::new_builder().previous_output(owner_out_point).build()) + .output( + CellOutput::new_builder() + .capacity(exact_capacity.pack()) + .lock(owner_lock) + .build(), + ) + .output_data(Bytes::new().pack()) + .header_dep(withdraw_header.hash()) + .header_dep(deposit_header.hash()) + .witness(header_dep_index_witness(1).pack()) + .witness(empty_witness().pack()) + .cell_dep(secp_data_dep) + .build(); + let claim_tx = sign_tx_by_input_group(context.complete_tx(claim_tx), &privkey, 1, 1); + context + .verify(&claim_tx, MAX_CYCLES) + .expect("signed secp-protected owner should complete the phase2 DAO claim"); +} diff --git a/scripts/tests/src/tests/signing.rs b/scripts/tests/src/tests/signing.rs index 0289a69..dfc5476 100644 --- a/scripts/tests/src/tests/signing.rs +++ b/scripts/tests/src/tests/signing.rs @@ -15,9 +15,24 @@ pub(super) fn sign_tx_by_input_group( key: &Privkey, begin_index: usize, group_len: usize, +) -> TransactionView { + let group_indices = (begin_index..(begin_index + group_len)).collect::>(); + sign_tx_by_input_indices(tx, key, &group_indices) +} + +pub(super) fn sign_tx_by_input_indices( + tx: TransactionView, + key: &Privkey, + group_indices: &[usize], ) -> TransactionView { let tx_hash = tx.hash(); let inputs_len = tx.inputs().len(); + let (&begin_index, rest_group_indices) = group_indices.split_first().expect("non-empty input group"); + assert!( + group_indices.windows(2).all(|indices| indices[0] < indices[1]), + "input group indices must be strictly increasing" + ); + assert!(group_indices.last().expect("input group") < &inputs_len, "input group index out of bounds"); let mut signed_witnesses: Vec = tx .inputs() .into_iter() @@ -36,7 +51,7 @@ pub(super) fn sign_tx_by_input_group( blake2b.update(&witness_for_digest.as_bytes()); // CKB sighash signs the rest of the current input group, then any trailing extra // witnesses after all inputs. It does not cover other input groups. - ((i + 1)..(i + group_len)).for_each(|n| { + rest_group_indices.iter().for_each(|&n| { let witness = tx.witnesses().get(n).unwrap(); let witness_len = witness.raw_data().len() as u64; blake2b.update(&witness_len.to_le_bytes()); @@ -266,3 +281,65 @@ fn sign_tx_by_input_group_covers_trailing_extra_witnesses_for_later_groups() { let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } + +#[test] +fn sign_tx_by_input_indices_signs_a_noncontiguous_secp_group() { + let mut context = Context::default(); + let passthrough_lock = always_success_lock(&mut context); + let (privkey, protected_lock, secp_data_dep) = secp_lock(&mut context); + + let protected_input_0 = context.create_cell( + CellOutput::new_builder() + .capacity((1_000 * CKB).pack()) + .lock(protected_lock.clone()) + .build(), + Bytes::new(), + ); + let passthrough_input = context.create_cell( + CellOutput::new_builder() + .capacity((1_000 * CKB).pack()) + .lock(passthrough_lock.clone()) + .build(), + Bytes::new(), + ); + let protected_input_2 = context.create_cell( + CellOutput::new_builder() + .capacity((1_000 * CKB).pack()) + .lock(protected_lock) + .build(), + Bytes::new(), + ); + + let tx = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(protected_input_0).build()) + .input(CellInput::new_builder().previous_output(passthrough_input).build()) + .input(CellInput::new_builder().previous_output(protected_input_2).build()) + .output( + CellOutput::new_builder() + .capacity((2_800 * CKB).pack()) + .lock(passthrough_lock) + .build(), + ) + .output_data(Bytes::new().pack()) + .witness(empty_witness().pack()) + .witness(Bytes::new().pack()) + .witness(Bytes::from_static(b"noncontiguous-group-witness").pack()) + .cell_dep(secp_data_dep) + .build(); + + let tx = sign_tx_by_input_indices(context.complete_tx(tx), &privkey, &[0, 2]); + context + .verify(&tx, MAX_CYCLES) + .expect("noncontiguous secp input group should verify"); + + let tampered_tx = tx + .as_advanced_builder() + .set_witnesses(vec![ + tx.witnesses().get(0).expect("signed witness"), + tx.witnesses().get(1).expect("passthrough witness"), + Bytes::from_static(b"tampered-group-witness").pack(), + ]) + .build(); + let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); + assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); +} From 35e667d323e37de950b521e67061771de9d0265f Mon Sep 17 00:00:00 2001 From: phroi <90913182+phroi@users.noreply.github.com> Date: Sat, 26 Sep 2026 15:15:49 +0200 Subject: [PATCH 07/13] test: a mint pairs each order with exactly one master A master cell carries limit_order as its type, so the script runs at mint and pairs every order with exactly one master. One order with its master mints; two orders on one master fail with SameMaster; a master without an order and an order pointing at a cell that is no master fail with InvalidConfiguration. This bounds the Limit Order confusion attack: it needs order cells created in a transaction with no master, where the script does not run. --- .../limit_order/crosswire_mint_creation.rs | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs b/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs index b25a74c..6a20233 100644 --- a/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs +++ b/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs @@ -249,3 +249,68 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { let err = context.verify(&melt_expected, MAX_CYCLES).unwrap_err(); assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } + +// A master's type script runs at mint and pairs every order with exactly one master: one order per +// master passes, two orders on one master fail, a master without an order fails, and an order +// pointing at a cell that is no master fails. +#[test] +fn mint_pairs_each_order_with_exactly_one_master() { + let mut context = Context::default(); + let owner_lock = named_always_success_lock(&mut context, b"owner"); + let (_, helper_type) = named_lock_and_helper_type_scripts(&mut context, b"owner"); + let limit_order = limit_order_script(&mut context); + let order = || { + CellOutput::new_builder() + .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) + .lock(limit_order.clone()) + .type_(Some(helper_type.clone()).pack()) + .build() + }; + let master = || { + CellOutput::new_builder() + .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) + .lock(owner_lock.clone()) + .type_(Some(limit_order.clone()).pack()) + .build() + }; + let mut mint = |outputs: Vec<(CellOutput, Bytes)>| { + let funding = funding_cell(&mut context); + let (cells, data): (Vec<_>, Vec<_>) = outputs.into_iter().unzip(); + let tx = TransactionBuilder::default() + .input(CellInput::new_builder().previous_output(funding).build()) + .outputs(cells) + .outputs_data(data.pack()) + .build(); + let tx = context.complete_tx(tx); + context.verify(&tx, MAX_CYCLES) + }; + + mint(vec![(order(), order_data_mint(0, 1, (1, 1))), (master(), Bytes::new())]) + .expect("one order with its own master mints"); + + let two_orders_one_master = mint(vec![ + (order(), order_data_mint(0, 2, (1, 1))), + (order(), order_data_mint(0, 1, (1, 1))), + (master(), Bytes::new()), + ]); + assert_script_error(two_orders_one_master.unwrap_err(), ERROR_LIMIT_ORDER_SAME_MASTER); + + let master_without_order = mint(vec![ + (order(), order_data_mint(0, 1, (1, 1))), + (master(), Bytes::new()), + (master(), Bytes::new()), + ]); + assert_script_error(master_without_order.unwrap_err(), ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); + + let plain = CellOutput::new_builder() + .capacity((100 * CKB).pack()) + .lock(owner_lock.clone()) + .build(); + let order_without_master = mint(vec![ + (order(), order_data_mint(0, 1, (1, 1))), + (master(), Bytes::new()), + (order(), order_data_mint(0, 1, (1, 1))), + (plain, Bytes::new()), + ]); + assert_script_error(order_without_master.unwrap_err(), ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); +} From 7ac68381bfe3d2273489934055d57ff501cc5722 Mon Sep 17 00:00:00 2001 From: phroi <90913182+phroi@users.noreply.github.com> Date: Sat, 26 Sep 2026 15:15:52 +0200 Subject: [PATCH 08/13] docs: the report states what the executable review now shows The report is updated to the tests added before it, and corrected where a re-audit found it wrong or unsupported. Contract-source citations stay pinned to the reviewed commit 454cfa9, whose code is deployed and immutable. Findings and conclusions: - LO-01 now names its cause: limit_order runs only when a transaction creates or spends a master or spends an order, so order cells created alone go unchecked. Phantom and fake orders come from there, and a fake order can strand a real one. Permuting identical orders and a minter pairing its own orders and masters are listed as harmless. - Script Grouping states that each iCKB script validates the whole transaction whenever it runs, so its only gaps come from transactions where it does not run. - Deposit bounds apply only to receipted deposits. The pool can hold deposits of any size, and value no minted iCKB matches is effectively burned. - The aggregate-deposit spread path costs its user, not the reverse. - Small deposits return their occupied capacity to the withdrawer, so smallest-first is optimal within the bounds and below the soft cap. - Scenarios 4F and 6G, iCKB-locked requests, one order per master and the unreachable AttemptToChangeFulfilled and DuplicatedMaster now cite tests or code. - Foreign DAO wrapping is limited by the node's lock-size rule for deposits since block 10,000,000. - Four narrowed claims: double execution, the node (not the VM) enforcing occupied capacity, the xUDT witness tests, and the verifier's scope. Citations: - The dead links to nervosnetwork/ckb@6730f80, a commit that does not exist, now pin v0.210.0 with re-derived lines. The DAO lock-size rule is equality. - The deployed NervosDAO source is identified through ckb-system-scripts v0.5.4. - Whitepaper links point at master, since both repositories evolve, and one quote follows the whitepaper's current wording. - The stack's connector filter, which exists only on its unmerged branch, is described without a link. - The 180-epoch cycle cites RFC 0023. - The executed test count is 230. The report's Markdown tables are realigned. --- 20260501-ICKB-Audit-Report.md | 171 +++++++++++++++++++--------------- 1 file changed, 94 insertions(+), 77 deletions(-) diff --git a/20260501-ICKB-Audit-Report.md b/20260501-ICKB-Audit-Report.md index 33150b4..15158cd 100644 --- a/20260501-ICKB-Audit-Report.md +++ b/20260501-ICKB-Audit-Report.md @@ -4,16 +4,16 @@ - **Reviewed contracts commit:** [`454cfa9`](https://github.com/ickb/contracts/tree/454cfa966052a621c4e8b67001718c29ee8191a2). This is the last commit that changed `scripts/contracts/**` or `scripts/Cargo.toml`. - **Executable test evidence:** current `scripts/tests/**` suite in this repository state. - **Scope:** `iCKB Logic`, `Owned Owner`, `Limit Order`, and the shared `utils` crate. -- **Cross-references:** the [iCKB whitepaper](https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md) and Nervos L1 reference implementations. +- **Cross-references:** the [iCKB whitepaper](https://github.com/ickb/whitepaper/blob/master/README.md) and Nervos L1 reference implementations. - **Prior external audit:** [Scalebit (2024-09-10)](https://scalebit.xyz/reports/20240911-ICKB-Final-Audit-Report.pdf). That audit reported three issues: two informational and one minor. ## Executive Summary Under the current deployment assumptions, the review confirmed one live issue: the known `Limit Order` confusion attack. -- `iCKB Logic` has a provenance-blind path: receiptless DAO-shaped outputs can later be treated as deposits, and a separately funded aggregate-deposit path can realize the split-vs-aggregate soft-cap spread. +- `iCKB Logic` has a provenance-blind path: receiptless DAO-shaped outputs can later be treated as deposits, and a separately funded aggregate-deposit path is accepted, though it costs its user more than it returns. - Even so, the current `iCKB Logic` tests do not show theft, duplicated principal, or a standalone profit path beyond assets the caller already controls. -- `Limit Order` remains vulnerable to phantom-order continuation, real-order stranding through fake match-state cells, and master rebinding when cloned or otherwise indistinguishable orders are cross-wired at mint or during match. +- `Limit Order` remains vulnerable to phantom-order continuation and real-order stranding through fake match-state cells. Permuting otherwise indistinguishable real orders does not by itself strand either encoded master lineage. - `Owned Owner` preserves its pairing rules under the current whole-transaction-binding lock model; the remaining weak-lock claim-reassignment cases stay at the integration boundary. - All other candidate issues are blocked paths, generic CKB model constraints, or boundary cases relevant only to future integrations. @@ -21,9 +21,9 @@ Under the current deployment assumptions, the review confirmed one live issue: t One known live issue remains in scope. -| ID | Status | Component | Finding | -|---|---|---|---| -| LO-01 | Known | `Limit Order` | CKB [does not execute output locks at creation time](https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/types.rs#L716-L739), and [`limit_order` accepts swapped mint pairings](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L71-L79), so phantom and cross-wired order/master lineages can survive into later match or melt flows. | +| ID | Status | Component | Finding | +| ----- | ------ | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| LO-01 | Known | `Limit Order` | `limit_order` runs only when a transaction creates or spends a master cell or spends an order. A transaction that only creates order cells runs no check, because CKB [does not execute output locks](https://github.com/nervosnetwork/ckb/blob/2592ddf0502cd4adfe886db893cccc866db3c60f/script/src/types.rs#L642-L666). Anyone can therefore create phantom orders pointing at no master, or fake orders pointing at someone else's live master. A fake order can trick the owner into melting it with their master, which strands their real order. | ## Protocol Model and Assumptions @@ -55,15 +55,17 @@ The next four execution rules explain why later findings hold or fail. ### Script Grouping -Mixed transactions execute `iCKB Logic` twice, but both runs see the same global cells and apply the same checks, so the dual execution does not create a desync path. CKB groups scripts by both hash and role. From [`script/src/types.rs:179-180`](https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/types.rs#L179-L180): +Each iCKB script has two roles, a lock on one kind of cell and a type on another, and whenever it runs in either role it validates every cell of the transaction that uses it, not only its own group. The only states it cannot check are those created by transactions in which it does not run, because CKB does not execute output locks. The Limit Order confusion attack (LO-01) is the live instance; receiptless `iCKB Logic` deposits and lock-only Owned Owner look-alikes are the others. + +A transaction that both spends an `iCKB Logic`-locked input and carries a receipt input or output executes `iCKB Logic` twice, once per role (a phase 1 plus phase 2 mix without deposit inputs runs it once), but both runs see the same global cells and apply the same checks, so the dual execution does not create a desync path. CKB groups scripts by both hash and role. From [`script/src/types.rs:175-176`](https://github.com/nervosnetwork/ckb/blob/2592ddf0502cd4adfe886db893cccc866db3c60f/script/src/types.rs#L175-L176): > A cell can have a lock script and an optional type script. Even they reference the same script, lock script and type script will not be grouped together. -Lock groups and type groups are stored in separate `BTreeMap`s ([`types.rs:657-659`](https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/types.rs#L657-L659)). `iCKB Logic` uses the same `{code_hash, Data1, empty_args}` for both roles, so a mixed transaction produces one lock group for deposit cells and one type group for receipt cells. +Lock groups and type groups are stored in separate `BTreeMap`s ([`types.rs:583-585`](https://github.com/nervosnetwork/ckb/blob/2592ddf0502cd4adfe886db893cccc866db3c60f/script/src/types.rs#L583-L585)). `iCKB Logic` uses the same `{code_hash, Data1, empty_args}` for both roles, so a mixed transaction produces one lock group for deposit cells and one type group for receipt cells. Both groups still see the same global cell set (`Source::Input` and `Source::Output`, not group-local sources) and apply the same balance checks, so duplicate execution does not create a path where one run succeeds and the other fails. -Script group construction at [`types.rs:716-740`](https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/types.rs#L716-L740): lock groups are built from input locks only; type groups are built from both input and output types. +Script group construction at [`types.rs:642-666`](https://github.com/nervosnetwork/ckb/blob/2592ddf0502cd4adfe886db893cccc866db3c60f/script/src/types.rs#L642-L666): lock groups are built from input locks only; type groups are built from both input and output types. ### xUDT Owner Mode @@ -84,21 +86,21 @@ In both cases `iCKB Logic` co-executes, as a type script for receipts or a lock ### NervosDAO Interaction -The [deposit phase 1 section of the iCKB whitepaper](https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#deposit-phase-1) pins `NervosDAO` to the historical [`814eb82` `dao.c`](https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c). That version enforces the known [64-output-cell limit](https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L565-L591) with an [`output_withdrawing_mask` bitset](https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L445). iCKB inherits that as a platform constraint, but its own correctness does not depend on the limit. +The [deposit phase 1 section of the iCKB whitepaper](https://github.com/ickb/whitepaper/blob/master/README.md#deposit-phase-1) pins `NervosDAO` to the historical [`814eb82` `dao.c`](https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c). That version enforces the known [64-output-cell limit](https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L565-L591) with an [`output_withdrawing_mask` bitset](https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L445). iCKB inherits that as a platform constraint, but its own correctness does not depend on the limit. Key NervosDAO constraints confirmed against the [whitepaper-pinned `dao.c`](https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c): - Withdrawal request must be at the [same output index](https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L518-L523) as the consumed deposit. - Withdrawal request capacity must [equal the deposit capacity](https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L356-L365). -- Withdrawal request lock is [not checked by `validate_withdrawing_cell`](https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L339-L385), but current CKB nodes still apply the [DaoScriptSizeVerifier](https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/verification/src/transaction_verifier.rs#L811-L885), so the withdrawing lock must at least match the consumed deposit lock's serialized size. +- Withdrawal request lock is [not checked by `validate_withdrawing_cell`](https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L339-L385), but current CKB nodes still apply the [DaoScriptSizeVerifier](https://github.com/nervosnetwork/ckb/blob/2592ddf0502cd4adfe886db893cccc866db3c60f/verification/src/transaction_verifier.rs#L865-L982), so for deposits committed at or after block 10,000,000 the withdrawing lock must have exactly the consumed deposit lock's serialized size; older deposits are exempt. - AR is read from [`deposit_data.dao[8]`](https://github.com/nervosnetwork/ckb-system-scripts/blob/814eb82c44f560dbdad2be97eb85464062920237/c/dao.c#L282-L283), matching iCKB's [`AR_OFFSET = 160 + 8`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L51). ### Header Access -Header access explains why iCKB uses a two-phase deposit flow. From [`script/src/syscalls/load_header.rs`](https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/syscalls/load_header.rs): +Header access explains why iCKB uses a two-phase deposit flow. From [`script/src/syscalls/load_header.rs`](https://github.com/nervosnetwork/ckb/blob/2592ddf0502cd4adfe886db893cccc866db3c60f/script/src/syscalls/load_header.rs): -- For `Source::Input`: returns the header of the block containing the cell's creation transaction. The block hash must appear in [`header_deps`](https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/syscalls/load_header.rs#L62-L66). -- For `Source::Output`: always returns `INDEX_OUT_OF_BOUND` ([`load_header.rs:80`](https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/syscalls/load_header.rs#L80)). Deposits require two phases. +- For `Source::Input`: returns the header of the block containing the cell's creation transaction. The block hash must appear in [`header_deps`](https://github.com/nervosnetwork/ckb/blob/2592ddf0502cd4adfe886db893cccc866db3c60f/script/src/syscalls/load_header.rs#L61-L66). +- For `Source::Output`: always returns `INDEX_OUT_OF_BOUND` ([`load_header.rs:79`](https://github.com/nervosnetwork/ckb/blob/2592ddf0502cd4adfe886db893cccc866db3c60f/script/src/syscalls/load_header.rs#L79)). Deposits require two phases. Two shared boundaries matter in the later sections: authorization and accounting. @@ -106,7 +108,9 @@ Two shared boundaries matter in the later sections: authorization and accounting Several candidate issues turn on the boundary between lock-script authorization and type-script accounting. The [lock script](https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0022-transaction-structure/0022-transaction-structure.md#lock-script) / [type script](https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0022-transaction-structure/0022-transaction-structure.md#type-script) split means ownership is enforced by the user lock, while `ickb_logic` enforces value conservation. Its [balance equation](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L28-L34) and [cell classification](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L69-L81) never inspect who receives the output `iCKB` or the phase-1 DAO claim. -Under the [current whole-transaction-binding user-lock assumption](https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#ancillary-scripts), that division is acceptable because the user's signature commits to the full transaction. The deployment model used for this review assumes current user-facing iCKB flows use strong transaction-binding locks and does not treat delegated or adopted `OTX` flows as in-scope present-day integrations. +Under the [current whole-transaction-binding user-lock assumption](https://github.com/ickb/whitepaper/blob/master/README.md#ancillary-scripts), that division is acceptable because the user's signature commits to the full transaction. The deployment model used for this review assumes current user-facing iCKB flows use strong transaction-binding locks and does not treat delegated or adopted `OTX` flows as in-scope present-day integrations. + +This remains an integration assumption rather than a complete connector-lock inventory. The stack interface being prepared filters connectors by `SignerType.CKB`, not by independently proving each signer's output-binding semantics, and the public SDK also accepts caller-provided signers or scripts. Any integration using a weaker lock inherits the reassignment behavior demonstrated below. The weak-lock tests in this report do not replay a current wallet path. They model future or custom delegated, `OTX`, or other non-output-binding integrations, where recipient binding is an integration invariant rather than a guarantee provided by the iCKB contracts. @@ -115,9 +119,9 @@ Executed regressions show why that stays a boundary case rather than a current f - **Weak-lock behavior:** Recipient reassignment is possible in both `iCKB Logic` and `Owned Owner`. The [phase-2 weak-lock redirect test](scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs) and the [withdrawal weak-lock redirect test](scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs) demonstrate that weak-lock path. - **Signed phase-2 minting:** Once `sighash` binds the full transaction, phase-2 redirects stop working. The [phase-2 sighash binding test](scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs) and the [mixed phase-2 sighash binding test](scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs) show that binding. - **Signed withdrawals:** The same redirect pattern fails for withdrawal outputs once `sighash` binds the transaction. The [withdrawal sighash binding test](scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs) and the [mixed withdrawal sighash binding test](scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs) show the same result. -- **Witness binding:** The [input-group signing test](scripts/tests/src/tests/signing.rs) and the [full-witness signing test](scripts/tests/src/tests/signing.rs) confirm the witness-binding model used by the signed path. +- **Witness binding:** The [input-group, noncontiguous input-group, and full-witness signing tests](scripts/tests/src/tests/signing.rs) confirm the witness-binding model used by the signed path. -The same [ancillary scripts section](https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#ancillary-scripts) already warns that delegated and `OTX` ownership patterns have their own pitfalls. +The same [ancillary scripts section](https://github.com/ickb/whitepaper/blob/master/README.md#ancillary-scripts) already warns that delegated and `OTX` ownership patterns have their own pitfalls. ### Accounting Basis and Build Setting @@ -135,21 +139,24 @@ This section pins the reviewed sources and the checks behind the conclusions. ### Reference Repositories -| Repository | Commit | -|---|---| -| [ickb/contracts](https://github.com/ickb/contracts/tree/454cfa966052a621c4e8b67001718c29ee8191a2) | [`454cfa9`](https://github.com/ickb/contracts/tree/454cfa966052a621c4e8b67001718c29ee8191a2) | -| [ickb/whitepaper](https://github.com/ickb/whitepaper/tree/cdbabf653ba98eacea397f94f8c894f32a538d6c) | [`cdbabf6`](https://github.com/ickb/whitepaper/tree/cdbabf653ba98eacea397f94f8c894f32a538d6c) | -| [nervosnetwork/ckb](https://github.com/nervosnetwork/ckb/tree/6730f8023810d0888aa80c6a0d54cc2af918097d) | [`6730f80`](https://github.com/nervosnetwork/ckb/tree/6730f8023810d0888aa80c6a0d54cc2af918097d) | -| [nervosnetwork/ckb-system-scripts](https://github.com/nervosnetwork/ckb-system-scripts/tree/814eb82c44f560dbdad2be97eb85464062920237) | [`814eb82`](https://github.com/nervosnetwork/ckb-system-scripts/tree/814eb82c44f560dbdad2be97eb85464062920237) | +| Repository | Commit | +| --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | +| [ickb/contracts](https://github.com/ickb/contracts/tree/454cfa966052a621c4e8b67001718c29ee8191a2) | [`454cfa9`](https://github.com/ickb/contracts/tree/454cfa966052a621c4e8b67001718c29ee8191a2) | +| [ickb/whitepaper](https://github.com/ickb/whitepaper/tree/master) | [`master`](https://github.com/ickb/whitepaper/tree/master) | +| [nervosnetwork/ckb](https://github.com/nervosnetwork/ckb/tree/2592ddf0502cd4adfe886db893cccc866db3c60f) | [`2592ddf`](https://github.com/nervosnetwork/ckb/tree/2592ddf0502cd4adfe886db893cccc866db3c60f) | +| [nervosnetwork/ckb-system-scripts](https://github.com/nervosnetwork/ckb-system-scripts/tree/814eb82c44f560dbdad2be97eb85464062920237) | [`814eb82`](https://github.com/nervosnetwork/ckb-system-scripts/tree/814eb82c44f560dbdad2be97eb85464062920237) | | [nervosnetwork/ckb-production-scripts](https://github.com/nervosnetwork/ckb-production-scripts/tree/26b0b4f15bb6eeb268b70d7ae006e244b7c06649) | [`26b0b4f`](https://github.com/nervosnetwork/ckb-production-scripts/tree/26b0b4f15bb6eeb268b70d7ae006e244b7c06649) | -| [nervosnetwork/rfcs](https://github.com/nervosnetwork/rfcs/tree/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe) | [`4b502ff`](https://github.com/nervosnetwork/rfcs/tree/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe) | +| [nervosnetwork/rfcs](https://github.com/nervosnetwork/rfcs/tree/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe) | [`4b502ff`](https://github.com/nervosnetwork/rfcs/tree/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe) | + +CKB `v0.210.0` takes its genesis NervosDAO binary prebuilt from the `ckb-system-scripts` 0.5.4 crate; the repository's `v0.5.4` tag holds a `dao.c` byte-identical to the cited `814eb82`. The last code change to `dao.c` before that is [`f25c5ae`](https://github.com/nervosnetwork/ckb-system-scripts/blob/f25c5ae8824c4907ad94326a0113a03defab9bfc/c/dao.c); later commits change only comments. +The `nervosnetwork/ckb` pin is release `v0.210.0`. ### Methodology The review prioritized executable behavior over static plausibility and classified issues by their concrete impact. - Reviewed the deployed release binaries and the transaction semantics they actually enforce, not just the latest source-level intent. -- Reproduced script behavior locally with `ckb-testtool`, using executable transaction tests rather than relying on inspection alone. +- Reproduced deployed-script behavior locally with `ckb-testtool`. Its `Context::verify_tx` checks output/data cardinality and executes scripts, but does not run the full node non-contextual or contextual transaction verifiers. The suite therefore holds every input and output to its occupied capacity before verifying, and every accepted DAO withdrawal to the node's lock-size rule, so no fixture builds a cell or withdrawal the node would reject; other consensus-level conclusions are separately source-backed. - Reused and extended the existing test suite, including replayed transaction shapes from observed protocol flows. - Computed NervosDAO accounting with the exact DAO withdrawal math before classifying any claim-path discrepancy as a finding. - Separated findings that affect the current deployment from weak-lock assumptions, operator mistakes, or broader integration-only scenarios. @@ -164,9 +171,11 @@ A [module wiring overview](scripts/tests/src/tests.rs) plus the [test layout not - **Scenario suite roots:** [ickb_logic](scripts/tests/src/tests/ickb_logic.rs), [owned_owner](scripts/tests/src/tests/owned_owner.rs), [limit_order](scripts/tests/src/tests/limit_order.rs), and [replay](scripts/tests/src/tests/replay.rs), each wiring topic-focused files under the matching subdirectory. - **Helper-focused unit coverage:** [helpers](scripts/tests/src/tests/helpers.rs), which checks the shared encoders and witness/data builders used by the larger suites. -A fresh `cargo test -p tests` run passed `214` tests with no failures. Those tests cover deployment-hash sanity checks, helper encodings, core flows, blocked-path regressions, and replayed transaction shapes across `iCKB Logic`, `Owned Owner`, and `Limit Order`. +A fresh `cargo test -p tests` run passed `230` tests with no failures. Those tests cover deployment-hash sanity checks, helper encodings, core flows, blocked-path regressions, and replayed transaction shapes across `iCKB Logic`, `Owned Owner`, and `Limit Order`. + +The type-role scan regression verifies a phase-2 conversion with 512 unrelated outputs within the suite's `10,000,000`-cycle ceiling. Lock-role transactions also execute NervosDAO, whose separately tested 64-output boundary caps their outputs. -The strong-lock regressions in `ickb_logic`, `owned_owner`, and `signing` replay `secp256k1_blake160_sighash_all` as the representative whole-transaction-binding lock. This repo does not include a `QRL` fixture or harness, so conclusions for other strong-lock deployments rely on the same binding property and the stated deployment assumptions rather than a separate in-repo replay. +Within this script-verifier scope, the strong-lock regressions in `ickb_logic`, `owned_owner`, and `signing` use `secp256k1_blake160_sighash_all` as the representative whole-transaction-binding lock. This repo does not include a `QRL` fixture or harness, so conclusions for other strong-lock deployments rely on the same binding property and the stated deployment assumptions rather than a separate in-repo replay. --- @@ -194,30 +203,33 @@ if c2u.ckb_mul * u2c.udt_mul < c2u.udt_mul * u2c.ckb_mul **Minimum match enforcement** ([`entry.rs:108-129`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L108-L129)): prevents dust-level partial matches. -**Strict data length on execution** ([`entry.rs:166`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L166)): when `limit_order` executes, order data must be exactly `UDT_SIZE + ORDER_SIZE` bytes, so trailing data fails validation. +**Strict data length on execution** ([`entry.rs:166`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L166)): when `limit_order` executes, order data must be exactly `UDT_SIZE + ORDER_SIZE` (89) bytes, so trailing data fails validation. ### Assessment -Executed tests confirm several live confusion manifestations under the current deployment assumptions, and separate tests bound the rebinding path. +Executed tests confirm several live confusion manifestations under the current deployment assumptions and distinguish them from harmless pairings and permutations of real orders. -| ID | Status | Finding | -|---|---|---| -| LO-01 | Known | CKB [does not execute output locks at creation time](https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/types.rs#L716-L739), and [`limit_order`'s mint branch](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L71-L79) accepts swapped mint pairings, so mint-time output creation can seed phantom or cross-wired order/master lineages that later pass match or melt validation. | +| ID | Status | Finding | +| ----- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| LO-01 | Known | `limit_order` runs only when a transaction creates or spends a master cell or spends an order. A transaction that only creates order cells runs no check, because CKB [does not execute output locks](https://github.com/nervosnetwork/ckb/blob/2592ddf0502cd4adfe886db893cccc866db3c60f/script/src/types.rs#L642-L666). Anyone can therefore create phantom orders pointing at no master, or fake orders pointing at someone else's live master. A fake order can trick the owner into melting it with their master, which strands their real order. | **Confirmed live manifestations:** - Phantom orders can be created without master validation: the [phantom mint creation test](scripts/tests/src/tests/limit_order/phantom_lineage.rs). - That phantom lineage can then enter and keep advancing through fake match state without a real master: the [phantom mint continuation test](scripts/tests/src/tests/limit_order/phantom_lineage.rs) and the [fake match lineage continuation test](scripts/tests/src/tests/limit_order/fake_match_lineage.rs). -- A fake match-shaped order can melt against a real master and strand the real order: the [real-order stranding test](scripts/tests/src/tests/limit_order/fake_match_lineage.rs). -- Cross-wired or cloned orders can rebind masters at mint or during match: the [mint crosswire test](scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs) and the [cloned-order master-swap test](scripts/tests/src/tests/limit_order/crosswire_live_match.rs). -- The cloned-order continuation is reproduced with `secp256k1_blake160_sighash_all`-protected masters, so the live path is not a weak-lock-only artifact: the [cloned-order master-swap test](scripts/tests/src/tests/limit_order/crosswire_live_match.rs). +- A foreign-token fake order with unrelated pricing and order information can melt against a real master and strand the real order: the [real-order stranding test](scripts/tests/src/tests/limit_order/fake_match_lineage.rs). -**Bounding evidence:** separate tests show that the rebinding path is narrower than arbitrary master rewriting: +**Harmless pairings and permutations:** + +- Permuting two indistinguishable matched orders does not itself strand either master: both continuations remain redeemable by the master encoded in their data, including with `secp256k1_blake160_sighash_all`-protected masters, as shown by the [cloned-order permutation test](scripts/tests/src/tests/limit_order/crosswire_live_match.rs). +- A mint can pair any of its order outputs with any of its master outputs, but the script enforces one order per master ([mint pairing rule test](scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs)) and the minter creates and controls all of them, so a crossed pairing is the minter's own choice and strands no one: the [mint pairing test](scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs). + +**Bounding evidence:** separate tests show that real order state cannot be rewritten arbitrarily: - Differing mint capacities and differing match progress both block cross-wiring: the [distinct mint-capacity crosswire block test](scripts/tests/src/tests/limit_order/crosswire_blockers.rs) and the [distinct match-progress crosswire block test](scripts/tests/src/tests/limit_order/crosswire_blockers.rs). - Even real orders fail to cross-wire arbitrarily, whether the checked info matches or differs: the [same-info real-order crosswire block test](scripts/tests/src/tests/limit_order/crosswire_blockers.rs) and the [different-info mainnet crosswire block test](scripts/tests/src/tests/limit_order/crosswire_blockers.rs). -The UDT -> CKB zero-UDT fulfilled-order shape still fails at the outer `InvalidMatch` check rather than surfacing a dedicated fulfilled-order guard. +A terminal CKB -> UDT fill passes script verification at exact occupied capacity. Continuing a fulfilled single-direction order fails at the outer `InvalidMatch` check (a dual-ratio order may still move in its other direction, as designed), while a lock-only order without a UDT type returns the typed `MissingUdtType` error. Two defensive errors cannot be reached by consensus-valid cells: `AttemptToChangeFulfilled`, because on the CKB -> UDT side a continuation shares the order's lock, type and data length, so it cannot hold less CKB than a fulfilled order, and on the UDT -> CKB side a fulfilled order has no UDT left to decrease (the [vector replay](scripts/tests/src/tests/protocol_vectors.rs) skips, by name, the two vectors that assume such a shrinking CKB -> UDT cell); and [`DuplicatedMaster`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L42-L45), because an input master is keyed by its out point and an output master by its output index, and no two cells share either. --- @@ -246,17 +258,17 @@ This equation is the core accounting invariant across all flows: [`celltype.rs:60-82`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L60-L82) classifies every cell in the transaction by examining lock and type script hashes, plus the DAO data shape when the DAO hash is present: -| Lock | Type | Classification | Line | -|---|---|---|---| -| iCKB Logic | DAO deposit (8 zero bytes) | `Deposit` | [L69](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L69) | -| iCKB Logic | anything else | `ScriptMisuse` (error) | [L72](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L72) | -| other | iCKB Logic | `Receipt` | [L75](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L75) | -| other | iCKB xUDT | `Udt` | [L78](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L78) | -| DAO deposit (8 zero bytes) as lock | any | `ScriptMisuse` (error) | [L62](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L62) | -| iCKB xUDT as lock | any | `ScriptMisuse` (error) | [L63](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L63) | -| other | other | `Unknown` (ignored) | [L81](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L81) | +| Lock | Type | Classification | Line | +| ---------------------------------- | -------------------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| iCKB Logic | DAO deposit (8 zero bytes) | `Deposit` | [L69](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L69) | +| iCKB Logic | anything else | `ScriptMisuse` (error) | [L72](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L72) | +| other | iCKB Logic | `Receipt` | [L75](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L75) | +| other | iCKB xUDT | `Udt` | [L78](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L78) | +| DAO deposit (8 zero bytes) as lock | any | `ScriptMisuse` (error) | [L62](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L62) | +| iCKB xUDT as lock | any | `ScriptMisuse` (error) | [L63](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L63) | +| other | other | `Unknown` (ignored) | [L81](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L81) | -`ScriptType::None` is only synthesized for [missing type scripts](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L48-L50); [`script_type()`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L95-L112) never returns `None` for locks, so the [`(ScriptType::None, _)`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L64) arm is unreachable. NervosDAO withdrawal requests, which have non-zero data, correctly classify as `Unknown` via [`is_deposit_data`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/dao.rs#L17-L22). +`ScriptType::None` is only synthesized for [missing type scripts](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L48-L50); [`script_type()`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L95-L112) never returns `None` for locks, so the [`(ScriptType::None, _)`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L64) arm is unreachable. NervosDAO withdrawal requests, which have non-zero data, classify as `Unknown` under any other lock; locked by `iCKB Logic` they fail with `ScriptMisuse` ([iCKB-locked request test](scripts/tests/src/tests/ickb_logic/creation_blind_spots.rs)). Both follow from [`is_deposit_data`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/dao.rs#L17-L22). ### Deposit-Receipt Accounting (`check_output`) @@ -268,7 +280,7 @@ This equation is the core accounting invariant across all flows: It also validates: -- Deposits: `1000 CKB <= unoccupied_capacity <= 1M CKB` ([`entry.rs:101-106`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L101-L106), bounds at [`constants.rs:5-6`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/constants.rs#L5-L6)) +- Deposits created with receipts: `1000 CKB <= unoccupied_capacity <= 1M CKB` ([`entry.rs:101-106`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L101-L106), bounds at [`constants.rs:5-6`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/constants.rs#L5-L6)) - Receipts: `deposit_quantity > 0` ([`entry.rs:114-116`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L114-L116)) - UDT: `amount <= u64::MAX` ([`entry.rs:123-125`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L123-L125)) @@ -284,7 +296,7 @@ if ickb_amount > ICKB_SOFT_CAP_PER_DEPOSIT { ``` - Division by zero: impossible (the [RFC 0023 accumulated-rate rule](https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0023-dao-deposit-withdraw/0023-dao-deposit-withdraw.md#calculation) sets `AR_0 = 10 ^ 16` and `AR_i = AR_{i-1} + floor(AR_{i-1} * s_i / C_{i-1})`, so `AR_m` is non-zero). -- Overflow: `u64 * u128` fits in u128 (~1.8e19 * 1e16 = ~1.8e35 < 3.4e38). +- Overflow: `u64 * u128` fits in u128 (~1.8e19 \* 1e16 = ~1.8e35 < 3.4e38). - Precision: integer division loses at most 1 shannon per operation. - Fee/discount symmetry: the same function is used for both input receipts (fee, [`entry.rs:58-59`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L58-L59)) and input deposits (discount, [`entry.rs:52`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L52)). The protocol breaks even: minted amount = burned amount. @@ -302,12 +314,12 @@ Output types don't need explicit checking because they trigger execution and sel `iCKB Logic` has one state-admission blind spot plus several boundary points: - **Provenance blind spot:** Receiptless DAO-shaped outputs can be admitted at output-lock creation time because CKB does not execute output locks, and later treated as pool deposits because [`cell_type_iter`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L68-L75) classifies any `ickb_logic`-locked, DAO-typed, deposit-data input as `Deposit` with no receipt-provenance check. The [receiptless deposit-admission test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) confirms that admission-plus-later-classification path. -- **Accepted spread path is still self-funded:** When a separately provided split receipt is paired against a self-funded receiptless aggregate deposit, the contract accepts minting only the soft-cap valuation delta rather than the aggregate principal. The [delta-only spread test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) and the [oversized spread test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) show the accepted spread, while the [deposit-alone spread block test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) blocks the deposit-alone variant. +- **Accepted spread path is still self-funded:** When a separately provided split receipt is paired against a self-funded receiptless aggregate deposit, the contract accepts minting only the soft-cap valuation delta rather than the aggregate principal. That leaves the user worse off than redeeming the receipt normally: in the tested case, a receipt for two 100k CKB deposits plus a separately funded 200k CKB aggregate yield 10k iCKB and the aggregate's CKB back, instead of the receipt's 200k iCKB. The split deposits stay ordinary pool deposits that any iCKB holder can withdraw at their value, but in aggregate the pool now holds 190k iCKB of value that no minted iCKB matches, so that value is effectively burned rather than transferred to anyone. The [delta-only spread test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) and the [oversized spread test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) show the accepted spread, while the [deposit-alone spread block test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) blocks the deposit-alone variant. - **Ordinary mixed flows still apply the soft cap per receipt:** The [mixed phase1-phase2 soft-cap test](scripts/tests/src/tests/ickb_logic/soft_cap.rs) shows that adding fresh phase-1 deposits in the same transaction does not turn this into a general aggregate soft-cap bypass. -- **Executed path limit:** The [narrowing comment in the phase-2 claim test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) and the [self-funded principal claim test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) make the current limit explicit: the self-funded aggregate principal remains claimable in DAO phase 2, so the executed path does not show third-party principal theft or duplicated recovery. +- **Executed path limit:** The [continuous split-deposit receipt, receiptless creation, delta-only spread, and DAO-claim trajectory](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) preserves each verified output's transaction hash and index. The original split deposits remain separate while the self-funded aggregate principal remains claimable in DAO phase 2, so the executed path does not show third-party principal theft or duplicated recovery. - **Prefix behavior:** Trailing bytes in receipt and `xUDT` data reflect prefix-based parsing, while truncated encodings are still rejected. The [receipt trailing-bytes tests](scripts/tests/src/tests/ickb_logic/receipt_encoding.rs), [truncated receipt tests](scripts/tests/src/tests/ickb_logic/receipt_encoding.rs), and [trailing/short `xUDT` output-data tests](scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs) cover that behavior. -- **Weak-lock boundary:** Recipient-redirection scenarios remain boundary cases and do not apply under the current [whole-transaction-binding user-lock assumption](https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#ancillary-scripts). -- **Rounding:** Whole-CKB rounding claims remain false leads. The [rounding mint test](scripts/tests/src/tests/ickb_logic/economic_precision.rs) and the [rounding withdrawal test](scripts/tests/src/tests/ickb_logic/economic_precision.rs) fail unless exact shannon precision is used. +- **Weak-lock boundary:** Recipient-redirection scenarios remain boundary cases and do not apply under the current [whole-transaction-binding user-lock assumption](https://github.com/ickb/whitepaper/blob/master/README.md#ancillary-scripts). +- **Rounding and operation order:** Whole-CKB rounding claims remain false leads. The [rounding mint, withdrawal, and non-genesis-AR soft-cap boundary tests](scripts/tests/src/tests/ickb_logic/economic_precision.rs) require exact shannon precision and confirm that integer AR normalization precedes the per-deposit haircut. On current executable evidence, that provenance-blind path is real, but it still falls short of a confirmed theft or standalone profit finding. @@ -337,9 +349,10 @@ For inputs and outputs separately, the script enforces the same pairing rules: `Owned Owner` leaves four boundary points. The live claim-rotation path stays blocked in the currently modeled flows: - **Live claim rotation remains blocked:** Attempts to roll a live claim into fresh `Owned Owner` pairs or to crosswire a fully DAO-constrained batch are rejected before a new live pairing survives. The [fresh-pair rotation block test](scripts/tests/src/tests/owned_owner/live_claim_rotation.rs), [new-pair rotation block test](scripts/tests/src/tests/owned_owner/live_claim_rotation.rs), and the [DAO index-rule crosswire block test](scripts/tests/src/tests/owned_owner/dao_crosswiring.rs) show that block. -- **Crosswired later-claim ownership still depends on weak phase-1 authorization:** When phase-1 owner outputs use weak or otherwise non-output-binding locks, later DAO claims can be reassigned across mixed foreign-plus-iCKB batches or fully iCKB batches. The [mixed foreign-plus-iCKB weak-lock crosswire test](scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs), [two-way weak-lock crosswire claim test](scripts/tests/src/tests/owned_owner/dao_crosswiring.rs), and [three-way weak-lock crosswire claim test](scripts/tests/src/tests/owned_owner/dao_crosswiring.rs) show that boundary case. Under the current strong-lock deployment assumption, this is not a present finding. -- **Foreign DAO withdrawal wrapping is allowed:** The [foreign DAO wrapping test](scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs) shows that any DAO withdrawal request can be wrapped and later claimed, because the script checks only DAO type plus withdrawal-shaped data on the owned cell. -- **Creator-side dead states are narrower than arbitrary malformed pairs:** When `Owned Owner` actually executes as a type script, it rejects orphan and count-mismatch shapes, as shown by the [orphan-owner rejection test](scripts/tests/src/tests/owned_owner/pair_formation.rs) and the [two-owner mismatch test](scripts/tests/src/tests/owned_owner/pair_formation.rs). But creation still accepts pairs whose owner lock never validated, as shown by the [unspendable foreign-owner-lock test](scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs) and the [limit-order owner-lock stranding test](scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs). It also allows lock-only `Owned Owner` look-alikes that later fail on spend, as shown by the [lock-only non-DAO look-alike test](scripts/tests/src/tests/owned_owner/script_misuse.rs) and the [lock-only DAO-deposit look-alike test](scripts/tests/src/tests/owned_owner/script_misuse.rs). +- **Signed lifecycle:** A [secp-protected sparse pair](scripts/tests/src/tests/owned_owner/positive_distance_claims.rs) completes phase 1 with a noncontiguous signed input group and then completes the signed owner spend in DAO phase 2. This establishes signature and pairing behavior under script verification; `ckb-testtool` does not establish `since` maturity. +- **Crosswired later-claim ownership still depends on weak phase-1 authorization:** When phase-1 owner outputs use weak or otherwise non-output-binding locks, later DAO claims can be reassigned across mixed foreign-plus-iCKB batches (with foreign deposits limited as below) or fully iCKB batches. The [mixed foreign-plus-iCKB weak-lock crosswire test](scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs), [two-way weak-lock crosswire claim test](scripts/tests/src/tests/owned_owner/dao_crosswiring.rs), and [three-way weak-lock crosswire claim test](scripts/tests/src/tests/owned_owner/dao_crosswiring.rs) show that boundary case. Under the current strong-lock deployment assumption, this is not a present finding. +- **Foreign DAO withdrawal wrapping is allowed:** The [foreign DAO wrapping test](scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs) shows that a DAO withdrawal request can be wrapped and later claimed, because the script checks only DAO type plus withdrawal-shaped data on the owned cell. For deposits committed at or after block 10,000,000, the node's `DaoScriptSizeVerifier` keeps a request's lock the same serialized size as its deposit's, so among those this applies only to deposits whose lock matches Owned Owner's size (empty args), not to deposits under ordinary user locks; older deposits can be wrapped regardless. +- **Creator-side dead states are narrower than arbitrary malformed pairs:** When `Owned Owner` actually executes as a type script, it rejects orphan and count-mismatch shapes, as shown by the [orphan-owner rejection test](scripts/tests/src/tests/owned_owner/pair_formation.rs) and the [two-owner mismatch test](scripts/tests/src/tests/owned_owner/pair_formation.rs), with the reverse shape, two owned requests for one owner, covered by the [two-owned mismatch test](scripts/tests/src/tests/owned_owner/pair_formation.rs). But creation still accepts pairs whose owner lock never validated, as shown by the [unspendable foreign-owner-lock test](scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs) and the [limit-order owner-lock stranding test](scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs). It also allows lock-only `Owned Owner` look-alikes that later fail on spend, as shown by the [lock-only non-DAO look-alike test](scripts/tests/src/tests/owned_owner/script_misuse.rs) and the [lock-only DAO-deposit look-alike test](scripts/tests/src/tests/owned_owner/script_misuse.rs). --- @@ -349,7 +362,7 @@ For inputs and outputs separately, the script enforces the same pairing rules: Witness malleability is a documented property, not a new finding. All three scripts use the script-as-lock (unsigned) plus script-as-type (controller) pattern, and none of them reads witnesses. -The [whitepaper states the consequence directly](https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#unsigned-lock-witnesses-malleability): "if a script in a transaction needs to store data in the witness and this data can be tampered without the transaction becoming invalid, then this transaction must not employ the scripts presented in the current whitepaper." +The [whitepaper states the consequence directly](https://github.com/ickb/whitepaper/blob/master/README.md#unsigned-lock-witnesses-malleability): "if a script in a transaction needs to store data in the witness and this data can be tampered with without making the transaction invalid, then this transaction must not employ the scripts presented in the current whitepaper." ### Non-Upgradable Deployment @@ -389,7 +402,7 @@ These scenarios test whether iCKB can be created without the corresponding depos **Trace:** under iCKB's deployed [`[ickb_logic_hash, XUDT_ARGS_FLAGS]`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/celltype.rs#L116-L126) with [`XUDT_ARGS_FLAGS = 0x80000000`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/constants.rs#L1-L2), `xUDT` owner mode has two live iCKB routes: a matching input type for receipts and a matching input lock for deposits ([RFC 0052](https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0052-extensible-udt/0052-extensible-udt.md#owner-mode-update), [`xudt_rce.c`](https://github.com/nervosnetwork/ckb-production-scripts/blob/26b0b4f15bb6eeb268b70d7ae006e244b7c06649/c/xudt_rce.c#L383-L458)). -The only other upstream owner-mode route is the witness [`owner_script` fallback](https://github.com/nervosnetwork/ckb-production-scripts/blob/26b0b4f15bb6eeb268b70d7ae006e244b7c06649/c/xudt_rce.c#L645-L649), but that path looks up the exported [`validate` symbol](https://github.com/nervosnetwork/ckb-production-scripts/blob/26b0b4f15bb6eeb268b70d7ae006e244b7c06649/c/xudt_rce.c#L36-L36) via [`ckb_dlsym`](https://github.com/nervosnetwork/ckb-production-scripts/blob/26b0b4f15bb6eeb268b70d7ae006e244b7c06649/c/xudt_rce.c#L91-L113). [`iCKB Logic`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/main.rs#L23-L35) is built as a CKB entrypoint instead of an xUDT extension. In the two live cases, `iCKB Logic` co-executes, so the balance equation still applies. The [output-witness owner-script fallback test](scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs) and the [input-witness owner-script fallback test](scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs) reproduce that attempted route and still fail under `xUDT` amount checks. +The only other upstream owner-mode route is the witness [`owner_script` fallback](https://github.com/nervosnetwork/ckb-production-scripts/blob/26b0b4f15bb6eeb268b70d7ae006e244b7c06649/c/xudt_rce.c#L645-L649), but that path looks up the exported [`validate` symbol](https://github.com/nervosnetwork/ckb-production-scripts/blob/26b0b4f15bb6eeb268b70d7ae006e244b7c06649/c/xudt_rce.c#L36-L36) via [`ckb_dlsym`](https://github.com/nervosnetwork/ckb-production-scripts/blob/26b0b4f15bb6eeb268b70d7ae006e244b7c06649/c/xudt_rce.c#L91-L113). [`iCKB Logic`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/main.rs#L23-L35) is built as a CKB entrypoint instead of an xUDT extension. In the two live cases, `iCKB Logic` co-executes, so the balance equation still applies. The [output-witness owner-script fallback test](scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs) and the [input-witness owner-script fallback test](scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs) confirm the outcome, failure under `xUDT` amount checks; `xudt_rce.c` discards the witness route's own result, so they cannot show why that route failed, which the source argument above establishes. **Result:** **Blocked.** @@ -405,7 +418,7 @@ The only other upstream owner-mode route is the witness [`owner_script` fallback **Attack:** make a receipt appear to be from an older block (lower AR = higher `iCKB` value). -**Trace:** [`extract_accumulated_rate`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L54-L61) calls `load_header`, which reads the block hash from [`CellMeta.transaction_info.block_hash`](https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/syscalls/load_header.rs#L57-L61) and only succeeds when that block is also present in [`header_deps`](https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/syscalls/load_header.rs#L62-L66). The transaction creator cannot override that linkage. +**Trace:** [`extract_accumulated_rate`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L54-L61) calls `load_header`, which reads the block hash from [`CellMeta.transaction_info.block_hash`](https://github.com/nervosnetwork/ckb/blob/2592ddf0502cd4adfe886db893cccc866db3c60f/script/src/syscalls/load_header.rs#L56-L60) and only succeeds when that block is also present in [`header_deps`](https://github.com/nervosnetwork/ckb/blob/2592ddf0502cd4adfe886db893cccc866db3c60f/script/src/syscalls/load_header.rs#L61-L66). The transaction creator cannot override that linkage. **Result:** **Blocked.** @@ -466,17 +479,19 @@ Net profit = 0. **Attack:** scan the pool for deposits that require the least nominal `iCKB` to withdraw and then withdraw those deposits first. -**Trace:** [`deposit_to_ickb`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L76) computes `amount * AR_0 / AR_m`. RFC 0023's [maximum-withdrawable-capacity formula](https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0023-dao-deposit-withdraw/0023-dao-deposit-withdraw.md#calculation) scales the later DAO claim by `AR_n / AR_m`, and the whitepaper's [exchange-rate calculation](https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#ickbckb-exchange-rate-calculation) values the same deposit from block `m` at `100000 CKB * 10 ^ 16 / AR_m` `iCKB`, excluding occupied capacity. +**Trace:** [`deposit_to_ickb`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L76) computes `amount * AR_0 / AR_m`. RFC 0023's [maximum-withdrawable-capacity formula](https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0023-dao-deposit-withdraw/0023-dao-deposit-withdraw.md#calculation) scales the later DAO claim by `AR_n / AR_m`, and the whitepaper's [exchange-rate calculation](https://github.com/ickb/whitepaper/blob/master/README.md#ickbckb-exchange-rate-calculation) values the same deposit from block `m` at `100000 CKB * 10 ^ 16 / AR_m` `iCKB`, excluding occupied capacity. Deposits with higher `AR_m` require less nominal `iCKB` because the formula values them lower in `iCKB`, not because the pool applies a discount. -**Result:** **No mispricing.** Each deposit is priced by the same formula, up to integer-division rounding. +The formula values only unoccupied capacity, while the phase 2 claim also returns the deposit's occupied capacity (82 CKB for a standard deposit cell). Per `iCKB` burned, a withdrawer therefore receives about `82 CKB / unoccupied` more from a small deposit: about 8.2% at 1,000 CKB, against 0.082% at 100k CKB, so among deposits within the bounds and below the soft cap, withdrawing the smallest first is optimal. Oversized deposits also pay more per `iCKB`, through the soft-cap discount (about 9.9% at 1M CKB). This is the whitepaper's intended [penalty on small deposits](https://github.com/ickb/whitepaper/blob/master/README.md#deposit-phase-1), paid by the depositor and collected by the withdrawer ([small-versus-standard withdrawal test](scripts/tests/src/tests/ickb_logic/economic_precision.rs)). + +**Result:** **No mispricing.** Each deposit's unoccupied capacity is priced by the same formula, up to integer-division rounding; the unaccounted occupied capacity is an intended incentive, not an error. **3C. Integer rounding exploitation** **Attack:** create many small deposits to accumulate rounding errors. -**Trace:** the [rounding mint test](scripts/tests/src/tests/ickb_logic/economic_precision.rs) and the [rounding withdrawal test](scripts/tests/src/tests/ickb_logic/economic_precision.rs) show that the reported whole-CKB or rounded claims fail with `AmountMismatch` unless the exact shannon-precision value is used. The supposed extraction path does not validate on chain. +**Trace:** the [rounding mint, withdrawal, and non-genesis-AR soft-cap boundary tests](scripts/tests/src/tests/ickb_logic/economic_precision.rs) show that the reported whole-CKB or rounded claims fail with `AmountMismatch` unless the exact shannon-precision value and operation order are used. The supposed extraction path fails deployed-script verification. **Result:** **Blocked by exact shannon-precision accounting.** @@ -504,7 +519,7 @@ These cases test whether malformed cells can enter the accounting flow with misl **4D. NervosDAO withdrawal request classified as deposit** -**Trace:** [`is_deposit_data`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/dao.rs#L17-L22) checks for exactly 8 zero bytes. Withdrawal requests have non-zero data that stores the block number, so they fall through to `ScriptType::Unknown` and then `CellType::Unknown`. +**Trace:** [`is_deposit_data`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/dao.rs#L17-L22) checks for exactly 8 zero bytes. Withdrawal requests have non-zero data that stores the block number, so they fall through to `ScriptType::Unknown`: under any other lock they become `CellType::Unknown`, and under an `iCKB Logic` lock the script rejects them with `ScriptMisuse` ([iCKB-locked request test](scripts/tests/src/tests/ickb_logic/creation_blind_spots.rs)). **Result:** **Blocked.** @@ -512,7 +527,7 @@ These cases test whether malformed cells can enter the accounting flow with misl **Attack:** inflate [`extract_unused_capacity`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L47-L49) by manipulating cell fields. -**Trace:** CKB requires [occupied capacity to fit within cell capacity](https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0022-transaction-structure/0022-transaction-structure.md#cell-data), and [`extract_unused_capacity`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L47-L49) subtracts that VM-computed occupied capacity from the actual cell capacity. For the standard iCKB deposit shape, the whitepaper's [exchange-rate calculation](https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#ickbckb-exchange-rate-calculation) uses `c_o = 82 CKB`. That occupied capacity is fixed by the deposit structure, not chosen independently by the attacker. +**Trace:** CKB requires [occupied capacity to fit within cell capacity](https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0022-transaction-structure/0022-transaction-structure.md#cell-data), and [`extract_unused_capacity`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L47-L49) subtracts the occupied capacity that the host syscall reports from the actual cell capacity. For the standard iCKB deposit shape, the whitepaper's [exchange-rate calculation](https://github.com/ickb/whitepaper/blob/master/README.md#ickbckb-exchange-rate-calculation) uses `c_o = 82 CKB`. That occupied capacity is fixed by the deposit structure, not chosen independently by the attacker. **Result:** **Blocked.** @@ -526,11 +541,11 @@ These cases test whether malformed cells can enter the accounting flow with misl 2. **By contrast, the broader provenance-blind path is a different claim.** The [receiptless deposit-admission test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) shows that `ickb_logic` later accepts a receiptless DAO-shaped output as a structurally valid deposit input once it exists. -The [delta-only spread test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) and the [oversized spread test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) show that the contract accepts a self-funded soft-cap spread, while the [deposit-alone spread block test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) blocks the deposit-only variant. +The [delta-only spread test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) and the [oversized spread test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) show that the contract accepts a self-funded soft-cap spread, which costs its user the consumed receipt's value minus the spread, while the [deposit-alone spread block test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) blocks the deposit-only variant. -The [narrowing comment in the phase-2 claim test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) and the [self-funded principal claim test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) make the limit explicit: the executed path still does not prove receipt-backed-principal theft or duplicated recovery. +The [continuous verified-output trajectory](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs) from split-deposit receipt creation through receiptless creation, spread realization, and DAO phase 2 makes the limit explicit: the executed path still does not prove receipt-backed-principal theft or duplicated recovery. -So the specific "same output index" reset is blocked by NervosDAO. The receiptless aggregate-deposit variant stays a self-funded provenance-blind edge case rather than a confirmed double-claim exploit. +So the specific "same output index" reset is blocked by NervosDAO: the [same-index reset test](scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs) withdraws and re-deposits in one transaction, which verifies with the request at the deposit's index and fails with error `-20` when the fresh deposit and the request swap indices. The receiptless aggregate-deposit variant stays a self-funded provenance-blind edge case rather than a confirmed double-claim exploit. **Result:** **Blocked for the same-index reset described here.** The receiptless aggregate-deposit path exists, but the current tests still stop short of proving receipt-backed-principal theft or duplicated recovery. @@ -546,15 +561,15 @@ These scenarios check whether behavior that is safe in isolation breaks once mul The [iCKB malformed witness test](scripts/tests/src/tests/ickb_logic/dao_phase2_batching.rs) and the [Owned Owner malformed witness test](scripts/tests/src/tests/owned_owner/melt_pairing_and_witness.rs) reproduce that malformed header-index witness failure path in `iCKB Logic` and `Owned Owner` withdrawal flows. -The [whitepaper's unsigned-lock-witnesses section](https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#unsigned-lock-witnesses-malleability) already documents that general malleability risk and warns against combining these scripts with witness-dependent logic. +The [whitepaper's unsigned-lock-witnesses section](https://github.com/ickb/whitepaper/blob/master/README.md#unsigned-lock-witnesses-malleability) already documents that general malleability risk and warns against combining these scripts with witness-dependent logic. -**Result:** **Can cause transaction failure (griefing), cannot cause fund loss.** This is a liveness issue, not a safety issue. [Documented in the whitepaper](https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#unsigned-lock-witnesses-malleability). +**Result:** **Can cause transaction failure (griefing), cannot cause fund loss.** This is a liveness issue, not a safety issue. [Documented in the whitepaper](https://github.com/ickb/whitepaper/blob/master/README.md#unsigned-lock-witnesses-malleability). **5B. Separate lock/type group execution desync** **Attack:** exploit dual execution in the hope that one run passes while the other fails. -**Trace:** CKB requires ALL script groups to pass ([the verifier loop](https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/verify.rs#L197-L213) returns an error if any `verify_script_group(...)` call fails). Both lock and type executions see identical cells at absolute indices and perform the same balance checks. If either fails, the transaction is rejected. +**Trace:** CKB requires ALL script groups to pass ([the verifier loop](https://github.com/nervosnetwork/ckb/blob/2592ddf0502cd4adfe886db893cccc866db3c60f/script/src/verify.rs#L180-L197) returns an error if any `verify_script_group(...)` call fails). Both lock and type executions see identical cells at absolute indices and perform the same balance checks. If either fails, the transaction is rejected. **Result:** **Blocked.** @@ -580,9 +595,9 @@ The [whitepaper's unsigned-lock-witnesses section](https://github.com/ickb/white **5F. Limit Order confusion attack** -**Trace:** CKB builds lock groups only from input locks, while type groups come from both input and output types ([`types.rs:716-739`](https://github.com/nervosnetwork/ckb/blob/6730f8023810d0888aa80c6a0d54cc2af918097d/script/src/types.rs#L716-L739)). A limit-order cell is the lock-only `(true, false)` case in [`limit_order/entry.rs:48-56`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L48-L56), so an attacker can create phantom order outputs with arbitrary master outpoints without running `limit_order` at creation time. One manifestation is a fake order that shares a real master outpoint; if a user later melts the wrong order, the real order becomes permanently stranded. +**Trace:** CKB builds lock groups only from input locks, while type groups come from both input and output types ([`types.rs:642-666`](https://github.com/nervosnetwork/ckb/blob/2592ddf0502cd4adfe886db893cccc866db3c60f/script/src/types.rs#L642-L666)). A limit-order cell is the lock-only `(true, false)` case in [`limit_order/entry.rs:48-56`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/limit_order/src/entry.rs#L48-L56), so an attacker can create phantom order outputs with arbitrary master outpoints without running `limit_order` at creation time. One manifestation is a foreign-token fake order with unrelated pricing and order information that references a real master outpoint; if a user later melts the wrong order, the real order becomes permanently stranded. -**Result:** **Known vulnerability.** [Documented in whitepaper](https://github.com/ickb/whitepaper/blob/cdbabf653ba98eacea397f94f8c894f32a538d6c/README.md#confusion-attack-on-limit-order). The [real-order stranding test](scripts/tests/src/tests/limit_order/fake_match_lineage.rs) confirms the later real-order stranding path on the deployed binary. +**Result:** **Known vulnerability.** [Documented in whitepaper](https://github.com/ickb/whitepaper/blob/master/README.md#confusion-attack-on-limit-order). The [real-order stranding test](scripts/tests/src/tests/limit_order/fake_match_lineage.rs) confirms the later real-order stranding path on the deployed binary. The whitepaper's mitigation is front-end lineage checking from the original mint transaction. Under the deployed lock-only design, the chain does not validate phantom orders at creation time because the order cell is created as an output lock-only cell. @@ -594,7 +609,9 @@ The remaining scenarios are boundary checks, platform constraints, or known econ **Trace:** the minimum deposit check uses `<` ([`entry.rs:101`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L101)), so exactly 1000 CKB is allowed. The maximum uses `>` ([`entry.rs:104`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/ickb_logic/src/entry.rs#L104)), so exactly 1M CKB is also allowed. The boundary-value regressions in [deposit_bounds.rs](scripts/tests/src/tests/ickb_logic/deposit_bounds.rs) cover both edges. -**Result:** **Correct.** +These bounds are part of the output check, which runs only when the creating transaction also executes `iCKB Logic`, as it does with a receipt. A receiptless deposit is created without that check, so the pool can hold deposits of any size; one below the minimum is still withdrawn at its exact iCKB value ([receiptless below-the-minimum test](scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs)). Its creator receives no iCKB, so withdrawing it costs its full iCKB value and the withdrawer gains only the deposit's occupied capacity; in aggregate, the pool keeps unoccupied value that no minted iCKB matches, which is effectively burned. Integrations must not assume pool deposits lie within the bounds. + +**Result:** **Correct for receipted deposits; the pool itself is unbounded.** **6B. u128 overflow in balance equation** @@ -610,7 +627,7 @@ The remaining scenarios are boundary checks, platform constraints, or known econ **6D. `extract_unused_capacity` underflow** -**Trace:** CKB VM enforces `capacity >= occupied_capacity` for all cells. The subtraction at [`utils.rs:48`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L48) is safe. +**Trace:** the node's transaction verifier enforces `capacity >= occupied_capacity` for all cells; `ckb-testtool` does not run that verifier, so this rests on the consensus rule rather than on the suite. The subtraction at [`utils.rs:48`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L48) is safe. **Result:** **Impossible.** @@ -628,15 +645,15 @@ The remaining scenarios are boundary checks, platform constraints, or known econ **Trace:** the attack requires sustained capital commitment. Per the [whitepaper analysis](https://github.com/ickb/whitepaper/issues/8), controlling the first available epoch requires about `0.6%` of pool capital, while controlling the first 3 days requires about `10%`. With a `0.3%` APR per 180 epochs, a user blocked for 1 epoch loses about `0.0017%` interest. -The attacker earns nothing because the cycled CKB returns to them, still pays transaction fees, and must lock capital for 180 epochs per cycle. As the pool grows, the capital requirement rises proportionally while the impact per unit of capital falls. +The attacker earns nothing because the cycled CKB returns to them, still pays transaction fees, and must lock capital for at least one 180-epoch NervosDAO period per cycle ([RFC 0023](https://github.com/nervosnetwork/rfcs/blob/4b502ffcb02fc7019e0dd4b5f866b5f09819cfbe/rfcs/0023-dao-deposit-withdraw/0023-dao-deposit-withdraw.md)). As the pool grows, the capital requirement rises proportionally while the impact per unit of capital falls. **Result:** **Requires sustained capital and yields less impact as the pool grows.** This is a known limitation, not a vulnerability. **6G. Same-block receipt and deposit consumption** -**Attack:** create a deposit plus receipt in `TX1`, then consume both in `TX2` (receipt for phase 2 plus deposit for withdrawal) in the hope that the AR difference yields free `iCKB`. +**Attack:** create a deposit plus receipt in `TX1`, then, once `TX1` is committed, consume both in a later `TX2` (receipt for phase 2 plus deposit for withdrawal) in the hope that the AR difference yields free `iCKB`. Both spends need `TX1`'s block header in `header_deps`, so `TX2` cannot share `TX1`'s block. -**Trace:** both were created in the same block (`TX1`). [`extract_accumulated_rate`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L54-L61) returns the same AR for both. Since `receipt_value == deposit_value`, the balance equation yields `0 + receipt_value == out_udt + deposit_value` -> `out_udt = 0`. No net `iCKB` is minted. +**Trace:** both were created in the same block (`TX1`). [`extract_accumulated_rate`](https://github.com/ickb/contracts/blob/454cfa966052a621c4e8b67001718c29ee8191a2/scripts/contracts/utils/src/utils.rs#L54-L61) returns the same AR for both. Since `receipt_value == deposit_value`, the balance equation yields `0 + receipt_value == out_udt + deposit_value` -> `out_udt = 0`. No net `iCKB` is minted, as the [same-block receipt and deposit test](scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs) shows: minting 0 passes and minting 1 fails with `AmountMismatch`. **Result:** **No profit.** From 6bdfc789161fd2e832468b5f38ea8fc9ff625e27 Mon Sep 17 00:00:00 2001 From: phroi <90913182+phroi@users.noreply.github.com> Date: Sat, 26 Sep 2026 15:15:55 +0200 Subject: [PATCH 09/13] docs: rename the report and give it a review period The report is an evolving review, revised since its first completion on 2026-05-01, so a single date in its name and header misdescribes it. It is now ICKB-Audit-Report.md with a review period of 2026-05-01 to 2026-09-26; the repository history records each revision. Both README links follow the rename. --- 20260501-ICKB-Audit-Report.md => ICKB-Audit-Report.md | 2 +- README.md | 2 +- scripts/README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename 20260501-ICKB-Audit-Report.md => ICKB-Audit-Report.md (99%) diff --git a/20260501-ICKB-Audit-Report.md b/ICKB-Audit-Report.md similarity index 99% rename from 20260501-ICKB-Audit-Report.md rename to ICKB-Audit-Report.md index 15158cd..3918d70 100644 --- a/20260501-ICKB-Audit-Report.md +++ b/ICKB-Audit-Report.md @@ -1,6 +1,6 @@ # iCKB Contracts Security Review -- **Review completion date:** 2026-05-01. +- **Review period:** 2026-05-01 to 2026-09-26. This is an evolving review; the repository history records each revision. - **Reviewed contracts commit:** [`454cfa9`](https://github.com/ickb/contracts/tree/454cfa966052a621c4e8b67001718c29ee8191a2). This is the last commit that changed `scripts/contracts/**` or `scripts/Cargo.toml`. - **Executable test evidence:** current `scripts/tests/**` suite in this repository state. - **Scope:** `iCKB Logic`, `Owned Owner`, `Limit Order`, and the shared `utils` crate. diff --git a/README.md b/README.md index 25a7912..daf9335 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ These L1 Scripts have been both internally reviewed by individuals with deep exp For convenience, a local copy of the Scalebit report is also available in this repository at [`20240911-ICKB-Final-Audit-Report.pdf`](./20240911-ICKB-Final-Audit-Report.pdf). -This repository also includes a later local executable review of the deployed release binaries in [`20260501-ICKB-Audit-Report.md`](./20260501-ICKB-Audit-Report.md). +This repository also includes a later local executable review of the deployed release binaries in [`ICKB-Audit-Report.md`](./ICKB-Audit-Report.md). ## Licensing diff --git a/scripts/README.md b/scripts/README.md index 38915fa..6983474 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -4,7 +4,7 @@ These L1 Scripts have been both internally reviewed by individuals with deep experience in Nervos L1 and [externally audited by the Scalebit team](https://scalebit.xyz/reports/20240911-ICKB-Final-Audit-Report.pdf), an internationally recognized blockchain security team. -This repository also includes a later local executable review of the deployed release binaries in [`../20260501-ICKB-Audit-Report.md`](../20260501-ICKB-Audit-Report.md). +This repository also includes a later local executable review of the deployed release binaries in [`../ICKB-Audit-Report.md`](../ICKB-Audit-Report.md). ## Building the Scripts From 42a0009fa8391691fd6430c0cfb59c3e46a876d3 Mon Sep 17 00:00:00 2001 From: phroi <90913182+phroi@users.noreply.github.com> Date: Sat, 26 Sep 2026 15:44:58 +0200 Subject: [PATCH 10/13] test: shared helpers for cells, inputs and failing verifications The suite spelled out cells with multi-line CellOutput builders (932), inputs with CellInput builders (540), and each expected failure as verify, unwrap_err and assert_script_error (120). Deposit, UDT and receipt cells repeated the same create_cell shape about 140 times. cell(capacity, lock, type) replaces 930 of the cell builders; the two left measure occupied capacity or omit a capacity on purpose. input(out_point) replaces the 481 inputs without a since. fail(context, tx, code) replaces the 120 failure checks. create_deposit, create_udt and create_receipt build the recurring live cells at the sizes the fixtures already used. Needless double borrows are removed. The suite drops from 16,412 to 12,160 lines. No test changes what it checks. A temporary log of every verification, run before and after, recorded each transaction's inputs, outputs, data, since values, header deps and witness lengths, with random out points masked, together with its result. Of the 230 tests, 206 verify transactions: the 184 whose transactions are deterministic built identical ones, and the 22 that use random keys or hash-ordered headers returned the same results. As a control, changing one funding cell by 1 CKB makes that log differ. --- scripts/tests/src/tests.rs | 92 ++--- scripts/tests/src/tests/fixtures.rs | 112 +++--- .../tests/ickb_logic/creation_blind_spots.rs | 97 +---- .../tests/ickb_logic/dao_phase2_batching.rs | 75 +--- .../src/tests/ickb_logic/deposit_bounds.rs | 82 +--- .../tests/ickb_logic/economic_precision.rs | 224 ++--------- .../ickb_logic/mixed_flow_composition.rs | 242 +++--------- .../ickb_logic/multi_quantity_receipts.rs | 38 +- .../src/tests/ickb_logic/phase2_headers.rs | 107 +----- .../ickb_logic/phase2_recipient_binding.rs | 111 +----- .../phase2_sibling_classification.rs | 250 +++--------- .../ickb_logic/phase2_xudt_output_data.rs | 61 +-- .../src/tests/ickb_logic/receipt_encoding.rs | 64 +--- .../src/tests/ickb_logic/receipt_matching.rs | 66 +--- .../receiptless_deposit_blind_spot.rs | 290 +++----------- .../tests/src/tests/ickb_logic/soft_cap.rs | 128 ++----- .../tests/ickb_logic/xudt_amount_limits.rs | 48 +-- .../ickb_logic/xudt_owner_witness_fallback.rs | 40 +- .../tests/limit_order/crosswire_blockers.rs | 126 ++----- .../tests/limit_order/crosswire_live_match.rs | 87 ++--- .../limit_order/crosswire_mint_creation.rs | 147 ++------ .../tests/limit_order/fake_match_lineage.rs | 86 +---- .../tests/src/tests/limit_order/fulfilled.rs | 46 +-- .../src/tests/limit_order/lock_only_shapes.rs | 66 +--- .../src/tests/limit_order/master_admission.rs | 70 +--- .../tests/limit_order/match_progression.rs | 259 +++---------- .../limit_order/mint_shape_validation.rs | 67 +--- .../src/tests/limit_order/phantom_lineage.rs | 152 ++------ .../tests/src/tests/limit_order/poisoning.rs | 106 ++---- .../src/tests/limit_order/real_lineage.rs | 48 +-- scripts/tests/src/tests/limit_order/remint.rs | 39 +- .../src/tests/limit_order/same_master.rs | 60 +-- .../src/tests/owned_owner/dao_crosswiring.rs | 257 +++---------- .../tests/owned_owner/foreign_dao_wrapping.rs | 54 +-- .../foreign_owner_lock_boundaries.rs | 135 ++----- .../tests/owned_owner/live_claim_rotation.rs | 119 ++---- .../owned_owner/melt_pairing_and_witness.rs | 177 ++------- .../owned_owner/mixed_asset_crosswiring.rs | 112 ++---- .../owned_owner/owner_distance_encoding.rs | 108 +----- .../src/tests/owned_owner/pair_formation.rs | 212 +++-------- .../src/tests/owned_owner/phase1_poisoning.rs | 104 ++--- .../owned_owner/positive_distance_claims.rs | 172 ++------- .../src/tests/owned_owner/script_misuse.rs | 134 ++----- .../owned_owner/weak_lock_output_rebinding.rs | 210 ++--------- .../withdrawal_amount_and_headers.rs | 356 ++++-------------- scripts/tests/src/tests/protocol_vectors.rs | 29 +- .../replay/family_attacker_limit_order.rs | 171 +++------ .../replay/family_mainnet_eight_claim.rs | 134 ++----- .../src/tests/replay/family_mixed_restake.rs | 199 +++------- .../tests/replay/family_two_claim_restake.rs | 210 +++-------- .../src/tests/replay/lineage_21ccbca0.rs | 203 +++------- .../src/tests/replay/lineage_30f8ed8a.rs | 113 ++---- .../src/tests/replay/lineage_86d442e2.rs | 231 +++--------- .../src/tests/replay/lineage_b866945c.rs | 217 +++-------- .../src/tests/replay/lineage_b923f354.rs | 84 +---- scripts/tests/src/tests/replay/tx_5f6d0d5b.rs | 66 +--- scripts/tests/src/tests/replay/tx_9df44c51.rs | 68 +--- scripts/tests/src/tests/replay_helpers.rs | 32 +- scripts/tests/src/tests/signing.rs | 83 ++-- 59 files changed, 1620 insertions(+), 5856 deletions(-) diff --git a/scripts/tests/src/tests.rs b/scripts/tests/src/tests.rs index bed5246..8e25b01 100644 --- a/scripts/tests/src/tests.rs +++ b/scripts/tests/src/tests.rs @@ -84,13 +84,13 @@ impl VerifyRealistic for Context { fn verify_rejects_a_cell_below_its_occupied_capacity() { let mut context = Context::default(); let lock = always_success_lock(&mut context); - let input = context.create_cell( - CellOutput::new_builder().capacity((1_000 * CKB).pack()).lock(lock.clone()).build(), + let funding = context.create_cell( + cell(1_000 * CKB, &lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input).build()) - .output(CellOutput::new_builder().capacity((40 * CKB).pack()).lock(lock).build()) + .input(input(funding)) + .output(cell(40 * CKB, &lock, None)) .output_data(Bytes::new().pack()) .build(); let tx = context.complete_tx(tx); @@ -105,15 +105,12 @@ fn verify_rejects_a_withdrawal_request_whose_lock_size_differs() { let request_lock = always_success_lock(&mut context); let dao = dao_script(&mut context); let capacity = 1_000 * CKB; - let deposit = context.create_cell( - CellOutput::new_builder().capacity(capacity.pack()).lock(deposit_lock).type_(Some(dao.clone()).pack()).build(), - dao_deposit_data(), - ); + let deposit = create_deposit(&mut context, capacity, &deposit_lock, &dao); let header = gen_header(1554, GENESIS_AR, 35, 1000, 1000); link_cell_to_header(&mut context, &deposit, &header); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit).build()) - .output(CellOutput::new_builder().capacity(capacity.pack()).lock(request_lock).type_(Some(dao).pack()).build()) + .input(input(deposit)) + .output(cell(capacity, &request_lock, Some(&dao))) .output_data(withdrawal_request_data(1554).pack()) .header_dep(header.hash()) .build(); @@ -175,6 +172,10 @@ fn assert_script_error(err: Error, err_code: i8) { ); } +fn fail(context: &Context, tx: &TransactionView, err_code: i8) { + assert_script_error(context.verify(tx, MAX_CYCLES).unwrap_err(), err_code); +} + fn assert_script_error_in(err: Error, err_codes: &[i8]) { let error_string = err.to_string(); assert!( @@ -198,42 +199,23 @@ fn type_role_scan_with_512_unrelated_outputs_stays_within_test_cycle_budget() { let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); let deposit_amount = 1_000 * CKB; let deposit_header = gen_header(1554, GENESIS_AR, 35, 1000, 1000); - let receipt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_input = create_receipt(&mut context, &user_lock, &ickb_logic, 1, deposit_amount); link_cell_to_header(&mut context, &receipt_input, &deposit_header); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity(((PADDING_OUTPUTS as u64 + 1) * 100 * CKB).pack()) - .lock(user_lock.clone()) - .build(), + cell((PADDING_OUTPUTS as u64 + 1) * 100 * CKB, &user_lock, None), Bytes::new(), ); - let mut outputs = vec![CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt).pack()) - .build()]; + let mut outputs = vec![cell(occupied_capacity(&user_lock, &xudt, 16), &user_lock, Some(&xudt))]; let mut outputs_data = vec![udt_data(u128::from(deposit_amount))]; for _ in 0..PADDING_OUTPUTS { - outputs.push( - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(user_lock.clone()) - .build(), - ); + outputs.push(cell(100 * CKB, &user_lock, None)); outputs_data.push(Bytes::new()); } let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_input).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(receipt_input)) + .input(input(funding_input)) .outputs(outputs) .outputs_data(outputs_data.pack()) .header_dep(deposit_header.hash()) @@ -283,54 +265,34 @@ fn scaffolding_tests_fail_for_the_reasons_reported() { let mut context = Context::default(); let ickb_logic = data1_script(&mut context, "ickb_logic", Bytes::from(vec![42])); let input_out_point = context.create_cell( - CellOutput::new_builder() - .capacity((1000 * CKB).pack()) - .lock(ickb_logic.clone()) - .build(), + cell(1000 * CKB, &ickb_logic, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_out_point).build()) + .input(input(input_out_point)) .outputs(vec![ - CellOutput::new_builder() - .capacity((500 * CKB).pack()) - .lock(ickb_logic.clone()) - .build(), - CellOutput::new_builder() - .capacity((500 * CKB).pack()) - .lock(ickb_logic) - .build(), + cell(500 * CKB, &ickb_logic, None), + cell(500 * CKB, &ickb_logic, None), ]) .outputs_data(vec![Bytes::new(), Bytes::new()].pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_NOT_EMPTY_ARGS); + fail(&context, &tx, ERROR_NOT_EMPTY_ARGS); let mut context = Context::default(); let ickb_logic = ickb_logic_script(&mut context); let input_out_point = context.create_cell( - CellOutput::new_builder() - .capacity((1000 * CKB).pack()) - .lock(ickb_logic.clone()) - .build(), + cell(1000 * CKB, &ickb_logic, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_out_point).build()) + .input(input(input_out_point)) .outputs(vec![ - CellOutput::new_builder() - .capacity((500 * CKB).pack()) - .lock(ickb_logic.clone()) - .build(), - CellOutput::new_builder() - .capacity((500 * CKB).pack()) - .lock(ickb_logic) - .build(), + cell(500 * CKB, &ickb_logic, None), + cell(500 * CKB, &ickb_logic, None), ]) .outputs_data(vec![Bytes::new(), Bytes::new()].pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SCRIPT_MISUSE); + fail(&context, &tx, ERROR_SCRIPT_MISUSE); } diff --git a/scripts/tests/src/tests/fixtures.rs b/scripts/tests/src/tests/fixtures.rs index ff907da..8e8a1bc 100644 --- a/scripts/tests/src/tests/fixtures.rs +++ b/scripts/tests/src/tests/fixtures.rs @@ -129,12 +129,7 @@ pub(super) fn dao_dep_out_point(context: &mut Context) -> OutPoint { let data = Bytes::from(BUNDLED_CELL.get("specs/cells/dao").expect("bundled dao cell").into_owned()); let lock = always_success_lock(context); let type_script = build_genesis_type_id_script(OUTPUT_INDEX_DAO); - let cell = CellOutput::new_builder() - .lock(lock) - .type_(Some(type_script).pack()) - .capacity(capacity_for_data(data.len() as u64).pack()) - .build(); - context.create_cell(cell, data) + context.create_cell(cell(capacity_for_data(data.len() as u64), &lock, Some(&type_script)), data) } pub(super) fn dao_script(context: &mut Context) -> Script { @@ -153,11 +148,40 @@ pub(super) fn capacity_for_data(data_len: u64) -> u64 { 100 * CKB + data_len } +/// A cell output with this capacity, lock and optional type. +pub(super) fn cell(capacity: u64, lock: &Script, type_: Option<&Script>) -> CellOutput { + CellOutput::new_builder() + .capacity(capacity.pack()) + .lock(lock.clone()) + .type_(type_.cloned().pack()) + .build() +} + +/// A transaction input spending this out point. +pub(super) fn input(out_point: OutPoint) -> CellInput { + CellInput::new_builder().previous_output(out_point).build() +} + +/// A live xUDT cell holding this amount, sized at its occupied capacity. +pub(super) fn create_udt(context: &mut Context, lock: &Script, xudt: &Script, amount: u128) -> OutPoint { + context.create_cell(cell(occupied_capacity(lock, xudt, 16), lock, Some(xudt)), udt_data(amount)) +} + +/// A live receipt cell for `quantity` deposits of `amount`, sized at its occupied capacity. +pub(super) fn create_receipt(context: &mut Context, lock: &Script, ickb_logic: &Script, quantity: u32, amount: u64) -> OutPoint { + context.create_cell(cell(occupied_capacity(lock, ickb_logic, 12), lock, Some(ickb_logic)), receipt_data(quantity, amount)) +} + +/// A live NervosDAO deposit cell with this total capacity. +pub(super) fn create_deposit(context: &mut Context, capacity: u64, lock: &Script, dao: &Script) -> OutPoint { + context.create_cell(cell(capacity, lock, Some(dao)), dao_deposit_data()) +} + /// A plain CKB cell that funds a transaction's outputs, as a wallet adds one on chain. pub(super) fn funding_cell(context: &mut Context) -> OutPoint { let lock = named_always_success_lock(context, b"funding"); context.create_cell( - CellOutput::new_builder().capacity((1_000 * CKB).pack()).lock(lock).build(), + cell(1_000 * CKB, &lock, None), Bytes::new(), ) } @@ -289,11 +313,7 @@ pub(super) fn create_receipt_input( accumulated_rate: u64, ) -> (OutPoint, Byte32) { let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(capacity_for_data(data.len() as u64).pack()) - .lock(lock) - .type_(Some(ickb_logic.clone()).pack()) - .build(), + cell(capacity_for_data(data.len() as u64), &lock, Some(ickb_logic)), data, ); let receipt_header = insert_header_for_cell(context, &receipt_out_point, block_number, accumulated_rate); @@ -312,23 +332,9 @@ pub(super) fn create_withdrawal_inputs( ) -> (u64, ckb_testtool::ckb_types::core::HeaderView, OutPoint, OutPoint) { let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(ickb_logic, dao, deposit_amount, deposit_number); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(context, deposit_total_capacity, ickb_logic, dao); link_cell_to_header(context, &deposit_input, &deposit_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock) - .type_(Some(xudt.clone()).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); + let udt_input = create_udt(context, &owner_lock, xudt, u128::from(deposit_amount)); // Returns `(deposit_total_capacity, deposit_header, deposit_input, udt_input)`; callers still supply the matching withdraw header deps. (deposit_total_capacity, deposit_header, deposit_input, udt_input) } @@ -350,27 +356,14 @@ pub(super) fn build_real_limit_order_and_master_with_capacity( let funding_lock = always_success_lock(context); let limit_order = limit_order_script(context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((capacity + 500u64).pack()) - .lock(funding_lock) - .build(), + cell(capacity + 500u64, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .output( - CellOutput::new_builder() - .capacity(capacity.pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type).pack()) - .build(), - ) + .input(input(funding_input)) + .output(cell(capacity, &limit_order, Some(&helper_type))) .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) - .lock(owner_lock) - .type_(Some(limit_order).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &limit_order, 0), &owner_lock, Some(&limit_order)), ) .outputs_data(vec![order_data_mint(0, 1, (1, 1)), Bytes::new()].pack()) .build(); @@ -389,20 +382,13 @@ pub(super) fn assert_lock_only_limit_order_spend_error(data: Bytes, expected_err let funding_lock = always_success_lock(&mut context); let (limit_order, output_type) = limit_order_and_helper_type_scripts(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((500 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(500 * CKB, &funding_lock, None), Bytes::new(), ); - let forged_output = CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(output_type).pack()) - .build(); + let forged_output = cell(200 * CKB, &limit_order, Some(&output_type)); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .output(forged_output.clone()) .output_data(data.clone().pack()) .build(); @@ -413,20 +399,10 @@ pub(super) fn assert_lock_only_limit_order_spend_error(data: Bytes, expected_err let forged_out_point = context.create_cell(forged_output, data); let spend_tx = TransactionBuilder::default() - .input( - CellInput::new_builder() - .previous_output(forged_out_point) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(always_success_lock(&mut context)) - .build(), - ) + .input(input(forged_out_point)) + .output(cell(200 * CKB, &always_success_lock(&mut context), None)) .output_data(Bytes::new().pack()) .build(); let spend_tx = context.complete_tx(spend_tx); - let err = context.verify(&spend_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, expected_error); + fail(&context, &spend_tx, expected_error); } diff --git a/scripts/tests/src/tests/ickb_logic/creation_blind_spots.rs b/scripts/tests/src/tests/ickb_logic/creation_blind_spots.rs index dee0999..ebf465b 100644 --- a/scripts/tests/src/tests/ickb_logic/creation_blind_spots.rs +++ b/scripts/tests/src/tests/ickb_logic/creation_blind_spots.rs @@ -8,22 +8,13 @@ fn lock_only_ickb_logic_non_dao_output_can_be_created() { let ickb_logic = ickb_logic_script(&mut context); let helper_type = helper_type_script(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((500 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(500 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .output( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(ickb_logic.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - ) + .input(input(funding_input)) + .output(cell(200 * CKB, &ickb_logic, Some(&helper_type))) .output_data(Bytes::new().pack()) .build(); @@ -33,27 +24,17 @@ fn lock_only_ickb_logic_non_dao_output_can_be_created() { .expect("lock-only misuse cell creation bypasses ickb_logic"); let phantom_out_point = context.create_cell( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(ickb_logic) - .type_(Some(helper_type).pack()) - .build(), + cell(200 * CKB, &ickb_logic, Some(&helper_type)), Bytes::new(), ); let spend_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(phantom_out_point).build()) - .output( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(always_success_lock(&mut context)) - .build(), - ) + .input(input(phantom_out_point)) + .output(cell(200 * CKB, &always_success_lock(&mut context), None)) .output_data(Bytes::new().pack()) .build(); let spend_tx = context.complete_tx(spend_tx); - let err = context.verify(&spend_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SCRIPT_MISUSE); + fail(&context, &spend_tx, ERROR_SCRIPT_MISUSE); } // Build a plain funding tx that creates an ickb_logic lock with non-empty args, then spend that output: creation passes because the lock is only on outputs, but the later spend fails because ickb_logic requires empty args when it finally executes. @@ -63,21 +44,13 @@ fn non_empty_args_ickb_logic_lock_output_can_be_created_but_not_spent() { let funding_lock = always_success_lock(&mut context); let ickb_logic_non_empty = data1_script(&mut context, "ickb_logic", Bytes::from(vec![1])); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((500 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(500 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .output( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(ickb_logic_non_empty.clone()) - .build(), - ) + .input(input(funding_input)) + .output(cell(200 * CKB, &ickb_logic_non_empty, None)) .output_data(Bytes::new().pack()) .build(); let tx = context.complete_tx(tx); @@ -86,25 +59,16 @@ fn non_empty_args_ickb_logic_lock_output_can_be_created_but_not_spent() { .expect("non-empty-args output lock can be created because output locks do not execute"); let out_point = context.create_cell( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(ickb_logic_non_empty) - .build(), + cell(200 * CKB, &ickb_logic_non_empty, None), Bytes::new(), ); let spend_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(out_point).build()) - .output( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(always_success_lock(&mut context)) - .build(), - ) + .input(input(out_point)) + .output(cell(200 * CKB, &always_success_lock(&mut context), None)) .output_data(Bytes::new().pack()) .build(); let spend_tx = context.complete_tx(spend_tx); - let err = context.verify(&spend_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_NOT_EMPTY_ARGS); + fail(&context, &spend_tx, ERROR_NOT_EMPTY_ARGS); } // A withdrawal request keeps the deposit's DAO type but carries non-zero data, so it is no deposit; @@ -117,36 +81,16 @@ fn withdrawal_request_locked_by_ickb_logic_is_script_misuse() { let deposit_amount = 1_500 * CKB; let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, deposit_amount); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); let deposit_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); + let udt_input = create_udt(&mut context, &user_lock, &xudt, u128::from(deposit_amount)); let withdraw_tx = |request_lock: &Script| { TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input.clone()).build()) - .input(CellInput::new_builder().previous_output(udt_input.clone()).build()) - .output( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(request_lock.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - ) + .input(input(deposit_input.clone())) + .input(input(udt_input.clone())) + .output(cell(deposit_total_capacity, request_lock, Some(&dao))) .output_data(withdrawal_request_data(1554).pack()) .header_dep(deposit_header.hash()) .build() @@ -158,6 +102,5 @@ fn withdrawal_request_locked_by_ickb_logic_is_script_misuse() { .expect("the same request under a user lock is a valid phase1 withdrawal"); let misuse = context.complete_tx(withdraw_tx(&ickb_logic)); - let err = context.verify(&misuse, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SCRIPT_MISUSE); + fail(&context, &misuse, ERROR_SCRIPT_MISUSE); } diff --git a/scripts/tests/src/tests/ickb_logic/dao_phase2_batching.rs b/scripts/tests/src/tests/ickb_logic/dao_phase2_batching.rs index edeca2c..540e940 100644 --- a/scripts/tests/src/tests/ickb_logic/dao_phase2_batching.rs +++ b/scripts/tests/src/tests/ickb_logic/dao_phase2_batching.rs @@ -12,21 +12,14 @@ fn dao_phase2_with_65_outputs_hits_the_upstream_batch_limit() { let deposit_number_data = 1554u64.to_le_bytes(); let withdrawing_input = context.create_cell( - CellOutput::new_builder() - .capacity((1_234_567_800u64 * 65).pack()) - .lock(owner_lock.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(1_234_567_800u64 * 65, &owner_lock, Some(&dao)), Bytes::from(deposit_number_data.to_vec()), ); link_cell_to_header(&mut context, &withdrawing_input, &withdraw_header); context.insert_header(deposit_header.clone()); let outputs = vec![ - CellOutput::new_builder() - .capacity(123_468_105_678u64.pack()) - .lock(owner_lock.clone()) - .build(); + cell(123_468_105_678u64, &owner_lock, None); 65 ]; let outputs_data = vec![Bytes::new(); 65]; @@ -48,8 +41,7 @@ fn dao_phase2_with_65_outputs_hits_the_upstream_batch_limit() { .build(); let tx = sign_tx(context.complete_tx(tx), &privkey); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_DAO_TOO_MANY_OUTPUT_CELLS); + fail(&context, &tx, ERROR_DAO_TOO_MANY_OUTPUT_CELLS); } // Build a helper-generated phase2 batch with 64 withdrawal claims and 64 matching deposit headers: this is the largest accepted batch shape, so verification should pass at the boundary. @@ -71,11 +63,7 @@ fn dao_phase2_rejects_header_dep_index_witness_in_output_type() { let deposit_header = gen_header(1554, SYNTHETIC_DEPOSIT_AR, 35, 1000, 1000); let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let withdrawing_input = context.create_cell( - CellOutput::new_builder() - .capacity(123_456_780_000u64.pack()) - .lock(owner_lock.clone()) - .type_(Some(dao).pack()) - .build(), + cell(123_456_780_000u64, &owner_lock, Some(&dao)), withdrawal_request_data(1554), ); link_cell_to_header(&mut context, &withdrawing_input, &withdraw_header); @@ -89,12 +77,7 @@ fn dao_phase2_rejects_header_dep_index_witness_in_output_type() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .output( - CellOutput::new_builder() - .capacity(123_468_106_670u64.pack()) - .lock(owner_lock) - .build(), - ) + .output(cell(123_468_106_670u64, &owner_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) @@ -102,8 +85,7 @@ fn dao_phase2_rejects_header_dep_index_witness_in_output_type() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, -11); + fail(&context, &tx, -11); } // Build a single-withdrawal DAO phase2 tx with an `input_type` witness that truncates the 8-byte header-dep index: the index encoding is incomplete, so DAO validation fails. @@ -116,11 +98,7 @@ fn dao_phase2_rejects_short_header_dep_index_witness_in_input_type() { let deposit_header = gen_header(1554, SYNTHETIC_DEPOSIT_AR, 35, 1000, 1000); let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let withdrawing_input = context.create_cell( - CellOutput::new_builder() - .capacity(123_456_780_000u64.pack()) - .lock(owner_lock.clone()) - .type_(Some(dao).pack()) - .build(), + cell(123_456_780_000u64, &owner_lock, Some(&dao)), withdrawal_request_data(1554), ); link_cell_to_header(&mut context, &withdrawing_input, &withdraw_header); @@ -134,12 +112,7 @@ fn dao_phase2_rejects_short_header_dep_index_witness_in_input_type() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .output( - CellOutput::new_builder() - .capacity(123_468_106_670u64.pack()) - .lock(owner_lock) - .build(), - ) + .output(cell(123_468_106_670u64, &owner_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) @@ -147,16 +120,14 @@ fn dao_phase2_rejects_short_header_dep_index_witness_in_input_type() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, -11); + fail(&context, &tx, -11); } // Build a 64-item DAO phase2 batch but deliberately point one witness at the wrong deposit header: the batch shape is otherwise valid, so failure isolates the per-input header binding invariant. #[test] fn dao_phase2_rejects_misbound_deposit_header_index_in_large_batch() { let (context, tx) = build_many_header_phase2_batch(64, Some((37, 1))); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_DAO_INVALID_WITHDRAW_BLOCK); + fail(&context, &tx, ERROR_DAO_INVALID_WITHDRAW_BLOCK); } // Build one tx that claims two withdrawal cells from two different deposit headers with separate header indices: mixed-header phase2 batching is allowed when each input names its own deposit header, so verification should pass. @@ -171,17 +142,9 @@ fn dao_phase2_with_two_distinct_deposit_headers_passes() { let withdraw_header_1 = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let withdraw_header_2 = gen_header(2_000_621, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); - let input_1_output = CellOutput::new_builder() - .capacity(123_456_780_000u64.pack()) - .lock(owner_lock.clone()) - .type_(Some(dao.clone()).pack()) - .build(); + let input_1_output = cell(123_456_780_000u64, &owner_lock, Some(&dao)); let input_1 = context.create_cell(input_1_output.clone(), withdrawal_request_data(1554)); - let input_2_output = CellOutput::new_builder() - .capacity(123_456_781_000u64.pack()) - .lock(owner_lock.clone()) - .type_(Some(dao.clone()).pack()) - .build(); + let input_2_output = cell(123_456_781_000u64, &owner_lock, Some(&dao)); let input_2 = context.create_cell(input_2_output.clone(), withdrawal_request_data(1564)); link_cell_to_header(&mut context, &input_1, &withdraw_header_1); link_cell_to_header(&mut context, &input_2, &withdraw_header_2); @@ -216,18 +179,8 @@ fn dao_phase2_with_two_distinct_deposit_headers_passes() { .since(0x2003e802340002f3u64.pack()) .build(), ) - .output( - CellOutput::new_builder() - .capacity(exact_capacity_1.pack()) - .lock(owner_lock.clone()) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity(exact_capacity_2.pack()) - .lock(owner_lock.clone()) - .build(), - ) + .output(cell(exact_capacity_1, &owner_lock, None)) + .output(cell(exact_capacity_2, &owner_lock, None)) .outputs_data(vec![Bytes::new(), Bytes::new()].pack()) .header_dep(withdraw_header_1.hash()) .header_dep(withdraw_header_2.hash()) diff --git a/scripts/tests/src/tests/ickb_logic/deposit_bounds.rs b/scripts/tests/src/tests/ickb_logic/deposit_bounds.rs index 73db905..c2d7140 100644 --- a/scripts/tests/src/tests/ickb_logic/deposit_bounds.rs +++ b/scripts/tests/src/tests/ickb_logic/deposit_bounds.rs @@ -7,34 +7,22 @@ fn deposit_below_minimum_is_rejected() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); let amount = 999 * CKB; - let deposit_output = CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao).pack()) - .build(); - let receipt_output = CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock) - .type_(Some(ickb_logic).pack()) - .build(); + let deposit_output = cell(deposit_capacity(&ickb_logic, &dao, 8, amount), &ickb_logic, Some(&dao)); + let receipt_output = cell(occupied_capacity(&funding_lock, &ickb_logic, 12), &funding_lock, Some(&ickb_logic)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![deposit_output, receipt_output]) .outputs_data(vec![dao_deposit_data(), receipt_data(1, amount)].pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_DEPOSIT_TOO_SMALL); + fail(&context, &tx, ERROR_DEPOSIT_TOO_SMALL); } // Build one DAO deposit plus one matching receipt with amount exactly 1000 CKB: this is the minimum accepted bucket, so the creation tx should pass at the lower boundary. @@ -44,27 +32,16 @@ fn deposit_at_minimum_is_accepted() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); let amount = 1_000 * CKB; - let deposit_output = CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao).pack()) - .build(); - let receipt_output = CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock) - .type_(Some(ickb_logic).pack()) - .build(); + let deposit_output = cell(deposit_capacity(&ickb_logic, &dao, 8, amount), &ickb_logic, Some(&dao)); + let receipt_output = cell(occupied_capacity(&funding_lock, &ickb_logic, 12), &funding_lock, Some(&ickb_logic)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![deposit_output, receipt_output]) .outputs_data(vec![dao_deposit_data(), receipt_data(1, amount)].pack()) .build(); @@ -82,34 +59,22 @@ fn deposit_above_maximum_is_rejected() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((1_100_000 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(1_100_000 * CKB, &funding_lock, None), Bytes::new(), ); let amount = 1_000_001 * CKB; - let deposit_output = CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao).pack()) - .build(); - let receipt_output = CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock) - .type_(Some(ickb_logic).pack()) - .build(); + let deposit_output = cell(deposit_capacity(&ickb_logic, &dao, 8, amount), &ickb_logic, Some(&dao)); + let receipt_output = cell(occupied_capacity(&funding_lock, &ickb_logic, 12), &funding_lock, Some(&ickb_logic)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![deposit_output, receipt_output]) .outputs_data(vec![dao_deposit_data(), receipt_data(1, amount)].pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_DEPOSIT_TOO_BIG); + fail(&context, &tx, ERROR_DEPOSIT_TOO_BIG); } // Build one DAO deposit plus one matching receipt with amount exactly 1,000,000 CKB: this is the maximum accepted bucket, so the creation tx should still verify at the upper boundary. @@ -119,27 +84,16 @@ fn deposit_at_maximum_is_accepted() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((1_100_000 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(1_100_000 * CKB, &funding_lock, None), Bytes::new(), ); let amount = 1_000_000 * CKB; - let deposit_output = CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao).pack()) - .build(); - let receipt_output = CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock) - .type_(Some(ickb_logic).pack()) - .build(); + let deposit_output = cell(deposit_capacity(&ickb_logic, &dao, 8, amount), &ickb_logic, Some(&dao)); + let receipt_output = cell(occupied_capacity(&funding_lock, &ickb_logic, 12), &funding_lock, Some(&ickb_logic)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![deposit_output, receipt_output]) .outputs_data(vec![dao_deposit_data(), receipt_data(1, amount)].pack()) .build(); diff --git a/scripts/tests/src/tests/ickb_logic/economic_precision.rs b/scripts/tests/src/tests/ickb_logic/economic_precision.rs index b44539f..d58f370 100644 --- a/scripts/tests/src/tests/ickb_logic/economic_precision.rs +++ b/scripts/tests/src/tests/ickb_logic/economic_precision.rs @@ -16,43 +16,21 @@ fn reported_rounding_claim_is_blocked_by_actual_shannon_precision() { assert!(exact_ickb_1152 > 1_000 * CKB as u128); assert!(exact_ickb_1151 < exact_ickb_1152); - let receipt_1152 = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &ickb_logic, 12).pack()) - .lock(owner_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, amount_1152), - ); + let receipt_1152 = create_receipt(&mut context, &owner_lock, &ickb_logic, 1, amount_1152); let receipt_1152_header = gen_header(1, ar, 1, 1, 1000); link_cell_to_header(&mut context, &receipt_1152, &receipt_1152_header); let mint_claimed_1000_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_1152.clone()).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - ) + .input(input(receipt_1152.clone())) + .output(cell(occupied_capacity(&owner_lock, &xudt, 16), &owner_lock, Some(&xudt))) .output_data(udt_data(1_000 * CKB as u128).pack()) .header_dep(receipt_1152_header.hash()) .build(); let mint_claimed_1000_tx = context.complete_tx(mint_claimed_1000_tx); - let err = context - .verify(&mint_claimed_1000_tx, MAX_CYCLES) - .unwrap_err(); - assert_script_error(err, ERROR_AMOUNT_MISMATCH); + fail(&context, &mint_claimed_1000_tx, ERROR_AMOUNT_MISMATCH); let mint_exact_1152_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_1152).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - ) + .input(input(receipt_1152)) + .output(cell(occupied_capacity(&owner_lock, &xudt, 16), &owner_lock, Some(&xudt))) .output_data(udt_data(exact_ickb_1152).pack()) .header_dep(receipt_1152_header.hash()) .build(); @@ -61,31 +39,17 @@ fn reported_rounding_claim_is_blocked_by_actual_shannon_precision() { .verify(&mint_exact_1152_tx, MAX_CYCLES) .expect("1152 CKB receipt should mint its exact shannon-precision amount"); - let receipt_1151 = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &ickb_logic, 12).pack()) - .lock(owner_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, amount_1151), - ); + let receipt_1151 = create_receipt(&mut context, &owner_lock, &ickb_logic, 1, amount_1151); let receipt_1151_header = gen_header(2, ar, 1, 1, 1000); link_cell_to_header(&mut context, &receipt_1151, &receipt_1151_header); let remint_exact_1152_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_1151).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(receipt_1151)) + .output(cell(occupied_capacity(&owner_lock, &xudt, 16), &owner_lock, Some(&xudt))) .output_data(udt_data(exact_ickb_1152).pack()) .header_dep(receipt_1151_header.hash()) .build(); let remint_exact_1152_tx = context.complete_tx(remint_exact_1152_tx); - let err = context.verify(&remint_exact_1152_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_AMOUNT_MISMATCH); + fail(&context, &remint_exact_1152_tx, ERROR_AMOUNT_MISMATCH); } // Pin the shifted soft-cap edge under a non-genesis AR: normalization reaches the cap at 110k CKB. Ten shannons past it, normalizing first mints cap+9 while applying the haircut first would mint cap+8, so the passing cap+9 mint proves normalization precedes the per-deposit haircut; eleven past it, cap+10 must fail. @@ -109,25 +73,12 @@ fn non_genesis_ar_soft_cap_boundary_preserves_integer_operation_order() { assert_eq!(soft_capped_ickb(shifted_boundary + 11, ar), soft_cap + 9); let mut assert_mint = |block_number: u64, amount: u64, minted: u128, should_pass: bool| { - let receipt = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &ickb_logic, 12).pack()) - .lock(owner_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, amount), - ); + let receipt = create_receipt(&mut context, &owner_lock, &ickb_logic, 1, amount); let receipt_header = gen_header(block_number, ar, 1, 1, 1000); link_cell_to_header(&mut context, &receipt, &receipt_header); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - ) + .input(input(receipt)) + .output(cell(occupied_capacity(&owner_lock, &xudt, 16), &owner_lock, Some(&xudt))) .output_data(udt_data(minted).pack()) .header_dep(receipt_header.hash()) .build(); @@ -161,78 +112,33 @@ fn reported_rounding_withdrawal_claim_is_blocked_by_actual_shannon_precision() { let header = gen_header(1554, ar, 35, 1000, 1000); - let deposit_1152 = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount_1152).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_1152 = create_deposit(&mut context, deposit_capacity(&ickb_logic, &dao, 8, amount_1152), &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_1152, &header); - let udt_1000 = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - udt_data(1_000 * CKB as u128), - ); + let udt_1000 = create_udt(&mut context, &user_lock, &xudt, 1_000 * CKB as u128); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_1152).build()) - .input(CellInput::new_builder().previous_output(udt_1000).build()) + .input(input(deposit_1152)) + .input(input(udt_1000)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount_1152).pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(deposit_capacity(&ickb_logic, &dao, 8, amount_1152), &owned_owner, Some(&dao)), + cell(occupied_capacity(&user_lock, &owned_owner, 4), &user_lock, Some(&owned_owner)), ]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .header_dep(header.hash()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_AMOUNT_MISMATCH); - - let deposit_1152_b = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount_1152).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + fail(&context, &tx, ERROR_AMOUNT_MISMATCH); + + let deposit_1152_b = create_deposit(&mut context, deposit_capacity(&ickb_logic, &dao, 8, amount_1152), &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_1152_b, &header); - let udt_exact = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - udt_data(exact_ickb_1152), - ); + let udt_exact = create_udt(&mut context, &user_lock, &xudt, exact_ickb_1152); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_1152_b).build()) - .input(CellInput::new_builder().previous_output(udt_exact).build()) + .input(input(deposit_1152_b)) + .input(input(udt_exact)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount_1152).pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(deposit_capacity(&ickb_logic, &dao, 8, amount_1152), &owned_owner, Some(&dao)), + cell(occupied_capacity(&user_lock, &owned_owner, 4), &user_lock, Some(&owned_owner)), ]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .header_dep(header.hash()) @@ -242,44 +148,21 @@ fn reported_rounding_withdrawal_claim_is_blocked_by_actual_shannon_precision() { .verify(&tx, MAX_CYCLES) .expect("withdrawing 1152 CKB should require the exact shannon-precision iCKB amount"); - let deposit_1151 = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount_1151).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_1151 = create_deposit(&mut context, deposit_capacity(&ickb_logic, &dao, 8, amount_1151), &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_1151, &header); - let udt_exact_again = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(exact_ickb_1152), - ); + let udt_exact_again = create_udt(&mut context, &user_lock, &xudt, exact_ickb_1152); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_1151).build()) - .input(CellInput::new_builder().previous_output(udt_exact_again).build()) + .input(input(deposit_1151)) + .input(input(udt_exact_again)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount_1151).pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) - .lock(user_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(deposit_capacity(&ickb_logic, &dao, 8, amount_1151), &owned_owner, Some(&dao)), + cell(occupied_capacity(&user_lock, &owned_owner, 4), &user_lock, Some(&owned_owner)), ]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .header_dep(header.hash()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_AMOUNT_MISMATCH); + fail(&context, &tx, ERROR_AMOUNT_MISMATCH); } // Build full phase1-plus-DAO-phase2 flows for older, newer, and soft-capped deposits: each case should pass and the later normalized claim value must stay within one shannon of the phase1 burn, showing the protocol does not open a profitable precision gap across time or size boundaries. @@ -334,39 +217,19 @@ fn burn_and_claim( let (user_lock, ickb_logic, dao, xudt) = scripts; let (withdraw_header, withdraw_ar) = withdraw; let deposit_header = gen_header(deposit_number, deposit_ar, 35, 1000, 1000); - let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, amount); + let deposit_total_capacity = deposit_capacity(ickb_logic, dao, 8, amount); let deposit_occupied_capacity = deposit_total_capacity - amount; - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(context, deposit_total_capacity, ickb_logic, dao); link_cell_to_header(context, &deposit_input, &deposit_header); let burned_ickb = soft_capped_ickb(amount, deposit_ar); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - udt_data(burned_ickb), - ); + let udt_input = create_udt(context, user_lock, xudt, burned_ickb); let phase1_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .output( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(user_lock.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - ) + .input(input(deposit_input)) + .input(input(udt_input)) + .output(cell(deposit_total_capacity, user_lock, Some(dao))) .output_data(withdrawal_request_data(deposit_number).pack()) .header_dep(deposit_header.hash()) .build(); @@ -398,12 +261,7 @@ fn burn_and_claim( .since(0x2003e800000002f4u64.pack()) .build(), ) - .output( - CellOutput::new_builder() - .capacity(claim_capacity.pack()) - .lock(user_lock.clone()) - .build(), - ) + .output(cell(claim_capacity, user_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) diff --git a/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs b/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs index 77222f2..7c33ca8 100644 --- a/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs +++ b/scripts/tests/src/tests/ickb_logic/mixed_flow_composition.rs @@ -8,43 +8,21 @@ fn mixed_flow_cannot_overmint_by_combining_new_deposit_with_phase2_receipt() { let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, deposit_amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); - let deposit_output = CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, 8, deposit_amount).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao).pack()) - .build(); - let new_receipt_output = CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(); - let udt_output = CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(); + let deposit_output = cell(deposit_capacity(&ickb_logic, &dao, 8, deposit_amount), &ickb_logic, Some(&dao)); + let new_receipt_output = cell(occupied_capacity(&funding_lock, &ickb_logic, 12), &funding_lock, Some(&ickb_logic)); + let udt_output = cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(receipt_out_point)) + .input(input(funding_input)) .outputs(vec![deposit_output, new_receipt_output, udt_output]) .outputs_data( vec![ @@ -58,8 +36,7 @@ fn mixed_flow_cannot_overmint_by_combining_new_deposit_with_phase2_receipt() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_AMOUNT_MISMATCH); + fail(&context, &tx, ERROR_AMOUNT_MISMATCH); } // Build one tx that simultaneously creates a new deposit, starts a withdrawal from another deposit, reissues a receipt, and remints xUDT by one extra shannon: even with phase1 and phase2 combined, the cross-flow accounting invariant should reject the overmint. @@ -73,74 +50,30 @@ fn mixed_flow_cannot_overmint_when_deposit_phase1_phase2_and_withdrawal_share_on let dao = dao_script(&mut context); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &user_lock, &ickb_logic, 1, deposit_amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); + let udt_input = create_udt(&mut context, &user_lock, &xudt, u128::from(deposit_amount)); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(user_lock.clone()) - .build(), + cell(2_000 * CKB, &user_lock, None), Bytes::new(), ); - let new_deposit_output = CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(); - let owned_output = CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(); - let owner_output = CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner).pack()) - .build(); - let new_receipt_output = CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(); - let udt_output = CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock) - .type_(Some(xudt).pack()) - .build(); + let new_deposit_output = cell(deposit_total_capacity, &ickb_logic, Some(&dao)); + let owned_output = cell(deposit_total_capacity, &owned_owner, Some(&dao)); + let owner_output = cell(occupied_capacity(&user_lock, &owned_owner, 4), &user_lock, Some(&owned_owner)); + let new_receipt_output = cell(occupied_capacity(&user_lock, &ickb_logic, 12), &user_lock, Some(&ickb_logic)); + let udt_output = cell(occupied_capacity(&user_lock, &xudt, 16), &user_lock, Some(&xudt)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(receipt_out_point)) + .input(input(deposit_input)) + .input(input(udt_input)) + .input(input(funding_input)) .outputs(vec![new_deposit_output, owned_output, owner_output, new_receipt_output, udt_output]) .outputs_data( vec![ @@ -157,8 +90,7 @@ fn mixed_flow_cannot_overmint_when_deposit_phase1_phase2_and_withdrawal_share_on .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_AMOUNT_MISMATCH); + fail(&context, &tx, ERROR_AMOUNT_MISMATCH); } // Build one live transition that consumes a receipt, a DAO deposit, and a real limit order, then emits a new limit order plus a withdrawal pair: all three script families should compose cleanly when each sibling shape and amount is valid, so verification passes. @@ -177,46 +109,20 @@ fn all_three_scripts_can_compose_in_one_live_state_transition() { let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); - let receipt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &ickb_logic, 12).pack()) - .lock(owner_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_input = create_receipt(&mut context, &owner_lock, &ickb_logic, 1, deposit_amount); link_cell_to_header(&mut context, &receipt_input, &deposit_header); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_input).build()) - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(real_order_out_point).build()) + .input(input(receipt_input)) + .input(input(deposit_input)) + .input(input(real_order_out_point)) .outputs(vec![ - CellOutput::new_builder() - .capacity((1_400 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(1_400 * CKB, &limit_order, Some(&helper_type)), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -246,63 +152,34 @@ fn fresh_deposit_cannot_replace_a_withdrawn_deposit_at_its_index() { let amount = 1_500 * CKB; let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, amount); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); let deposit_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(amount)), - ); + let udt_input = create_udt(&mut context, &user_lock, &xudt, u128::from(amount)); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2 * deposit_total_capacity).pack()) - .lock(user_lock.clone()) - .build(), + cell(2 * deposit_total_capacity, &user_lock, None), Bytes::new(), ); let request = ( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(user_lock.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(deposit_total_capacity, &user_lock, Some(&dao)), withdrawal_request_data(1554), ); let fresh_deposit = ( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(deposit_total_capacity, &ickb_logic, Some(&dao)), dao_deposit_data(), ); let receipt = ( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), + cell(occupied_capacity(&user_lock, &ickb_logic, 12), &user_lock, Some(&ickb_logic)), receipt_data(1, amount), ); let tx = |outputs: Vec<(CellOutput, Bytes)>| { let (cells, data): (Vec<_>, Vec<_>) = outputs.into_iter().unzip(); let tx: TransactionView = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input.clone()).build()) - .input(CellInput::new_builder().previous_output(udt_input.clone()).build()) - .input(CellInput::new_builder().previous_output(funding_input.clone()).build()) + .input(input(deposit_input.clone())) + .input(input(udt_input.clone())) + .input(input(funding_input.clone())) .outputs(cells) .outputs_data(data.pack()) .header_dep(deposit_header.hash()) @@ -317,8 +194,7 @@ fn fresh_deposit_cannot_replace_a_withdrawn_deposit_at_its_index() { // Same cells with the two DAO outputs swapped: the fresh deposit takes the withdrawn deposit's index. let reset_in_place = context.complete_tx(tx(vec![fresh_deposit, request, receipt])); - let err = context.verify(&reset_in_place, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_DAO_INVALID_WITHDRAWING_CELL); + fail(&context, &reset_in_place, ERROR_DAO_INVALID_WITHDRAWING_CELL); } // Scenario 6G: a deposit and its receipt created in the same block read the same accumulated rate, @@ -332,47 +208,21 @@ fn same_block_receipt_and_deposit_mint_nothing_when_spent_together() { let amount = 1_500 * CKB; let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, amount); let creation_header = gen_header(1554, SYNTHETIC_WITHDRAW_AR, 35, 1000, 1000); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); - let receipt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, amount), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); + let receipt_input = create_receipt(&mut context, &user_lock, &ickb_logic, 1, amount); link_cell_to_header(&mut context, &deposit_input, &creation_header); link_cell_to_header(&mut context, &receipt_input, &creation_header); for minted in [0u128, 1] { let mut builder = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input.clone()).build()) - .input(CellInput::new_builder().previous_output(receipt_input.clone()).build()) - .output( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(user_lock.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - ) + .input(input(deposit_input.clone())) + .input(input(receipt_input.clone())) + .output(cell(deposit_total_capacity, &user_lock, Some(&dao))) .output_data(withdrawal_request_data(1554).pack()) .header_dep(creation_header.hash()); if minted > 0 { builder = builder - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - ) + .output(cell(occupied_capacity(&user_lock, &xudt, 16), &user_lock, Some(&xudt))) .output_data(udt_data(minted).pack()); } let tx = context.complete_tx(builder.build()); diff --git a/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs b/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs index 09f1bf6..54308b0 100644 --- a/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs +++ b/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs @@ -7,30 +7,19 @@ fn repeated_deposit_bucket_can_be_matched_by_one_multi_quantity_receipt() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((3_000 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(3_000 * CKB, &funding_lock, None), Bytes::new(), ); let deposit_amount = 1_000 * CKB; let deposit_data = dao_deposit_data(); let deposit_output = || { - CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, deposit_data.len(), deposit_amount).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build() + cell(deposit_capacity(&ickb_logic, &dao, deposit_data.len(), deposit_amount), &ickb_logic, Some(&dao)) }; - let receipt_output = CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock) - .type_(Some(ickb_logic.clone()).pack()) - .build(); + let receipt_output = cell(occupied_capacity(&funding_lock, &ickb_logic, 12), &funding_lock, Some(&ickb_logic)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![deposit_output(), deposit_output(), receipt_output]) .outputs_data(vec![deposit_data.clone(), deposit_data, receipt_data(2, deposit_amount)].pack()) .build(); @@ -49,25 +38,12 @@ fn multi_quantity_receipt_can_be_converted_in_phase2() { let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(2, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 2, deposit_amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(receipt_out_point)) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(u128::from(2 * deposit_amount)).pack()) .header_dep(receipt_header.clone()) .build(); diff --git a/scripts/tests/src/tests/ickb_logic/phase2_headers.rs b/scripts/tests/src/tests/ickb_logic/phase2_headers.rs index 40d3ea2..23d8122 100644 --- a/scripts/tests/src/tests/ickb_logic/phase2_headers.rs +++ b/scripts/tests/src/tests/ickb_logic/phase2_headers.rs @@ -8,31 +8,17 @@ fn phase2_conversion_without_receipt_header_dep_is_rejected() { let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, deposit_amount); insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(receipt_out_point)) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(u128::from(deposit_amount)).pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_ITEM_MISSING); + fail(&context, &tx, ERROR_ITEM_MISSING); } // Build one phase2 mint from two receipts that point at two different headers and supply both headers: multi-header conversion is allowed when every receipt has its own dependency, so verification passes. @@ -44,22 +30,8 @@ fn phase2_conversion_with_two_receipts_from_distinct_headers_passes() { let first_amount = 1_000 * CKB; let second_amount = 1_200 * CKB; - let first_receipt = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, first_amount), - ); - let second_receipt = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, second_amount), - ); + let first_receipt = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, first_amount); + let second_receipt = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, second_amount); let first_header = gen_header(0, GENESIS_AR as u64, 0, 0, 1); let second_header = gen_header(1, SYNTHETIC_WITHDRAW_AR, 1, 1, 1); link_cell_to_header(&mut context, &first_receipt, &first_header); @@ -68,15 +40,9 @@ fn phase2_conversion_with_two_receipts_from_distinct_headers_passes() { let expected = u128::from(first_amount) + (u128::from(second_amount) * u128::from(GENESIS_AR) / u128::from(SYNTHETIC_WITHDRAW_AR)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(first_receipt).build()) - .input(CellInput::new_builder().previous_output(second_receipt).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(first_receipt)) + .input(input(second_receipt)) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(expected).pack()) .header_dep(first_header.hash()) .header_dep(second_header.hash()) @@ -97,44 +63,23 @@ fn phase2_conversion_with_one_missing_receipt_header_dep_is_rejected() { let first_amount = 1_000 * CKB; let second_amount = 1_200 * CKB; - let first_receipt = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, first_amount), - ); - let second_receipt = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, second_amount), - ); + let first_receipt = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, first_amount); + let second_receipt = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, second_amount); let first_header = gen_header(0, GENESIS_AR as u64, 0, 0, 1); let second_header = gen_header(1, SYNTHETIC_WITHDRAW_AR, 1, 1, 1); link_cell_to_header(&mut context, &first_receipt, &first_header); link_cell_to_header(&mut context, &second_receipt, &second_header); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(first_receipt).build()) - .input(CellInput::new_builder().previous_output(second_receipt).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(first_receipt)) + .input(input(second_receipt)) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(u128::from(first_amount + second_amount)).pack()) .header_dep(first_header.hash()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_ITEM_MISSING); + fail(&context, &tx, ERROR_ITEM_MISSING); } // Build a phase2 conversion whose receipt header has accumulated rate zero: this is a malformed pricing header, so the conversion path panics instead of minting from an invalid rate. @@ -145,31 +90,17 @@ fn phase2_conversion_with_zero_accumulated_rate_header_is_rejected() { let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, deposit_amount); let malformed_header = gen_header(0, 0, 0, 0, 1); link_cell_to_header(&mut context, &receipt_out_point, &malformed_header); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(receipt_out_point)) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(u128::from(deposit_amount)).pack()) .header_dep(malformed_header.hash()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SCRIPT_PANIC); + fail(&context, &tx, ERROR_SCRIPT_PANIC); } diff --git a/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs b/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs index 4ab0f2f..96d7aa7 100644 --- a/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs +++ b/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs @@ -19,18 +19,8 @@ fn weak_lock_receipt_can_reassign_phase2_mint_recipient() { ); let tx = TransactionBuilder::default() - .input( - CellInput::new_builder() - .previous_output(receipt_out_point) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&attacker_lock, &xudt, 16).pack()) - .lock(attacker_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(receipt_out_point)) + .output(cell(occupied_capacity(&attacker_lock, &xudt, 16), &attacker_lock, Some(&xudt))) .output_data(udt_data(u128::from(deposit_amount)).pack()) .header_dep(receipt_header.clone()) .build(); @@ -50,25 +40,12 @@ fn sighash_lock_binds_phase2_mint_outputs_to_the_signed_transaction() { let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &ickb_logic, 12).pack()) - .lock(owner_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &owner_lock, &ickb_logic, 1, deposit_amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - ) + .input(input(receipt_out_point)) + .output(cell(occupied_capacity(&owner_lock, &xudt, 16), &owner_lock, Some(&xudt))) .output_data(udt_data(u128::from(deposit_amount)).pack()) .witness(empty_witness().pack()) .cell_dep(secp_data_dep) @@ -83,15 +60,10 @@ fn sighash_lock_binds_phase2_mint_outputs_to_the_signed_transaction() { let tampered_tx = tx .as_advanced_builder() .set_outputs(vec![ - CellOutput::new_builder() - .capacity(occupied_capacity(&attacker_lock, &xudt, 16).pack()) - .lock(attacker_lock) - .type_(Some(xudt).pack()) - .build(), + cell(occupied_capacity(&attacker_lock, &xudt, 16), &attacker_lock, Some(&xudt)), ]) .build(); - let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); + fail(&context, &tampered_tx, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } // Build one phase2 mint that mixes a signed receipt and a weak receipt into one xUDT output, then tamper the recipient after signing the strong input group: the signed tx passes, but the tampered version fails because one strong lock is enough to bind the shared outputs. @@ -105,22 +77,8 @@ fn mixed_sighash_and_weak_receipts_bind_all_phase2_outputs_once_signed() { let amount1 = 1_000 * CKB; let amount2 = 1_200 * CKB; - let receipt1 = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &ickb_logic, 12).pack()) - .lock(owner_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, amount1), - ); - let receipt2 = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&weak_lock, &ickb_logic, 12).pack()) - .lock(weak_lock) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, amount2), - ); + let receipt1 = create_receipt(&mut context, &owner_lock, &ickb_logic, 1, amount1); + let receipt2 = create_receipt(&mut context, &weak_lock, &ickb_logic, 1, amount2); let header1 = insert_header_for_cell(&mut context, &receipt1, 0, GENESIS_AR); let header2 = gen_header(1, SYNTHETIC_WITHDRAW_AR, 1, 1, 1); link_cell_to_header(&mut context, &receipt2, &header2); @@ -128,15 +86,9 @@ fn mixed_sighash_and_weak_receipts_bind_all_phase2_outputs_once_signed() { + (u128::from(amount2) * u128::from(GENESIS_AR) / u128::from(SYNTHETIC_WITHDRAW_AR)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt1).build()) - .input(CellInput::new_builder().previous_output(receipt2).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - ) + .input(input(receipt1)) + .input(input(receipt2)) + .output(cell(occupied_capacity(&owner_lock, &xudt, 16), &owner_lock, Some(&xudt))) .output_data(udt_data(expected).pack()) .witness(empty_witness().pack()) .witness(Bytes::new().pack()) @@ -153,15 +105,10 @@ fn mixed_sighash_and_weak_receipts_bind_all_phase2_outputs_once_signed() { let tampered_tx = tx .as_advanced_builder() .set_outputs(vec![ - CellOutput::new_builder() - .capacity(occupied_capacity(&attacker_lock, &xudt, 16).pack()) - .lock(attacker_lock) - .type_(Some(xudt).pack()) - .build(), + cell(occupied_capacity(&attacker_lock, &xudt, 16), &attacker_lock, Some(&xudt)), ]) .build(); - let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); + fail(&context, &tampered_tx, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } // Build one phase2 mint from two weakly locked receipts and pay the combined xUDT to an attacker lock: with no strong signer in the transaction, nothing binds the recipient, so reassignment is expected to pass. @@ -175,22 +122,8 @@ fn two_weak_receipts_can_reassign_combined_phase2_mint_recipient() { let amount1 = 1_000 * CKB; let amount2 = 1_200 * CKB; - let receipt1 = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&weak_lock_1, &ickb_logic, 12).pack()) - .lock(weak_lock_1) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, amount1), - ); - let receipt2 = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&weak_lock_2, &ickb_logic, 12).pack()) - .lock(weak_lock_2) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, amount2), - ); + let receipt1 = create_receipt(&mut context, &weak_lock_1, &ickb_logic, 1, amount1); + let receipt2 = create_receipt(&mut context, &weak_lock_2, &ickb_logic, 1, amount2); let header1 = insert_header_for_cell(&mut context, &receipt1, 0, GENESIS_AR); let header2 = gen_header(1, SYNTHETIC_WITHDRAW_AR, 1, 1, 1); link_cell_to_header(&mut context, &receipt2, &header2); @@ -198,15 +131,9 @@ fn two_weak_receipts_can_reassign_combined_phase2_mint_recipient() { + (u128::from(amount2) * u128::from(GENESIS_AR) / u128::from(SYNTHETIC_WITHDRAW_AR)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt1).build()) - .input(CellInput::new_builder().previous_output(receipt2).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&attacker_lock, &xudt, 16).pack()) - .lock(attacker_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(receipt1)) + .input(input(receipt2)) + .output(cell(occupied_capacity(&attacker_lock, &xudt, 16), &attacker_lock, Some(&xudt))) .output_data(udt_data(expected).pack()) .header_dep(header1) .header_dep(header2.hash()) diff --git a/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs b/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs index 8689e2a..a60dc6a 100644 --- a/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs +++ b/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs @@ -9,44 +9,26 @@ fn unrelated_non_empty_args_output_lock_poisons_phase2() { let poisoned_lock = data1_script(&mut context, "ickb_logic", Bytes::from(vec![1])); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, deposit_amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let extra_input = context.create_cell( - CellOutput::new_builder() - .capacity((500 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(500 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .input(CellInput::new_builder().previous_output(extra_input).build()) + .input(input(receipt_out_point)) + .input(input(extra_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(poisoned_lock) - .build(), + cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt)), + cell(200 * CKB, &poisoned_lock, None), ]) .outputs_data(vec![udt_data(u128::from(deposit_amount)), Bytes::new()].pack()) .header_dep(receipt_header.clone()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_NOT_EMPTY_ARGS); + fail(&context, &tx, ERROR_NOT_EMPTY_ARGS); } // Build a valid phase2 mint but add another output whose lock is the iCKB xUDT script itself: this sibling looks like script misuse rather than a normal foreign output, so verification fails. @@ -57,44 +39,26 @@ fn ickb_xudt_shaped_output_lock_poisons_phase2() { let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, deposit_amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let extra_input = context.create_cell( - CellOutput::new_builder() - .capacity((500 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(500 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .input(CellInput::new_builder().previous_output(extra_input).build()) + .input(input(receipt_out_point)) + .input(input(extra_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) - .lock(xudt) - .build(), + cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt)), + cell(capacity_for_data(16), &xudt, None), ]) .outputs_data(vec![udt_data(u128::from(deposit_amount)), udt_data(0)].pack()) .header_dep(receipt_header.clone()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SCRIPT_MISUSE); + fail(&context, &tx, ERROR_SCRIPT_MISUSE); } // Build a valid phase2 mint but add another output whose lock is the DAO script with deposit-shaped data: that sibling is an impossible lock shape the classifier rejects, so the transaction fails as misuse. @@ -105,44 +69,26 @@ fn dao_deposit_shaped_output_lock_poisons_phase2() { let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, deposit_amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let extra_input = context.create_cell( - CellOutput::new_builder() - .capacity((500 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(500 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .input(CellInput::new_builder().previous_output(extra_input).build()) + .input(input(receipt_out_point)) + .input(input(extra_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - CellOutput::new_builder() - .capacity(capacity_for_data(8).pack()) - .lock(dao) - .build(), + cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt)), + cell(capacity_for_data(8), &dao, None), ]) .outputs_data(vec![udt_data(u128::from(deposit_amount)), dao_deposit_data()].pack()) .header_dep(receipt_header.clone()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SCRIPT_MISUSE); + fail(&context, &tx, ERROR_SCRIPT_MISUSE); } // Build a valid phase2 mint plus a second output whose lock uses the same xUDT code under different args: the sibling is foreign to iCKB accounting, so the real mint should still pass. @@ -155,36 +101,19 @@ fn foreign_xudt_output_lock_is_ignored() { let foreign_xudt = xudt_script(&mut context, &foreign_owner); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, deposit_amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let extra_input = context.create_cell( - CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) - .lock(funding_lock.clone()) - .build(), + cell(capacity_for_data(16), &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .input(CellInput::new_builder().previous_output(extra_input).build()) + .input(input(receipt_out_point)) + .input(input(extra_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) - .lock(foreign_xudt) - .build(), + cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt)), + cell(capacity_for_data(16), &foreign_xudt, None), ]) .outputs_data(vec![udt_data(u128::from(deposit_amount)), udt_data(0)].pack()) .header_dep(receipt_header.clone()) @@ -206,37 +135,19 @@ fn foreign_xudt_type_output_is_ignored() { let foreign_xudt = xudt_script(&mut context, &foreign_owner); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, deposit_amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let extra_input = context.create_cell( - CellOutput::new_builder() - .capacity(capacity_for_data(16).pack()) - .lock(funding_lock.clone()) - .build(), + cell(capacity_for_data(16), &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .input(CellInput::new_builder().previous_output(extra_input).build()) + .input(input(receipt_out_point)) + .input(input(extra_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &foreign_xudt, 16).pack()) - .lock(funding_lock.clone()) - .type_(Some(foreign_xudt).pack()) - .build(), + cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt)), + cell(occupied_capacity(&funding_lock, &foreign_xudt, 16), &funding_lock, Some(&foreign_xudt)), ]) .outputs_data(vec![udt_data(u128::from(deposit_amount)), udt_data(0)].pack()) .header_dep(receipt_header.clone()) @@ -256,36 +167,19 @@ fn withdrawal_request_shaped_dao_output_lock_is_ignored() { let (ickb_logic, dao, xudt) = ickb_logic_dao_and_xudt_scripts(&mut context); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, deposit_amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let extra_input = context.create_cell( - CellOutput::new_builder() - .capacity(capacity_for_data(8).pack()) - .lock(funding_lock.clone()) - .build(), + cell(capacity_for_data(8), &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .input(CellInput::new_builder().previous_output(extra_input).build()) + .input(input(receipt_out_point)) + .input(input(extra_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - CellOutput::new_builder() - .capacity(capacity_for_data(8).pack()) - .lock(dao) - .build(), + cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt)), + cell(capacity_for_data(8), &dao, None), ]) .outputs_data(vec![udt_data(u128::from(deposit_amount)), withdrawal_request_data(1554)].pack()) .header_dep(receipt_header.clone()) @@ -308,45 +202,26 @@ fn deposit_shaped_non_empty_args_output_poisons_phase2() { let dao = dao_script(&mut context); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, deposit_amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let extra_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .input(CellInput::new_builder().previous_output(extra_input).build()) + .input(input(receipt_out_point)) + .input(input(extra_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - CellOutput::new_builder() - .capacity(deposit_capacity(&poisoned_lock, &dao, 8, deposit_amount).pack()) - .lock(poisoned_lock) - .type_(Some(dao).pack()) - .build(), + cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt)), + cell(deposit_capacity(&poisoned_lock, &dao, 8, deposit_amount), &poisoned_lock, Some(&dao)), ]) .outputs_data(vec![udt_data(u128::from(deposit_amount)), dao_deposit_data()].pack()) .header_dep(receipt_header.clone()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_NOT_EMPTY_ARGS); + fail(&context, &tx, ERROR_NOT_EMPTY_ARGS); } // Build a valid phase2 mint but include a second receipt input whose type script reuses ickb_logic code with non-empty args: sibling input classification sees an invalid receipt-shaped peer, so the whole mint fails on the args check. @@ -359,40 +234,19 @@ fn non_empty_args_receipt_sibling_poisons_phase2() { let xudt = xudt_script(&mut context, &ickb_logic); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, deposit_amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); - let poisoned_receipt = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &poisoned_receipt_type, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(poisoned_receipt_type).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let poisoned_receipt = create_receipt(&mut context, &funding_lock, &poisoned_receipt_type, 1, deposit_amount); insert_header_for_cell(&mut context, &poisoned_receipt, 0, GENESIS_AR); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .input(CellInput::new_builder().previous_output(poisoned_receipt).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(receipt_out_point)) + .input(input(poisoned_receipt)) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(u128::from(deposit_amount)).pack()) .header_dep(receipt_header) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_NOT_EMPTY_ARGS); + fail(&context, &tx, ERROR_NOT_EMPTY_ARGS); } diff --git a/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs b/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs index d0f1cef..2d33399 100644 --- a/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs +++ b/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs @@ -8,26 +8,15 @@ fn phase2_mint_accepts_xudt_data_with_trailing_bytes() { let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, deposit_amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let mut output_data = udt_data(u128::from(deposit_amount)).to_vec(); output_data.push(0xaa); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) + .input(input(receipt_out_point)) .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, output_data.len()).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), + cell(occupied_capacity(&funding_lock, &xudt, output_data.len()), &funding_lock, Some(&xudt)), ) .output_data(Bytes::from(output_data).pack()) .header_dep(receipt_header.clone()) @@ -47,32 +36,18 @@ fn phase2_mint_rejects_short_xudt_output_data() { let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, deposit_amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 8).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(receipt_out_point)) + .output(cell(occupied_capacity(&funding_lock, &xudt, 8), &funding_lock, Some(&xudt))) .output_data(truncated_bytes(udt_data(u128::from(deposit_amount)), 8).pack()) .header_dep(receipt_header.clone()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_ENCODING); + fail(&context, &tx, ERROR_ENCODING); } // Build a phase2 mint whose xUDT output data is empty: there is no encoded amount at all, so the output data shape is invalid and verification fails. @@ -83,30 +58,16 @@ fn phase2_mint_rejects_zero_length_xudt_output_data() { let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); let deposit_amount = 1_000 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, deposit_amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, deposit_amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 0).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(receipt_out_point)) + .output(cell(occupied_capacity(&funding_lock, &xudt, 0), &funding_lock, Some(&xudt))) .output_data(Bytes::new().pack()) .header_dep(receipt_header.clone()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_ENCODING); + fail(&context, &tx, ERROR_ENCODING); } diff --git a/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs b/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs index b84c2a9..4433310 100644 --- a/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs +++ b/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs @@ -7,27 +7,16 @@ fn receipt_trailing_bytes_do_not_change_creation_accounting() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); let deposit_amount = 1_000 * CKB; let deposit_data = dao_deposit_data(); - let deposit_output = CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, deposit_data.len(), deposit_amount).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao).pack()) - .build(); - let receipt_output = CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 15).pack()) - .lock(funding_lock) - .type_(Some(ickb_logic).pack()) - .build(); + let deposit_output = cell(deposit_capacity(&ickb_logic, &dao, deposit_data.len(), deposit_amount), &ickb_logic, Some(&dao)); + let receipt_output = cell(occupied_capacity(&funding_lock, &ickb_logic, 15), &funding_lock, Some(&ickb_logic)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![deposit_output, receipt_output]) .outputs_data( vec![ @@ -62,14 +51,8 @@ fn receipt_trailing_bytes_do_not_change_phase2_conversion() { ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(receipt_out_point)) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(u128::from(deposit_amount)).pack()) .header_dep(receipt_header.clone()) .build(); @@ -87,27 +70,16 @@ fn truncated_receipt_output_with_small_amount_is_rejected() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); let deposit_amount = 1_000 * CKB; let deposit_data = dao_deposit_data(); - let deposit_output = CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, deposit_data.len(), deposit_amount).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao).pack()) - .build(); - let receipt_output = CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 9).pack()) - .lock(funding_lock) - .type_(Some(ickb_logic).pack()) - .build(); + let deposit_output = cell(deposit_capacity(&ickb_logic, &dao, deposit_data.len(), deposit_amount), &ickb_logic, Some(&dao)); + let receipt_output = cell(occupied_capacity(&funding_lock, &ickb_logic, 9), &funding_lock, Some(&ickb_logic)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![deposit_output, receipt_output]) .outputs_data( vec![dao_deposit_data(), truncated_bytes(receipt_data(1, deposit_amount), 9)].pack(), @@ -115,8 +87,7 @@ fn truncated_receipt_output_with_small_amount_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_ENCODING); + fail(&context, &tx, ERROR_ENCODING); } // Build a phase2 mint from a live receipt input whose stored receipt payload is truncated to 9 bytes: conversion cannot decode the amount bucket, so verification fails on encoding. @@ -137,19 +108,12 @@ fn truncated_receipt_input_with_small_amount_is_rejected() { ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(receipt_out_point)) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(u128::from(deposit_amount)).pack()) .header_dep(receipt_header.clone()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_ENCODING); + fail(&context, &tx, ERROR_ENCODING); } diff --git a/scripts/tests/src/tests/ickb_logic/receipt_matching.rs b/scripts/tests/src/tests/ickb_logic/receipt_matching.rs index f9852cd..fc053ef 100644 --- a/scripts/tests/src/tests/ickb_logic/receipt_matching.rs +++ b/scripts/tests/src/tests/ickb_logic/receipt_matching.rs @@ -7,34 +7,22 @@ fn zero_quantity_receipt_is_rejected() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); let amount = 1_000 * CKB; - let deposit_output = CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao).pack()) - .build(); - let receipt_output = CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock) - .type_(Some(ickb_logic).pack()) - .build(); + let deposit_output = cell(deposit_capacity(&ickb_logic, &dao, 8, amount), &ickb_logic, Some(&dao)); + let receipt_output = cell(occupied_capacity(&funding_lock, &ickb_logic, 12), &funding_lock, Some(&ickb_logic)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![deposit_output, receipt_output]) .outputs_data(vec![dao_deposit_data(), receipt_data(0, amount)].pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_EMPTY_RECEIPT); + fail(&context, &tx, ERROR_EMPTY_RECEIPT); } // Build one deposit plus one receipt that claims quantity 2 for that deposit bucket: the receipt overstates how many equal deposits were created, so matching fails. @@ -44,34 +32,22 @@ fn forged_receipt_quantity_without_enough_deposits_is_rejected() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); let amount = 1_000 * CKB; - let deposit_output = CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, 8, amount).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao).pack()) - .build(); - let receipt_output = CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock) - .type_(Some(ickb_logic).pack()) - .build(); + let deposit_output = cell(deposit_capacity(&ickb_logic, &dao, 8, amount), &ickb_logic, Some(&dao)); + let receipt_output = cell(occupied_capacity(&funding_lock, &ickb_logic, 12), &funding_lock, Some(&ickb_logic)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![deposit_output, receipt_output]) .outputs_data(vec![dao_deposit_data(), receipt_data(2, amount)].pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_RECEIPT_MISMATCH); + fail(&context, &tx, ERROR_RECEIPT_MISMATCH); } // Build one 1000-CKB deposit plus one receipt that claims a 1001-CKB bucket: receipt matching is keyed by exact deposit amount, so the mismatched bucket is rejected. @@ -81,31 +57,19 @@ fn receipt_for_unmatched_deposit_amount_is_rejected() { let funding_lock = always_success_lock(&mut context); let (ickb_logic, dao) = ickb_logic_and_dao_scripts(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); - let deposit_output = CellOutput::new_builder() - .capacity(deposit_capacity(&ickb_logic, &dao, 8, 1_000 * CKB).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao).pack()) - .build(); - let receipt_output = CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock) - .type_(Some(ickb_logic).pack()) - .build(); + let deposit_output = cell(deposit_capacity(&ickb_logic, &dao, 8, 1_000 * CKB), &ickb_logic, Some(&dao)); + let receipt_output = cell(occupied_capacity(&funding_lock, &ickb_logic, 12), &funding_lock, Some(&ickb_logic)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![deposit_output, receipt_output]) .outputs_data(vec![dao_deposit_data(), receipt_data(1, 1_001 * CKB)].pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_RECEIPT_MISMATCH); + fail(&context, &tx, ERROR_RECEIPT_MISMATCH); } diff --git a/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs b/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs index b65412b..b3e25e1 100644 --- a/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs +++ b/scripts/tests/src/tests/ickb_logic/receiptless_deposit_blind_spot.rs @@ -10,22 +10,13 @@ fn receiptless_dao_shaped_output_is_accepted_as_deposit() { let deposit_amount = 1_500 * CKB; let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, deposit_amount); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(user_lock.clone()) - .build(), + cell(deposit_total_capacity, &user_lock, None), Bytes::new(), ); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .output( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - ) + .input(input(funding_input)) + .output(cell(deposit_total_capacity, &ickb_logic, Some(&dao))) .output_data(dao_deposit_data().pack()) .build(); @@ -34,36 +25,16 @@ fn receiptless_dao_shaped_output_is_accepted_as_deposit() { .verify(&create_tx, MAX_CYCLES) .expect("receiptless DAO-shaped ickb_logic output can be created at output-lock creation time"); - let receiptless_deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let receiptless_deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); let deposit_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); link_cell_to_header(&mut context, &receiptless_deposit_input, &deposit_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); + let udt_input = create_udt(&mut context, &user_lock, &xudt, u128::from(deposit_amount)); let withdraw_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receiptless_deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .output( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(user_lock) - .type_(Some(dao).pack()) - .build(), - ) + .input(input(receiptless_deposit_input)) + .input(input(udt_input)) + .output(cell(deposit_total_capacity, &user_lock, Some(&dao))) .output_data(withdrawal_request_data(1554).pack()) .header_dep(deposit_header.hash()) .build(); @@ -86,21 +57,12 @@ fn receiptless_deposits_below_the_minimum_are_created_and_withdrawn_at_value() { let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, deposit_amount); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(user_lock.clone()) - .build(), + cell(deposit_total_capacity, &user_lock, None), Bytes::new(), ); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .output( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - ) + .input(input(funding_input)) + .output(cell(deposit_total_capacity, &ickb_logic, Some(&dao))) .output_data(dao_deposit_data().pack()) .build(); let create_tx = context.complete_tx(create_tx); @@ -108,14 +70,7 @@ fn receiptless_deposits_below_the_minimum_are_created_and_withdrawn_at_value() { .verify(&create_tx, MAX_CYCLES) .expect("a receiptless deposit below the minimum is created without running the bounds check"); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); let deposit_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); link_cell_to_header(&mut context, &deposit_input, &deposit_header); @@ -126,26 +81,13 @@ fn receiptless_deposits_below_the_minimum_are_created_and_withdrawn_at_value() { } for burned in burns { let mut builder = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input.clone()).build()); + .input(input(deposit_input.clone())); if burned > 0 { - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - udt_data(burned), - ); - builder = builder.input(CellInput::new_builder().previous_output(udt_input).build()); + let udt_input = create_udt(&mut context, &user_lock, &xudt, burned); + builder = builder.input(input(udt_input)); } let withdraw_tx = builder - .output( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(user_lock.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - ) + .output(cell(deposit_total_capacity, &user_lock, Some(&dao))) .output_data(withdrawal_request_data(1554).pack()) .header_dep(deposit_header.hash()) .build(); @@ -179,21 +121,12 @@ fn split_receipt_against_receiptless_aggregate_mints_only_spread() { assert_eq!(delta, u128::from(10_000 * CKB)); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity(aggregate_total_capacity.pack()) - .lock(user_lock.clone()) - .build(), + cell(aggregate_total_capacity, &user_lock, None), Bytes::new(), ); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .output( - CellOutput::new_builder() - .capacity(aggregate_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - ) + .input(input(funding_input)) + .output(cell(aggregate_total_capacity, &ickb_logic, Some(&dao))) .output_data(dao_deposit_data().pack()) .build(); let create_tx = context.complete_tx(create_tx); @@ -201,44 +134,22 @@ fn split_receipt_against_receiptless_aggregate_mints_only_spread() { .verify(&create_tx, MAX_CYCLES) .expect("aggregate receiptless deposit creation is allowed at output-lock creation time"); - let receiptless_aggregate_deposit = context.create_cell( - CellOutput::new_builder() - .capacity(aggregate_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let receiptless_aggregate_deposit = create_deposit(&mut context, aggregate_total_capacity, &ickb_logic, &dao); let shared_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); link_cell_to_header(&mut context, &receiptless_aggregate_deposit, &shared_header); - let receipt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic).pack()) - .build(), - receipt_data(2, split_amount), - ); + let receipt_input = create_receipt(&mut context, &user_lock, &ickb_logic, 2, split_amount); link_cell_to_header(&mut context, &receipt_input, &shared_header); // The receipt contributes only the valuation delta between per-deposit and aggregate soft-cap treatment. // The separately funded aggregate principal stays in the DAO withdrawal output below. let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receiptless_aggregate_deposit).build()) - .input(CellInput::new_builder().previous_output(receipt_input).build()) - .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) + .input(input(receiptless_aggregate_deposit)) + .input(input(receipt_input)) + .input(input(funding_cell(&mut context))) .outputs(vec![ - CellOutput::new_builder() - .capacity(aggregate_total_capacity.pack()) - .lock(user_lock.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock) - .type_(Some(xudt).pack()) - .build(), + cell(aggregate_total_capacity, &user_lock, Some(&dao)), + cell(occupied_capacity(&user_lock, &xudt, 16), &user_lock, Some(&xudt)), ]) .outputs_data(vec![withdrawal_request_data(1554), udt_data(delta)].pack()) .header_dep(shared_header.hash()) @@ -253,8 +164,7 @@ fn split_receipt_against_receiptless_aggregate_mints_only_spread() { .as_advanced_builder() .set_outputs_data(vec![withdrawal_request_data(1554).pack(), udt_data(delta + 1).pack()]) .build(); - let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_AMOUNT_MISMATCH); + fail(&context, &tampered_tx, ERROR_AMOUNT_MISMATCH); } // Verify one continuous split-deposit receipt, receiptless creation, delta-only spread, and DAO phase2 claim trajectory: each later input keeps the preceding verified output's tx hash and index. @@ -273,34 +183,15 @@ fn verified_receiptless_creation_spread_and_claim_trajectory() { let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let split_funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2 * split_total_capacity + capacity_for_data(16)).pack()) - .lock(user_lock.clone()) - .build(), + cell(2 * split_total_capacity + capacity_for_data(16), &user_lock, None), Bytes::new(), ); let split_tx = TransactionBuilder::default() - .input( - CellInput::new_builder() - .previous_output(split_funding_input) - .build(), - ) + .input(input(split_funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(split_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(split_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), + cell(split_total_capacity, &ickb_logic, Some(&dao)), + cell(split_total_capacity, &ickb_logic, Some(&dao)), + cell(occupied_capacity(&user_lock, &ickb_logic, 12), &user_lock, Some(&ickb_logic)), ]) .outputs_data( vec![ @@ -328,21 +219,12 @@ fn verified_receiptless_creation_spread_and_claim_trajectory() { link_cell_to_header(&mut context, &receipt_input, &deposit_header); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity(aggregate_total_capacity.pack()) - .lock(user_lock.clone()) - .build(), + cell(aggregate_total_capacity, &user_lock, None), Bytes::new(), ); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .output( - CellOutput::new_builder() - .capacity(aggregate_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - ) + .input(input(funding_input)) + .output(cell(aggregate_total_capacity, &ickb_logic, Some(&dao))) .output_data(dao_deposit_data().pack()) .build(); let create_tx = context.complete_tx(create_tx); @@ -361,20 +243,12 @@ fn verified_receiptless_creation_spread_and_claim_trajectory() { // This is the same delta-only mint path as above, then a DAO phase2 claim. // The claim demonstrates that the self-funded aggregate principal stays spendable after minting only the spread. let mint_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receiptless_aggregate_deposit).build()) - .input(CellInput::new_builder().previous_output(receipt_input).build()) - .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) + .input(input(receiptless_aggregate_deposit)) + .input(input(receipt_input)) + .input(input(funding_cell(&mut context))) .outputs(vec![ - CellOutput::new_builder() - .capacity(aggregate_total_capacity.pack()) - .lock(user_lock.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(aggregate_total_capacity, &user_lock, Some(&dao)), + cell(occupied_capacity(&user_lock, &xudt, 16), &user_lock, Some(&xudt)), ]) .outputs_data(vec![withdrawal_request_data(1554), udt_data(delta)].pack()) .header_dep(deposit_header.hash()) @@ -407,12 +281,7 @@ fn verified_receiptless_creation_spread_and_claim_trajectory() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .output( - CellOutput::new_builder() - .capacity(claim_capacity.pack()) - .lock(user_lock) - .build(), - ) + .output(cell(claim_capacity, &user_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) @@ -436,37 +305,21 @@ fn receiptless_aggregate_alone_cannot_mint_spread() { let delta = u128::from(10_000 * CKB); let deposit_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); - let receiptless_aggregate_deposit = context.create_cell( - CellOutput::new_builder() - .capacity(aggregate_total_capacity.pack()) - .lock(ickb_logic) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let receiptless_aggregate_deposit = create_deposit(&mut context, aggregate_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &receiptless_aggregate_deposit, &deposit_header); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receiptless_aggregate_deposit).build()) + .input(input(receiptless_aggregate_deposit)) .outputs(vec![ - CellOutput::new_builder() - .capacity(aggregate_total_capacity.pack()) - .lock(user_lock.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock) - .type_(Some(xudt).pack()) - .build(), + cell(aggregate_total_capacity, &user_lock, Some(&dao)), + cell(occupied_capacity(&user_lock, &xudt, 16), &user_lock, Some(&xudt)), ]) .outputs_data(vec![withdrawal_request_data(1554), udt_data(delta)].pack()) .header_dep(deposit_header.hash()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_AMOUNT_MISMATCH); + fail(&context, &tx, ERROR_AMOUNT_MISMATCH); } // Build the same receiptless-aggregate-plus-split-receipt pattern at 20x size: the larger aggregate should still pass while realizing a proportionally larger soft-cap spread, showing the blind spot scales with aggregate size. @@ -485,21 +338,12 @@ fn oversized_receiptless_aggregate_realizes_larger_spread() { assert_eq!(delta, u128::from(190_000 * CKB)); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity(aggregate_total_capacity.pack()) - .lock(user_lock.clone()) - .build(), + cell(aggregate_total_capacity, &user_lock, None), Bytes::new(), ); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .output( - CellOutput::new_builder() - .capacity(aggregate_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - ) + .input(input(funding_input)) + .output(cell(aggregate_total_capacity, &ickb_logic, Some(&dao))) .output_data(dao_deposit_data().pack()) .build(); let create_tx = context.complete_tx(create_tx); @@ -507,42 +351,20 @@ fn oversized_receiptless_aggregate_realizes_larger_spread() { .verify(&create_tx, MAX_CYCLES) .expect("oversized aggregate receiptless deposit can still be created at output-lock creation time"); - let receiptless_aggregate_deposit = context.create_cell( - CellOutput::new_builder() - .capacity(aggregate_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let receiptless_aggregate_deposit = create_deposit(&mut context, aggregate_total_capacity, &ickb_logic, &dao); let shared_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); link_cell_to_header(&mut context, &receiptless_aggregate_deposit, &shared_header); - let receipt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &ickb_logic, 12).pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(quantity, split_amount), - ); + let receipt_input = create_receipt(&mut context, &user_lock, &ickb_logic, quantity, split_amount); link_cell_to_header(&mut context, &receipt_input, &shared_header); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receiptless_aggregate_deposit).build()) - .input(CellInput::new_builder().previous_output(receipt_input).build()) - .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) + .input(input(receiptless_aggregate_deposit)) + .input(input(receipt_input)) + .input(input(funding_cell(&mut context))) .outputs(vec![ - CellOutput::new_builder() - .capacity(aggregate_total_capacity.pack()) - .lock(user_lock.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock) - .type_(Some(xudt).pack()) - .build(), + cell(aggregate_total_capacity, &user_lock, Some(&dao)), + cell(occupied_capacity(&user_lock, &xudt, 16), &user_lock, Some(&xudt)), ]) .outputs_data(vec![withdrawal_request_data(1554), udt_data(delta)].pack()) .header_dep(shared_header.hash()) diff --git a/scripts/tests/src/tests/ickb_logic/soft_cap.rs b/scripts/tests/src/tests/ickb_logic/soft_cap.rs index 958115e..55c0d26 100644 --- a/scripts/tests/src/tests/ickb_logic/soft_cap.rs +++ b/scripts/tests/src/tests/ickb_logic/soft_cap.rs @@ -8,41 +8,21 @@ fn phase2_mint_applies_soft_cap_discount_above_boundary() { let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); let amount = 100_001 * CKB; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let naive_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point.clone()).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - ) + .input(input(receipt_out_point.clone())) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(u128::from(amount)).pack()) .header_dep(receipt_header.clone()) .build(); let naive_tx = context.complete_tx(naive_tx); - let err = context.verify(&naive_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_AMOUNT_MISMATCH); + fail(&context, &naive_tx, ERROR_AMOUNT_MISMATCH); let exact_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(receipt_out_point)) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(soft_capped_ickb(amount, GENESIS_AR)).pack()) .header_dep(receipt_header.clone()) .build(); @@ -62,25 +42,12 @@ fn phase2_mint_does_not_discount_at_soft_cap_boundary() { let amount = 100_000 * CKB; assert_eq!(soft_capped_ickb(amount, GENESIS_AR), u128::from(amount)); - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic).pack()) - .build(), - receipt_data(1, amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(receipt_out_point)) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(u128::from(amount)).pack()) .header_dep(receipt_header) .build(); @@ -100,14 +67,7 @@ fn multi_quantity_phase2_mint_applies_soft_cap_per_deposit() { let amount = 100_001 * CKB; let quantity = 2u32; - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(quantity, amount), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, quantity, amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let exact = u128::from(quantity) * soft_capped_ickb(amount, GENESIS_AR); let total_raw = u128::from(quantity) * u128::from(amount); @@ -116,30 +76,17 @@ fn multi_quantity_phase2_mint_applies_soft_cap_per_deposit() { assert!(exact > naive_aggregate); let naive_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point.clone()).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - ) + .input(input(receipt_out_point.clone())) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(naive_aggregate).pack()) .header_dep(receipt_header.clone()) .build(); let naive_tx = context.complete_tx(naive_tx); - let err = context.verify(&naive_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_AMOUNT_MISMATCH); + fail(&context, &naive_tx, ERROR_AMOUNT_MISMATCH); let exact_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(receipt_out_point)) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(exact).pack()) .header_dep(receipt_header.clone()) .build(); @@ -159,20 +106,10 @@ fn mixed_phase1_phase2_still_apply_soft_cap_per_receipt() { let amount = 100_001 * CKB; let quantity = 2u32; let deposit_output_capacity = deposit_capacity(&ickb_logic, &dao, 8, amount); - let receipt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(quantity, amount), - ); + let receipt_input = create_receipt(&mut context, &funding_lock, &ickb_logic, quantity, amount); let receipt_header = insert_header_for_cell(&mut context, &receipt_input, 0, GENESIS_AR); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((300_000 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(300_000 * CKB, &funding_lock, None), Bytes::new(), ); @@ -184,29 +121,13 @@ fn mixed_phase1_phase2_still_apply_soft_cap_per_receipt() { let build_tx = |udt_amount: u128| { TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input.clone()).build()) - .input(CellInput::new_builder().previous_output(receipt_input.clone()).build()) + .input(input(funding_input.clone())) + .input(input(receipt_input.clone())) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_output_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(deposit_output_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(deposit_output_capacity, &ickb_logic, Some(&dao)), + cell(deposit_output_capacity, &ickb_logic, Some(&dao)), + cell(occupied_capacity(&funding_lock, &ickb_logic, 12), &funding_lock, Some(&ickb_logic)), + cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt)), ]) .outputs_data( vec![ @@ -222,8 +143,7 @@ fn mixed_phase1_phase2_still_apply_soft_cap_per_receipt() { }; let naive_tx = context.complete_tx(build_tx(naive_aggregate)); - let err = context.verify(&naive_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_AMOUNT_MISMATCH); + fail(&context, &naive_tx, ERROR_AMOUNT_MISMATCH); let exact_tx = context.complete_tx(build_tx(exact)); context diff --git a/scripts/tests/src/tests/ickb_logic/xudt_amount_limits.rs b/scripts/tests/src/tests/ickb_logic/xudt_amount_limits.rs index 2a3693d..fe04387 100644 --- a/scripts/tests/src/tests/ickb_logic/xudt_amount_limits.rs +++ b/scripts/tests/src/tests/ickb_logic/xudt_amount_limits.rs @@ -8,39 +8,22 @@ fn oversized_output_udt_amount_is_rejected() { let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((1_000 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(1_000 * CKB, &funding_lock, None), Bytes::new(), ); - let receipt_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - receipt_data(1, 1_000 * CKB), - ); + let receipt_out_point = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, 1_000 * CKB); let receipt_header = insert_header_for_cell(&mut context, &receipt_out_point, 0, GENESIS_AR); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(funding_input)) + .input(input(receipt_out_point)) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .outputs_data(vec![udt_data(u128::from(u64::MAX) + 1)].pack()) .header_dep(receipt_header.clone()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_AMOUNT_UNREASONABLY_BIG); + fail(&context, &tx, ERROR_AMOUNT_UNREASONABLY_BIG); } // Build a plain xUDT transfer that keeps the amount exactly at `u64::MAX`: this is the accepted numeric boundary, so the tx should pass unchanged. @@ -50,24 +33,11 @@ fn xudt_amount_at_u64_max_boundary_is_allowed() { let user_lock = always_success_lock(&mut context); let (_, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - udt_data(u128::from(u64::MAX)), - ); + let udt_input = create_udt(&mut context, &user_lock, &xudt, u128::from(u64::MAX)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(udt_input).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(udt_input)) + .output(cell(occupied_capacity(&user_lock, &xudt, 16), &user_lock, Some(&xudt))) .output_data(udt_data(u128::from(u64::MAX)).pack()) .build(); diff --git a/scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs b/scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs index 536165d..0a8e385 100644 --- a/scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs +++ b/scripts/tests/src/tests/ickb_logic/xudt_owner_witness_fallback.rs @@ -8,30 +8,20 @@ fn xudt_owner_script_output_witness_cannot_mint_without_live_owner_mode() { let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((500 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(500 * CKB, &funding_lock, None), Bytes::new(), ); let witness = witness_with_output_type(xudt_owner_script_witness(ickb_logic)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(funding_input)) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(1).pack()) .witness(witness.pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_XUDT_AMOUNT); + fail(&context, &tx, ERROR_XUDT_AMOUNT); } // Build a plain xUDT self-transfer that increases the amount while supplying the xUDT owner-script witness in `input_type`: without a live iCKB owner-mode route, the fallback witness still cannot authorize minting, so verification fails. @@ -41,30 +31,16 @@ fn xudt_owner_script_input_witness_cannot_mint_without_live_owner_mode() { let user_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - udt_data(1), - ); + let udt_input = create_udt(&mut context, &user_lock, &xudt, 1); let witness = witness_with_input_type(xudt_owner_script_witness(ickb_logic)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(udt_input).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock) - .type_(Some(xudt).pack()) - .build(), - ) + .input(input(udt_input)) + .output(cell(occupied_capacity(&user_lock, &xudt, 16), &user_lock, Some(&xudt))) .output_data(udt_data(2).pack()) .witness(witness.pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_XUDT_AMOUNT); + fail(&context, &tx, ERROR_XUDT_AMOUNT); } diff --git a/scripts/tests/src/tests/limit_order/crosswire_blockers.rs b/scripts/tests/src/tests/limit_order/crosswire_blockers.rs index 3060d69..4a6dbfa 100644 --- a/scripts/tests/src/tests/limit_order/crosswire_blockers.rs +++ b/scripts/tests/src/tests/limit_order/crosswire_blockers.rs @@ -23,19 +23,11 @@ fn distinct_mint_capacities_block_master_crosswire() { let crosswired_order1_data = order_data_match(100 * CKB as u128, &master2_input, (1, 1)); let crosswired_order2_data = order_data_match(100 * CKB as u128, &master1_input, (1, 1)); let crosswire_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order1_input).build()) - .input(CellInput::new_builder().previous_output(order2_input).build()) + .input(input(order1_input)) + .input(input(order2_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity((1_400 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), + cell(1_500 * CKB, &limit_order, Some(&helper_type)), + cell(1_400 * CKB, &limit_order, Some(&helper_type)), ]) .outputs_data(vec![crosswired_order1_data.clone(), crosswired_order2_data].pack()) .build(); @@ -73,14 +65,8 @@ fn distinct_match_progress_blocks_master_crosswire() { let order1_matched_data = order_data_match(100 * CKB as u128, &master1_input, (1, 1)); let order1_match_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order1_input).build()) - .output( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - ) + .input(input(order1_input)) + .output(cell(1_500 * CKB, &limit_order, Some(&helper_type))) .output_data(order1_matched_data.clone().pack()) .build(); let order1_match_tx = context.complete_tx(order1_match_tx); @@ -96,14 +82,8 @@ fn distinct_match_progress_blocks_master_crosswire() { let order2_matched_data = order_data_match(200 * CKB as u128, &master2_input, (1, 1)); let order2_match_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order2_input).build()) - .output( - CellOutput::new_builder() - .capacity((1_300 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - ) + .input(input(order2_input)) + .output(cell(1_300 * CKB, &limit_order, Some(&helper_type))) .output_data(order2_matched_data.clone().pack()) .build(); let order2_match_tx = context.complete_tx(order2_match_tx); @@ -120,19 +100,11 @@ fn distinct_match_progress_blocks_master_crosswire() { let crosswired_order1_data = order_data_match(200 * CKB as u128, &master2_input, (1, 1)); let crosswired_order2_data = order_data_match(300 * CKB as u128, &master1_input, (1, 1)); let crosswire_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order1_matched).build()) - .input(CellInput::new_builder().previous_output(order2_matched).build()) + .input(input(order1_matched)) + .input(input(order2_matched)) .outputs(vec![ - CellOutput::new_builder() - .capacity((1_400 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity((1_200 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), + cell(1_400 * CKB, &limit_order, Some(&helper_type)), + cell(1_200 * CKB, &limit_order, Some(&helper_type)), ]) .outputs_data(vec![crosswired_order1_data.clone(), crosswired_order2_data].pack()) .build(); @@ -170,14 +142,8 @@ fn real_mint_and_match_orders_cannot_crosswire_masters() { let match_order_data = order_data_match(100 * CKB as u128, &master2_input, (1, 1)); let seed_match_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(match_order_seed).build()) - .output( - CellOutput::new_builder() - .capacity((1_400 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - ) + .input(input(match_order_seed)) + .output(cell(1_400 * CKB, &limit_order, Some(&helper_type))) .output_data(match_order_data.clone().pack()) .build(); let seed_match_tx = context.complete_tx(seed_match_tx); @@ -194,19 +160,11 @@ fn real_mint_and_match_orders_cannot_crosswire_masters() { let crosswired_mint_data = order_data_match(100 * CKB as u128, &master2_input, (1, 1)); let crosswired_match_data = order_data_match(200 * CKB as u128, &master1_input, (1, 1)); let crosswire_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(mint_order_input).build()) - .input(CellInput::new_builder().previous_output(match_order_input).build()) + .input(input(mint_order_input)) + .input(input(match_order_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity((1_300 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), + cell(1_500 * CKB, &limit_order, Some(&helper_type)), + cell(1_300 * CKB, &limit_order, Some(&helper_type)), ]) .outputs_data(vec![crosswired_mint_data.clone(), crosswired_match_data].pack()) .build(); @@ -251,40 +209,24 @@ fn different_info_mainnet_orders_cannot_crosswire_during_match() { context.create_cell_with_out_point( master_a_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(owner_a_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), + cell(u64_from_hex("0x23c346000"), &owner_a_lock, Some(&limit_order)), Bytes::new(), ); context.create_cell_with_out_point( master_b_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x230489e00").pack()) - .lock(owner_b_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), + cell(u64_from_hex("0x230489e00"), &owner_b_lock, Some(&limit_order)), Bytes::new(), ); context.create_cell_with_out_point( order_a_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x641d5c5e1c4").pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(u64_from_hex("0x641d5c5e1c4"), &limit_order, Some(&helper_type)), bytes_from_hex( "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000c16ff28623005b03be74cf7a2a000000000000000000000000000000000021", ), ); context.create_cell_with_out_point( order_b_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x4a221e700").pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(u64_from_hex("0x4a221e700"), &limit_order, Some(&helper_type)), bytes_from_hex( "0xff2222085e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff000000000000000000000000000000000000c16ff28623000a1338d4d7672a0021", ), @@ -329,23 +271,12 @@ fn different_info_mainnet_orders_cannot_crosswire_during_match() { ); let crosswire_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order_a_input).build()) - .input(CellInput::new_builder().previous_output(order_b_input).build()) + .input(input(order_a_input)) + .input(input(order_b_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0x4a221e700").pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x74deeef1ad").pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x5ccf6d6f017").pack()) - .lock(change_lock) - .build(), + cell(u64_from_hex("0x4a221e700"), &limit_order, Some(&helper_type)), + cell(u64_from_hex("0x74deeef1ad"), &limit_order, Some(&helper_type)), + cell(u64_from_hex("0x5ccf6d6f017"), &change_lock, None), ]) .outputs_data( vec![ @@ -358,6 +289,5 @@ fn different_info_mainnet_orders_cannot_crosswire_during_match() { .build(); let crosswire_tx = context.complete_tx(crosswire_tx); - let err = context.verify(&crosswire_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_DIFFERENT_INFO); + fail(&context, &crosswire_tx, ERROR_LIMIT_ORDER_DIFFERENT_INFO); } diff --git a/scripts/tests/src/tests/limit_order/crosswire_live_match.rs b/scripts/tests/src/tests/limit_order/crosswire_live_match.rs index 84ec4a1..44620bd 100644 --- a/scripts/tests/src/tests/limit_order/crosswire_live_match.rs +++ b/scripts/tests/src/tests/limit_order/crosswire_live_match.rs @@ -16,19 +16,11 @@ fn cloned_live_orders_can_permute_without_stranding_either_master() { let matched_order1_data = order_data_match(100 * CKB as u128, &master2_input, (1, 1)); let matched_order2_data = order_data_match(100 * CKB as u128, &master1_input, (1, 1)); let crosswire_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order1_input).build()) - .input(CellInput::new_builder().previous_output(order2_input).build()) + .input(input(order1_input)) + .input(input(order2_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity((1_400 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity((1_400 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), + cell(1_400 * CKB, &limit_order, Some(&helper_type)), + cell(1_400 * CKB, &limit_order, Some(&helper_type)), ]) .outputs_data(vec![matched_order1_data.clone(), matched_order2_data.clone()].pack()) .build(); @@ -43,14 +35,9 @@ fn cloned_live_orders_can_permute_without_stranding_either_master() { let crosswired_order2 = seed_verified_output(&mut context, &crosswire_tx, 1, matched_order2_data); let rebound_melt = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(crosswired_order1.clone()).build()) - .input(CellInput::new_builder().previous_output(master2_input.clone()).build()) - .output( - CellOutput::new_builder() - .capacity((1_600 * CKB).pack()) - .lock(owner2_lock.clone()) - .build(), - ) + .input(input(crosswired_order1.clone())) + .input(input(master2_input.clone())) + .output(cell(1_600 * CKB, &owner2_lock, None)) .output_data(Bytes::new().pack()) .witness(Bytes::new().pack()) .witness(empty_witness().pack()) @@ -62,14 +49,9 @@ fn cloned_live_orders_can_permute_without_stranding_either_master() { .expect("the alternate master can melt the permuted cloned continuation after the metapoint swap"); let other_melt = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(crosswired_order2).build()) - .input(CellInput::new_builder().previous_output(master1_input).build()) - .output( - CellOutput::new_builder() - .capacity((1_600 * CKB).pack()) - .lock(owner1_lock) - .build(), - ) + .input(input(crosswired_order2)) + .input(input(master1_input)) + .output(cell(1_600 * CKB, &owner1_lock, None)) .output_data(Bytes::new().pack()) .witness(Bytes::new().pack()) .witness(empty_witness().pack()) @@ -93,30 +75,18 @@ fn hybrid_fake_and_real_limit_order_match_keeps_real_master_on_real_metapoint() let limit_order = limit_order_script(&mut context); let fake_master = OutPoint::new(Byte32::from_slice(&[7u8; 32]).expect("byte32"), 9); let fake_order_input = context.create_cell( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(1_500 * CKB, &limit_order, Some(&helper_type)), order_data_match(0, &fake_master, (1, 1)), ); let real_lineage_data = order_data_match(100 * CKB as u128, &real_master_input, (1, 1)); let fake_lineage_data = order_data_match(100 * CKB as u128, &fake_master, (1, 1)); let hybrid_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(fake_order_input).build()) - .input(CellInput::new_builder().previous_output(real_order_input).build()) + .input(input(fake_order_input)) + .input(input(real_order_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity((1_400 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity((1_400 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), + cell(1_400 * CKB, &limit_order, Some(&helper_type)), + cell(1_400 * CKB, &limit_order, Some(&helper_type)), ]) .outputs_data(vec![real_lineage_data.clone(), fake_lineage_data.clone()].pack()) .build(); @@ -141,14 +111,9 @@ fn hybrid_fake_and_real_limit_order_match_keeps_real_master_on_real_metapoint() ); let real_lineage_melt = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(real_lineage_output).build()) - .input(CellInput::new_builder().previous_output(real_master_input.clone()).build()) - .output( - CellOutput::new_builder() - .capacity((1_600 * CKB).pack()) - .lock(owner_lock.clone()) - .build(), - ) + .input(input(real_lineage_output)) + .input(input(real_master_input.clone())) + .output(cell(1_600 * CKB, &owner_lock, None)) .output_data(Bytes::new().pack()) .witness(Bytes::new().pack()) .witness(empty_witness().pack()) @@ -160,14 +125,9 @@ fn hybrid_fake_and_real_limit_order_match_keeps_real_master_on_real_metapoint() .expect("the real master should still authorize the melt on the real metapoint in the hybrid match"); let fake_lineage_melt_with_real_master = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(fake_lineage_output).build()) - .input(CellInput::new_builder().previous_output(real_master_input).build()) - .output( - CellOutput::new_builder() - .capacity((1_600 * CKB).pack()) - .lock(owner_lock) - .build(), - ) + .input(input(fake_lineage_output)) + .input(input(real_master_input)) + .output(cell(1_600 * CKB, &owner_lock, None)) .output_data(Bytes::new().pack()) .witness(Bytes::new().pack()) .witness(empty_witness().pack()) @@ -179,8 +139,5 @@ fn hybrid_fake_and_real_limit_order_match_keeps_real_master_on_real_metapoint() 1, 1, ); - let err = context - .verify(&fake_lineage_melt_with_real_master, MAX_CYCLES) - .unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); + fail(&context, &fake_lineage_melt_with_real_master, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } diff --git a/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs b/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs index 6a20233..cd8a5a6 100644 --- a/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs +++ b/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs @@ -9,36 +9,17 @@ fn mint_crosswire_swaps_order_masters() { let (owner2_lock, helper_type) = named_lock_and_helper_type_scripts(&mut context, b"owner2"); let limit_order = limit_order_script(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((4_000 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(4_000 * CKB, &funding_lock, None), Bytes::new(), ); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner1_lock, &limit_order, 0).pack()) - .lock(owner1_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner2_lock, &limit_order, 0).pack()) - .lock(owner2_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), + cell(1_500 * CKB, &limit_order, Some(&helper_type)), + cell(occupied_capacity(&owner1_lock, &limit_order, 0), &owner1_lock, Some(&limit_order)), + cell(1_500 * CKB, &limit_order, Some(&helper_type)), + cell(occupied_capacity(&owner2_lock, &limit_order, 0), &owner2_lock, Some(&limit_order)), ]) .outputs_data( vec![ @@ -83,14 +64,9 @@ fn mint_crosswire_swaps_order_masters() { ); let melt_other_users_order = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order2).build()) - .input(CellInput::new_builder().previous_output(master1.clone()).build()) - .output( - CellOutput::new_builder() - .capacity((1_700 * CKB).pack()) - .lock(owner1_lock) - .build(), - ) + .input(input(order2)) + .input(input(master1.clone())) + .output(cell(1_700 * CKB, &owner1_lock, None)) .output_data(Bytes::new().pack()) .build(); let melt_other_users_order = context.complete_tx(melt_other_users_order); @@ -99,19 +75,13 @@ fn mint_crosswire_swaps_order_masters() { .expect("master1 is bound to order2 when mint distances are cross-wired"); let melt_expected_order = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order1).build()) - .input(CellInput::new_builder().previous_output(master1).build()) - .output( - CellOutput::new_builder() - .capacity((1_700 * CKB).pack()) - .lock(owner2_lock) - .build(), - ) + .input(input(order1)) + .input(input(master1)) + .output(cell(1_700 * CKB, &owner2_lock, None)) .output_data(Bytes::new().pack()) .build(); let melt_expected_order = context.complete_tx(melt_expected_order); - let err = context.verify(&melt_expected_order, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); + fail(&context, &melt_expected_order, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } // Create the same crosswire through sparse output spacing and negative distances; limit_order runs at mint and accepts the crosswired distances, and the far paired master remains the valid melt path. @@ -124,64 +94,33 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { let (filler_lock, helper_type) = named_lock_and_helper_type_scripts(&mut context, b"filler"); let limit_order = limit_order_script(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((8_000 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(8_000 * CKB, &funding_lock, None), Bytes::new(), ); let mut outputs = vec![ - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(1_500 * CKB, &limit_order, Some(&helper_type)), ]; let mut outputs_data = vec![order_data_mint(0, 11, (1, 1))]; for _ in 0..8 { - outputs.push( - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(filler_lock.clone()) - .build(), - ); + outputs.push(cell(100 * CKB, &filler_lock, None)); outputs_data.push(Bytes::new()); } - outputs.push( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - ); + outputs.push(cell(1_500 * CKB, &limit_order, Some(&helper_type))); outputs_data.push(order_data_mint(0, 3, (1, 1))); - outputs.push( - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(filler_lock) - .build(), - ); + outputs.push(cell(100 * CKB, &filler_lock, None)); outputs_data.push(Bytes::new()); outputs.push( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner2_lock, &limit_order, 0).pack()) - .lock(owner2_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), + cell(occupied_capacity(&owner2_lock, &limit_order, 0), &owner2_lock, Some(&limit_order)), ); outputs_data.push(Bytes::new()); outputs.push( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner1_lock, &limit_order, 0).pack()) - .lock(owner1_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), + cell(occupied_capacity(&owner1_lock, &limit_order, 0), &owner1_lock, Some(&limit_order)), ); outputs_data.push(Bytes::new()); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(outputs) .outputs_data(outputs_data.pack()) .build(); @@ -218,14 +157,9 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { ); let melt_crosswired = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order1.clone()).build()) - .input(CellInput::new_builder().previous_output(master2.clone()).build()) - .output( - CellOutput::new_builder() - .capacity((1_700 * CKB).pack()) - .lock(owner2_lock) - .build(), - ) + .input(input(order1.clone())) + .input(input(master2.clone())) + .output(cell(1_700 * CKB, &owner2_lock, None)) .output_data(Bytes::new().pack()) .build(); @@ -235,19 +169,13 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { .expect("far-distance sparse layout still binds order1 to owner2's master"); let melt_expected = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order1).build()) - .input(CellInput::new_builder().previous_output(master1).build()) - .output( - CellOutput::new_builder() - .capacity((1_700 * CKB).pack()) - .lock(owner1_lock) - .build(), - ) + .input(input(order1)) + .input(input(master1)) + .output(cell(1_700 * CKB, &owner1_lock, None)) .output_data(Bytes::new().pack()) .build(); let melt_expected = context.complete_tx(melt_expected); - let err = context.verify(&melt_expected, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); + fail(&context, &melt_expected, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } // A master's type script runs at mint and pairs every order with exactly one master: one order per @@ -260,24 +188,16 @@ fn mint_pairs_each_order_with_exactly_one_master() { let (_, helper_type) = named_lock_and_helper_type_scripts(&mut context, b"owner"); let limit_order = limit_order_script(&mut context); let order = || { - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build() + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)) }; let master = || { - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) - .lock(owner_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build() + cell(occupied_capacity(&owner_lock, &limit_order, 0), &owner_lock, Some(&limit_order)) }; let mut mint = |outputs: Vec<(CellOutput, Bytes)>| { let funding = funding_cell(&mut context); let (cells, data): (Vec<_>, Vec<_>) = outputs.into_iter().unzip(); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding).build()) + .input(input(funding)) .outputs(cells) .outputs_data(data.pack()) .build(); @@ -302,10 +222,7 @@ fn mint_pairs_each_order_with_exactly_one_master() { ]); assert_script_error(master_without_order.unwrap_err(), ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); - let plain = CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(owner_lock.clone()) - .build(); + let plain = cell(100 * CKB, &owner_lock, None); let order_without_master = mint(vec![ (order(), order_data_mint(0, 1, (1, 1))), (master(), Bytes::new()), diff --git a/scripts/tests/src/tests/limit_order/fake_match_lineage.rs b/scripts/tests/src/tests/limit_order/fake_match_lineage.rs index 8189ef7..d5358b7 100644 --- a/scripts/tests/src/tests/limit_order/fake_match_lineage.rs +++ b/scripts/tests/src/tests/limit_order/fake_match_lineage.rs @@ -8,23 +8,13 @@ fn fake_match_lineage_can_keep_advancing_without_real_master() { let fake_master = OutPoint::new(Byte32::from_slice(&[7u8; 32]).expect("byte32"), 9); let initial_order = context.create_cell( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(1_500 * CKB, &limit_order, Some(&helper_type)), order_data_match(0, &fake_master, (1, 1)), ); let first_match_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(initial_order).build()) - .output( - CellOutput::new_builder() - .capacity((1_400 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - ) + .input(input(initial_order)) + .output(cell(1_400 * CKB, &limit_order, Some(&helper_type))) .output_data(order_data_match(100 * CKB as u128, &fake_master, (1, 1)).pack()) .build(); @@ -41,14 +31,8 @@ fn fake_match_lineage_can_keep_advancing_without_real_master() { ); let second_match_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(first_match_out_point).build()) - .output( - CellOutput::new_builder() - .capacity((1_300 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - ) + .input(input(first_match_out_point)) + .output(cell(1_300 * CKB, &limit_order, Some(&helper_type))) .output_data(order_data_match(200 * CKB as u128, &fake_master, (1, 1)).pack()) .build(); @@ -66,25 +50,14 @@ fn foreign_token_fake_order_with_arbitrary_info_can_strand_real_order() { let limit_order = limit_order_script(&mut context); let funding_lock = always_success_lock(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((1_700 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(1_700 * CKB, &funding_lock, None), Bytes::new(), ); let mint_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) - .lock(owner_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), + cell(1_500 * CKB, &limit_order, Some(&helper_type)), + cell(occupied_capacity(&owner_lock, &limit_order, 0), &owner_lock, Some(&limit_order)), ]) .outputs_data(vec![order_data_mint(0, 1, (1, 1)), Bytes::new()].pack()) .build(); @@ -112,31 +85,14 @@ fn foreign_token_fake_order_with_arbitrary_info_can_strand_real_order() { 42, ); let phantom_order_out_point = context.create_cell( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order) - .type_(Some(foreign_token).pack()) - .build(), + cell(1_500 * CKB, &limit_order, Some(&foreign_token)), fake_data, ); let tx = TransactionBuilder::default() - .input( - CellInput::new_builder() - .previous_output(phantom_order_out_point) - .build(), - ) - .input( - CellInput::new_builder() - .previous_output(real_master_out_point.clone()) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity((1_700 * CKB).pack()) - .lock(owner_lock) - .build(), - ) + .input(input(phantom_order_out_point)) + .input(input(real_master_out_point.clone())) + .output(cell(1_700 * CKB, &owner_lock, None)) .output_data(Bytes::new().pack()) .build(); @@ -146,20 +102,10 @@ fn foreign_token_fake_order_with_arbitrary_info_can_strand_real_order() { .expect("a foreign-token fake order with arbitrary pricing should melt against the referenced real master"); let stranded_order_tx = TransactionBuilder::default() - .input( - CellInput::new_builder() - .previous_output(real_order_out_point) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(always_success_lock(&mut context)) - .build(), - ) + .input(input(real_order_out_point)) + .output(cell(1_500 * CKB, &always_success_lock(&mut context), None)) .output_data(Bytes::new().pack()) .build(); let stranded_order_tx = context.complete_tx(stranded_order_tx); - let err = context.verify(&stranded_order_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); + fail(&context, &stranded_order_tx, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } diff --git a/scripts/tests/src/tests/limit_order/fulfilled.rs b/scripts/tests/src/tests/limit_order/fulfilled.rs index dba7669..8cfa17e 100644 --- a/scripts/tests/src/tests/limit_order/fulfilled.rs +++ b/scripts/tests/src/tests/limit_order/fulfilled.rs @@ -8,29 +8,20 @@ fn fulfilled_ckb_to_udt_shape_fails_as_invalid_match() { let master = OutPoint::new(Byte32::zero(), 5); let input_order = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 0).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 0), &limit_order, Some(&helper_type)), order_data_match(0, &master, (1, 1)), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order).build()) + .input(input(input_order)) .output( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 0).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 0), &limit_order, Some(&helper_type)), ) .output_data(order_data_match(1, &master, (1, 1)).pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_MATCH); + fail(&context, &tx, ERROR_LIMIT_ORDER_INVALID_MATCH); } // Forge a fulfilled UDT->CKB-shaped cell and try to continue it; this shape never reaches the inner fulfilled guard and instead fails the outer match validation. @@ -40,34 +31,20 @@ fn fulfilled_udt_to_ckb_shape_cannot_reach_guard_and_fails_as_invalid_match() { let (funding_lock, limit_order, helper_type) = funding_limit_order_and_helper_type_scripts(&mut context); let input_order = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_custom(0, 1, [0u8; 32], 5u32.to_le_bytes(), (0, 0), (1, 1), 4), ); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(100 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(input_order)) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - CellOutput::new_builder() - .capacity((80 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB), &limit_order, Some(&helper_type)), + cell(80 * CKB, &funding_lock, None), ]) .outputs_data( vec![ @@ -81,6 +58,5 @@ fn fulfilled_udt_to_ckb_shape_cannot_reach_guard_and_fails_as_invalid_match() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_MATCH); + fail(&context, &tx, ERROR_LIMIT_ORDER_INVALID_MATCH); } diff --git a/scripts/tests/src/tests/limit_order/lock_only_shapes.rs b/scripts/tests/src/tests/limit_order/lock_only_shapes.rs index 99f33d9..79da5d1 100644 --- a/scripts/tests/src/tests/limit_order/lock_only_shapes.rs +++ b/scripts/tests/src/tests/limit_order/lock_only_shapes.rs @@ -8,21 +8,14 @@ fn non_empty_args_output_lock_can_be_created_but_not_spent() { let limit_order_non_empty = data1_script(&mut context, "limit_order", Bytes::from(vec![1])); let helper_type = helper_type_script(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .output( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order_non_empty, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order_non_empty.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order_non_empty, &helper_type, 89, 1_500 * CKB), &limit_order_non_empty, Some(&helper_type)), ) .output_data(order_data_mint(0, 1, (1, 1)).pack()) .build(); @@ -32,26 +25,16 @@ fn non_empty_args_output_lock_can_be_created_but_not_spent() { .expect("non-empty-args limit_order output lock can be created because output locks do not execute"); let out_point = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order_non_empty, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order_non_empty.clone()) - .type_(Some(helper_type).pack()) - .build(), + cell(deposit_capacity(&limit_order_non_empty, &helper_type, 89, 1_500 * CKB), &limit_order_non_empty, Some(&helper_type)), order_data_mint(0, 1, (1, 1)), ); let spend_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(out_point).build()) - .output( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(always_success_lock(&mut context)) - .build(), - ) + .input(input(out_point)) + .output(cell(1_500 * CKB, &always_success_lock(&mut context), None)) .output_data(Bytes::new().pack()) .build(); let spend_tx = context.complete_tx(spend_tx); - let err = context.verify(&spend_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_NOT_EMPTY_ARGS); + fail(&context, &spend_tx, ERROR_NOT_EMPTY_ARGS); } // Forge a cell that uses `limit_order` as both lock and type so the type script executes immediately and rejects the misuse at creation. @@ -61,28 +44,20 @@ fn cell_using_limit_order_as_both_lock_and_type_is_rejected() { let funding_lock = always_success_lock(&mut context); let limit_order = limit_order_script(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&limit_order, &limit_order, 0).pack()) - .lock(limit_order.clone()) - .type_(Some(limit_order).pack()) - .build(), + cell(occupied_capacity(&limit_order, &limit_order, 0), &limit_order, Some(&limit_order)), ) .output_data(Bytes::new().pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_SCRIPT_MISUSE); + fail(&context, &tx, ERROR_LIMIT_ORDER_SCRIPT_MISUSE); } // Create a lock-only output with undecodable order bytes, then spend it and fail once the input lock parses the malformed payload. @@ -160,15 +135,12 @@ fn lock_only_limit_order_missing_udt_type_returns_typed_error_at_valid_capacity( .expect("occupied capacity") .as_u64(); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(200 * CKB, &funding_lock, None), Bytes::new(), ); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .output( forged_output .clone() @@ -188,19 +160,13 @@ fn lock_only_limit_order_missing_udt_type_returns_typed_error_at_valid_capacity( order_data_custom(0, 0, [0u8; 32], 5i32.to_le_bytes(), (1, 1), (0, 0), 0), ); let spend_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(forged_out_point).build()) - .output( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(always_success_lock(&mut context)) - .build(), - ) + .input(input(forged_out_point)) + .output(cell(200 * CKB, &always_success_lock(&mut context), None)) .output_data(Bytes::new().pack()) .build(); let spend_tx = context.complete_tx(spend_tx); - let err = context.verify(&spend_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_MISSING_UDT_TYPE); + fail(&context, &spend_tx, ERROR_LIMIT_ORDER_MISSING_UDT_TYPE); } // Create a lock-only output with valid mint data plus trailing bytes, then spend it and fail on the input-side length check. diff --git a/scripts/tests/src/tests/limit_order/master_admission.rs b/scripts/tests/src/tests/limit_order/master_admission.rs index 4211931..1196e63 100644 --- a/scripts/tests/src/tests/limit_order/master_admission.rs +++ b/scripts/tests/src/tests/limit_order/master_admission.rs @@ -9,28 +9,15 @@ fn mint_accepts_master_with_unspendable_foreign_lock() { let limit_order = limit_order_script(&mut context); let poisoned_lock = data1_script(&mut context, "ickb_logic", Bytes::from(vec![1])); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) + .output(cell(1_500 * CKB, &limit_order, Some(&helper_type))) .output( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type).pack()) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&poisoned_lock, &limit_order, 0).pack()) - .lock(poisoned_lock) - .type_(Some(limit_order.clone()).pack()) - .build(), + cell(occupied_capacity(&poisoned_lock, &limit_order, 0), &poisoned_lock, Some(&limit_order)), ) .outputs_data(vec![order_data_mint(0, 1, (1, 1)), Bytes::new()].pack()) .build(); @@ -55,20 +42,14 @@ fn mint_accepts_master_with_unspendable_foreign_lock() { ); let melt_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order_out_point).build()) - .input(CellInput::new_builder().previous_output(master_out_point).build()) - .output( - CellOutput::new_builder() - .capacity((1_700 * CKB).pack()) - .lock(always_success_lock(&mut context)) - .build(), - ) + .input(input(order_out_point)) + .input(input(master_out_point)) + .output(cell(1_700 * CKB, &always_success_lock(&mut context), None)) .output_data(Bytes::new().pack()) .build(); let melt_tx = context.complete_tx(melt_tx); - let err = context.verify(&melt_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_NOT_EMPTY_ARGS); + fail(&context, &melt_tx, ERROR_NOT_EMPTY_ARGS); } // Mint a real pair whose master uses `ickb_logic` with empty args; creation still skips the master lock, and melt later fails when that foreign script executes. @@ -80,28 +61,15 @@ fn mint_accepts_master_with_empty_args_ickb_logic_lock_and_strands_on_spend() { let limit_order = limit_order_script(&mut context); let benign_foreign_lock = ickb_logic_script(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) + .output(cell(1_500 * CKB, &limit_order, Some(&helper_type))) .output( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type).pack()) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&benign_foreign_lock, &limit_order, 0).pack()) - .lock(benign_foreign_lock) - .type_(Some(limit_order.clone()).pack()) - .build(), + cell(occupied_capacity(&benign_foreign_lock, &limit_order, 0), &benign_foreign_lock, Some(&limit_order)), ) .outputs_data(vec![order_data_mint(0, 1, (1, 1)), Bytes::new()].pack()) .build(); @@ -126,18 +94,12 @@ fn mint_accepts_master_with_empty_args_ickb_logic_lock_and_strands_on_spend() { ); let melt_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order_out_point).build()) - .input(CellInput::new_builder().previous_output(master_out_point).build()) - .output( - CellOutput::new_builder() - .capacity((1_700 * CKB).pack()) - .lock(always_success_lock(&mut context)) - .build(), - ) + .input(input(order_out_point)) + .input(input(master_out_point)) + .output(cell(1_700 * CKB, &always_success_lock(&mut context), None)) .output_data(Bytes::new().pack()) .build(); let melt_tx = context.complete_tx(melt_tx); - let err = context.verify(&melt_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SCRIPT_MISUSE); + fail(&context, &melt_tx, ERROR_SCRIPT_MISUSE); } diff --git a/scripts/tests/src/tests/limit_order/match_progression.rs b/scripts/tests/src/tests/limit_order/match_progression.rs index 43592c7..a3bc7e7 100644 --- a/scripts/tests/src/tests/limit_order/match_progression.rs +++ b/scripts/tests/src/tests/limit_order/match_progression.rs @@ -7,34 +7,20 @@ fn udt_to_ckb_match_passes() { let (funding_lock, limit_order, helper_type) = funding_limit_order_and_helper_type_scripts(&mut context); let input_order = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_custom(100, 1, [0u8; 32], 5u32.to_le_bytes(), (0, 0), (1, 1), 4), ); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(100 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(input_order)) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - CellOutput::new_builder() - .capacity((80 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB), &limit_order, Some(&helper_type)), + cell(80 * CKB, &funding_lock, None), ]) .outputs_data( vec![ @@ -58,34 +44,20 @@ fn udt_to_ckb_match_accepts_exact_minimum_partial_fill() { let (funding_lock, limit_order, helper_type) = funding_limit_order_and_helper_type_scripts(&mut context); let input_order = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_custom(100, 1, [0u8; 32], 5u32.to_le_bytes(), (0, 0), (1, 1), 4), ); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(100 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(input_order)) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_516 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - CellOutput::new_builder() - .capacity((84 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_516 * CKB), &limit_order, Some(&helper_type)), + cell(84 * CKB, &funding_lock, None), ]) .outputs_data( vec![ @@ -111,39 +83,21 @@ fn valid_match_ignores_foreign_typed_output() { let foreign_type = named_always_success_lock(&mut context, b"foreign-type"); let input_order = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_custom(100, 1, [0u8; 32], 5u32.to_le_bytes(), (0, 0), (1, 1), 4), ); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((300 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(300 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(input_order)) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - CellOutput::new_builder() - .capacity((80 * CKB).pack()) - .lock(funding_lock) - .build(), - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(foreign_lock) - .type_(Some(foreign_type).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB), &limit_order, Some(&helper_type)), + cell(80 * CKB, &funding_lock, None), + cell(200 * CKB, &foreign_lock, Some(&foreign_type)), ]) .outputs_data( vec![ @@ -168,28 +122,17 @@ fn ckb_to_udt_match_passes_with_both_ratios_present() { let (funding_lock, limit_order, helper_type) = funding_limit_order_and_helper_type_scripts(&mut context); let input_order = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_custom(0, 1, [0u8; 32], 5u32.to_le_bytes(), (1, 1), (1, 1), 4), ); // The matcher collects the 20 CKB into its own funding cell, which a bare 20 CKB cell could not hold. let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order).build()) - .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) + .input(input(input_order)) + .input(input(funding_cell(&mut context))) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_480 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - CellOutput::new_builder() - .capacity((1_020 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_480 * CKB), &limit_order, Some(&helper_type)), + cell(1_020 * CKB, &funding_lock, None), ]) .outputs_data( vec![ @@ -221,22 +164,14 @@ fn ckb_to_udt_match_accepts_exact_minimum_partial_fill() { let (limit_order, helper_type) = limit_order_and_helper_type_scripts(&mut context); let input_order_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_custom(0, 1, [0u8; 32], 5u32.to_le_bytes(), (1, 1), (0, 0), 4), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order_out_point).build()) + .input(input(input_order_out_point)) .output( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB - 16).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB - 16), &limit_order, Some(&helper_type)), ) .output_data(order_data_custom(16, 1, [0u8; 32], 5u32.to_le_bytes(), (1, 1), (0, 0), 4).pack()) .build(); @@ -254,34 +189,20 @@ fn udt_to_ckb_match_rejects_small_udt_delta_under_minimum() { let (funding_lock, limit_order, helper_type) = funding_limit_order_and_helper_type_scripts(&mut context); let input_order = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_custom(100, 1, [0u8; 32], 5u32.to_le_bytes(), (0, 0), (1, 1), 8), ); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(100 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(input_order)) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - CellOutput::new_builder() - .capacity((80 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB), &limit_order, Some(&helper_type)), + cell(80 * CKB, &funding_lock, None), ]) .outputs_data( vec![ @@ -293,8 +214,7 @@ fn udt_to_ckb_match_rejects_small_udt_delta_under_minimum() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INSUFFICIENT_MATCH); + fail(&context, &tx, ERROR_LIMIT_ORDER_INSUFFICIENT_MATCH); } // Continue a UDT->CKB order whose `ckb_min_match_log` demands a larger fill than the delta shown; the match path rejects the insufficient continuation. @@ -304,34 +224,20 @@ fn udt_to_ckb_match_rejects_large_minimum_partial_fill() { let (funding_lock, limit_order, helper_type) = funding_limit_order_and_helper_type_scripts(&mut context); let input_order = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_custom(100, 1, [0u8; 32], 5u32.to_le_bytes(), (0, 0), (1, 1), 40), ); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(100 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(input_order)) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - CellOutput::new_builder() - .capacity((80 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB), &limit_order, Some(&helper_type)), + cell(80 * CKB, &funding_lock, None), ]) .outputs_data( vec![ @@ -343,8 +249,7 @@ fn udt_to_ckb_match_rejects_large_minimum_partial_fill() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INSUFFICIENT_MATCH); + fail(&context, &tx, ERROR_LIMIT_ORDER_INSUFFICIENT_MATCH); } // Continue a match-shaped order while reversing progress in the wrong direction; the match path rejects the inconsistent state transition. @@ -355,29 +260,20 @@ fn match_rejects_invalid_direction_change() { let master = OutPoint::new(Byte32::zero(), 5); let input_order_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_match(100 * CKB as u128, &master, (1, 1)), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order_out_point).build()) + .input(input(input_order_out_point)) .output( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_400 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_400 * CKB), &limit_order, Some(&helper_type)), ) .output_data(order_data_match(50 * CKB as u128, &master, (1, 1)).pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_MATCH); + fail(&context, &tx, ERROR_LIMIT_ORDER_INVALID_MATCH); } // Re-emit a match-shaped order without changing capacity or matched amount; the match path rejects the no-op continuation. @@ -388,29 +284,20 @@ fn match_rejects_unchanged_shape() { let master = OutPoint::new(Byte32::zero(), 5); let input_order_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_match(100 * CKB as u128, &master, (1, 1)), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order_out_point).build()) + .input(input(input_order_out_point)) .output( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), ) .output_data(order_data_match(100 * CKB as u128, &master, (1, 1)).pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_MATCH); + fail(&context, &tx, ERROR_LIMIT_ORDER_INVALID_MATCH); } // Continue a match-shaped order while reducing total order value; the match path catches the decreasing-value transition. @@ -421,29 +308,20 @@ fn match_rejects_decreasing_value() { let master = OutPoint::new(Byte32::zero(), 5); let input_order_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_match(0, &master, (1, 1)), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order_out_point).build()) + .input(input(input_order_out_point)) .output( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_400 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_400 * CKB), &limit_order, Some(&helper_type)), ) .output_data(order_data_match(50 * CKB as u128, &master, (1, 1)).pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_DECREASING_VALUE); + fail(&context, &tx, ERROR_LIMIT_ORDER_DECREASING_VALUE); } // Continue a CKB->UDT order by less than its minimum partial fill; the match path rejects the too-small delta. @@ -453,29 +331,20 @@ fn match_rejects_too_small_partial_fill() { let (limit_order, helper_type) = limit_order_and_helper_type_scripts(&mut context); let input_order_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_custom(0, 1, [0u8; 32], 5u32.to_le_bytes(), (1, 1), (0, 0), 4), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order_out_point).build()) + .input(input(input_order_out_point)) .output( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB - 8).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB - 8), &limit_order, Some(&helper_type)), ) .output_data(order_data_custom(8, 1, [0u8; 32], 5u32.to_le_bytes(), (1, 1), (0, 0), 4).pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INSUFFICIENT_MATCH); + fail(&context, &tx, ERROR_LIMIT_ORDER_INSUFFICIENT_MATCH); } // Fully fill a CKB->UDT order down to its exact occupied capacity; terminal fills bypass the partial-fill minimum. @@ -485,22 +354,14 @@ fn ckb_to_udt_terminal_full_fill_passes_at_occupied_capacity() { let (limit_order, helper_type) = limit_order_and_helper_type_scripts(&mut context); let input_order_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 8).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 8), &limit_order, Some(&helper_type)), order_data_custom(0, 1, [0u8; 32], 5u32.to_le_bytes(), (1, 1), (0, 0), 4), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order_out_point).build()) + .input(input(input_order_out_point)) .output( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 0).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 0), &limit_order, Some(&helper_type)), ) .output_data(order_data_custom(8, 1, [0u8; 32], 5u32.to_le_bytes(), (1, 1), (0, 0), 4).pack()) .build(); diff --git a/scripts/tests/src/tests/limit_order/mint_shape_validation.rs b/scripts/tests/src/tests/limit_order/mint_shape_validation.rs index f9c179a..ceee610 100644 --- a/scripts/tests/src/tests/limit_order/mint_shape_validation.rs +++ b/scripts/tests/src/tests/limit_order/mint_shape_validation.rs @@ -9,28 +9,15 @@ fn mint_accepts_ckb_min_match_log_64() { let limit_order = limit_order_script(&mut context); let helper_type = helper_type_script(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) + .output(cell(1_500 * CKB, &limit_order, Some(&helper_type))) .output( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type).pack()) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) - .lock(owner_lock) - .type_(Some(limit_order).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &limit_order, 0), &owner_lock, Some(&limit_order)), ) .outputs_data( vec![ @@ -56,28 +43,15 @@ fn mint_rejects_ckb_min_match_log_65() { let limit_order = limit_order_script(&mut context); let helper_type = helper_type_script(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .output( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type).pack()) - .build(), - ) + .input(input(funding_input)) + .output(cell(1_500 * CKB, &limit_order, Some(&helper_type))) .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) - .lock(owner_lock) - .type_(Some(limit_order).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &limit_order, 0), &owner_lock, Some(&limit_order)), ) .outputs_data( vec![ @@ -89,8 +63,7 @@ fn mint_rejects_ckb_min_match_log_65() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CKB_MIN_MATCH_LOG); + fail(&context, &tx, ERROR_LIMIT_ORDER_INVALID_CKB_MIN_MATCH_LOG); } // Create two would-be master outputs and no order output; the creation path fails as invalid configuration before any duplicate-master-specific conclusion applies. @@ -101,31 +74,19 @@ fn two_master_outputs_fail_as_invalid_configuration_not_duplicate_master() { let owner_lock = named_always_success_lock(&mut context, b"owner"); let limit_order = limit_order_script(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((1_000 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(1_000 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) - .lock(owner_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) - .lock(owner_lock) - .type_(Some(limit_order).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &limit_order, 0), &owner_lock, Some(&limit_order)), + cell(occupied_capacity(&owner_lock, &limit_order, 0), &owner_lock, Some(&limit_order)), ]) .outputs_data(vec![Bytes::new(), Bytes::new()].pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); + fail(&context, &tx, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } diff --git a/scripts/tests/src/tests/limit_order/phantom_lineage.rs b/scripts/tests/src/tests/limit_order/phantom_lineage.rs index be78425..56c4691 100644 --- a/scripts/tests/src/tests/limit_order/phantom_lineage.rs +++ b/scripts/tests/src/tests/limit_order/phantom_lineage.rs @@ -7,22 +7,13 @@ fn phantom_mint_output_can_be_created() { let (funding_lock, limit_order, helper_type) = funding_limit_order_and_helper_type_scripts(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .output( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - ) + .input(input(funding_input)) + .output(cell(1_500 * CKB, &limit_order, Some(&helper_type))) .output_data(order_data_mint(0, 5, (1, 1)).pack()) .build(); @@ -39,28 +30,14 @@ fn phantom_mint_lineage_can_enter_match_without_real_master() { let (limit_order, helper_type) = limit_order_and_helper_type_scripts(&mut context); let phantom_order_out_point = context.create_cell( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(1_500 * CKB, &limit_order, Some(&helper_type)), order_data_mint(0, 5, (1, 1)), ); let phantom_master_out_point = OutPoint::new(phantom_order_out_point.tx_hash(), 5); let tx = TransactionBuilder::default() - .input( - CellInput::new_builder() - .previous_output(phantom_order_out_point) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity((1_400 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - ) + .input(input(phantom_order_out_point)) + .output(cell(1_400 * CKB, &limit_order, Some(&helper_type))) .output_data(order_data_match(100 * CKB as u128, &phantom_master_out_point, (1, 1)).pack()) .build(); @@ -77,34 +54,19 @@ fn phantom_mint_lineage_cannot_rebind_to_an_arbitrary_fake_match_master() { let (limit_order, helper_type) = limit_order_and_helper_type_scripts(&mut context); let phantom_order_out_point = context.create_cell( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(1_500 * CKB, &limit_order, Some(&helper_type)), order_data_mint(0, 5, (1, 1)), ); let fake_master = OutPoint::new(Byte32::from_slice(&[7u8; 32]).expect("byte32"), 9); let tx = TransactionBuilder::default() - .input( - CellInput::new_builder() - .previous_output(phantom_order_out_point) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity((1_400 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - ) + .input(input(phantom_order_out_point)) + .output(cell(1_400 * CKB, &limit_order, Some(&helper_type))) .output_data(order_data_match(100 * CKB as u128, &fake_master, (1, 1)).pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); + fail(&context, &tx, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } // Continue a phantom mint into match state while changing its ratio info; the match path still enforces same-order info and rejects the rewrite. @@ -114,34 +76,19 @@ fn phantom_limit_order_match_still_requires_same_order_info() { let (limit_order, helper_type) = limit_order_and_helper_type_scripts(&mut context); let phantom_order_out_point = context.create_cell( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(1_500 * CKB, &limit_order, Some(&helper_type)), order_data_mint(0, 5, (1, 1)), ); let phantom_master_out_point = OutPoint::new(phantom_order_out_point.tx_hash(), 5); let tx = TransactionBuilder::default() - .input( - CellInput::new_builder() - .previous_output(phantom_order_out_point) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity((1_400 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - ) + .input(input(phantom_order_out_point)) + .output(cell(1_400 * CKB, &limit_order, Some(&helper_type))) .output_data(order_data_match(100 * CKB as u128, &phantom_master_out_point, (2, 1)).pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_DIFFERENT_INFO); + fail(&context, &tx, ERROR_LIMIT_ORDER_DIFFERENT_INFO); } // Try to melt a phantom mint without any master input; the melt path rejects because no matching master lock/type pair is present. @@ -151,32 +98,18 @@ fn phantom_limit_order_cannot_be_melted_without_a_master_input() { let (limit_order, helper_type) = limit_order_and_helper_type_scripts(&mut context); let phantom_order_out_point = context.create_cell( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), + cell(1_500 * CKB, &limit_order, Some(&helper_type)), order_data_mint(0, 5, (1, 1)), ); let tx = TransactionBuilder::default() - .input( - CellInput::new_builder() - .previous_output(phantom_order_out_point) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(always_success_lock(&mut context)) - .build(), - ) + .input(input(phantom_order_out_point)) + .output(cell(1_500 * CKB, &always_success_lock(&mut context), None)) .output_data(Bytes::new().pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); + fail(&context, &tx, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } // Try to melt a phantom mint against an unrelated real master cell; the melt path rejects because the derived metapoint does not match that master. @@ -187,45 +120,23 @@ fn phantom_limit_order_cannot_be_melted_with_an_unrelated_master() { let owner_lock = named_always_success_lock(&mut context, b"owner"); let phantom_order_out_point = context.create_cell( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(1_500 * CKB, &limit_order, Some(&helper_type)), order_data_mint(0, 5, (1, 1)), ); let unrelated_master_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) - .lock(owner_lock.clone()) - .type_(Some(limit_order).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &limit_order, 0), &owner_lock, Some(&limit_order)), Bytes::new(), ); let tx = TransactionBuilder::default() - .input( - CellInput::new_builder() - .previous_output(phantom_order_out_point) - .build(), - ) - .input( - CellInput::new_builder() - .previous_output(unrelated_master_out_point) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity((1_700 * CKB).pack()) - .lock(owner_lock) - .build(), - ) + .input(input(phantom_order_out_point)) + .input(input(unrelated_master_out_point)) + .output(cell(1_700 * CKB, &owner_lock, None)) .output_data(Bytes::new().pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); + fail(&context, &tx, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } // Create a lock-only output that already carries match data and a fake master; creation succeeds because output locks do not execute. @@ -236,23 +147,14 @@ fn lock_only_limit_order_output_can_be_created_with_match_order_data() { let helper_type = helper_type_script(&mut context); let limit_order = limit_order_script(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); let fake_master = OutPoint::new(Byte32::from_slice(&[7u8; 32]).expect("byte32"), 9); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .output( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - ) + .input(input(funding_input)) + .output(cell(1_500 * CKB, &limit_order, Some(&helper_type))) .output_data(order_data_match(0, &fake_master, (1, 1)).pack()) .build(); diff --git a/scripts/tests/src/tests/limit_order/poisoning.rs b/scripts/tests/src/tests/limit_order/poisoning.rs index 1633106..5959f07 100644 --- a/scripts/tests/src/tests/limit_order/poisoning.rs +++ b/scripts/tests/src/tests/limit_order/poisoning.rs @@ -8,38 +8,21 @@ fn unrelated_non_empty_args_output_lock_poisons_match() { let poisoned_lock = data1_script(&mut context, "limit_order", Bytes::from(vec![1])); let input_order = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_custom(100, 1, [0u8; 32], 5u32.to_le_bytes(), (0, 0), (1, 1), 4), ); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(100 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(input_order)) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - CellOutput::new_builder() - .capacity((80 * CKB).pack()) - .lock(funding_lock) - .build(), - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(poisoned_lock) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB), &limit_order, Some(&helper_type)), + cell(80 * CKB, &funding_lock, None), + cell(200 * CKB, &poisoned_lock, None), ]) .outputs_data( vec![ @@ -52,8 +35,7 @@ fn unrelated_non_empty_args_output_lock_poisons_match() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_NOT_EMPTY_ARGS); + fail(&context, &tx, ERROR_NOT_EMPTY_ARGS); } // Run the same valid match while also creating a plausible order-shaped output under non-empty-args `limit_order`; the extra output lock still executes and aborts the tx. @@ -66,39 +48,21 @@ fn order_shaped_non_empty_args_output_poisons_match() { let helper_type = helper_type_script(&mut context); let input_order = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_custom(100, 1, [0u8; 32], 5u32.to_le_bytes(), (0, 0), (1, 1), 4), ); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((400 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(400 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(input_order)) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity((80 * CKB).pack()) - .lock(funding_lock) - .build(), - CellOutput::new_builder() - .capacity(deposit_capacity(&poisoned_lock, &helper_type, 89, 300 * CKB).pack()) - .lock(poisoned_lock) - .type_(Some(helper_type).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB), &limit_order, Some(&helper_type)), + cell(80 * CKB, &funding_lock, None), + cell(deposit_capacity(&poisoned_lock, &helper_type, 89, 300 * CKB), &poisoned_lock, Some(&helper_type)), ]) .outputs_data( vec![ @@ -111,8 +75,7 @@ fn order_shaped_non_empty_args_output_poisons_match() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_NOT_EMPTY_ARGS); + fail(&context, &tx, ERROR_NOT_EMPTY_ARGS); } // Run a valid match but include an unrelated master sibling whose type is non-empty-args `limit_order`; that extra input-side script executes and poisons verification. @@ -126,43 +89,25 @@ fn non_empty_args_master_sibling_poisons_match() { let helper_type = helper_type_script(&mut context); let input_order = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_custom(100, 1, [0u8; 32], 5u32.to_le_bytes(), (0, 0), (1, 1), 4), ); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(funding_lock.clone()) - .build(), + cell(100 * CKB, &funding_lock, None), Bytes::new(), ); let poisoned_master_input = context.create_cell( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(owner_lock) - .type_(Some(poisoned_master_type).pack()) - .build(), + cell(200 * CKB, &owner_lock, Some(&poisoned_master_type)), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) - .input(CellInput::new_builder().previous_output(poisoned_master_input).build()) + .input(input(input_order)) + .input(input(funding_input)) + .input(input(poisoned_master_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - CellOutput::new_builder() - .capacity((80 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_520 * CKB), &limit_order, Some(&helper_type)), + cell(80 * CKB, &funding_lock, None), ]) .outputs_data( vec![ @@ -174,6 +119,5 @@ fn non_empty_args_master_sibling_poisons_match() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_NOT_EMPTY_ARGS); + fail(&context, &tx, ERROR_NOT_EMPTY_ARGS); } diff --git a/scripts/tests/src/tests/limit_order/real_lineage.rs b/scripts/tests/src/tests/limit_order/real_lineage.rs index da25a94..1d8b2b1 100644 --- a/scripts/tests/src/tests/limit_order/real_lineage.rs +++ b/scripts/tests/src/tests/limit_order/real_lineage.rs @@ -12,24 +12,13 @@ fn real_order_match_cannot_rewrite_master_outpoint_to_an_arbitrary_master() { let limit_order = limit_order_script(&mut context); let tx = TransactionBuilder::default() - .input( - CellInput::new_builder() - .previous_output(real_order_out_point) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type.clone()).pack()) - .build(), - ) + .input(input(real_order_out_point)) + .output(cell(1_500 * CKB, &limit_order, Some(&helper_type))) .output_data(order_data_match(100 * CKB as u128, &victim_master_out_point, (1, 1)).pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); + fail(&context, &tx, ERROR_LIMIT_ORDER_INVALID_CONFIGURATION); } // Continue a real mint-state order into its first match state without spending the master cell; the match path accepts the derived metapoint continuation. @@ -42,18 +31,8 @@ fn real_limit_order_can_transition_from_mint_to_match_without_consuming_master() let limit_order = limit_order_script(&mut context); let tx = TransactionBuilder::default() - .input( - CellInput::new_builder() - .previous_output(real_order_out_point) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity((1_400 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - ) + .input(input(real_order_out_point)) + .output(cell(1_400 * CKB, &limit_order, Some(&helper_type))) .output_data(order_data_match(100 * CKB as u128, &real_master_out_point, (1, 1)).pack()) .build(); @@ -73,22 +52,11 @@ fn real_limit_order_match_rejects_rewriting_order_info() { let limit_order = limit_order_script(&mut context); let tx = TransactionBuilder::default() - .input( - CellInput::new_builder() - .previous_output(real_order_out_point) - .build(), - ) - .output( - CellOutput::new_builder() - .capacity((1_400 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), - ) + .input(input(real_order_out_point)) + .output(cell(1_400 * CKB, &limit_order, Some(&helper_type))) .output_data(order_data_match(100 * CKB as u128, &real_master_out_point, (2, 1)).pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_DIFFERENT_INFO); + fail(&context, &tx, ERROR_LIMIT_ORDER_DIFFERENT_INFO); } diff --git a/scripts/tests/src/tests/limit_order/remint.rs b/scripts/tests/src/tests/limit_order/remint.rs index c5aa3c0..866bfba 100644 --- a/scripts/tests/src/tests/limit_order/remint.rs +++ b/scripts/tests/src/tests/limit_order/remint.rs @@ -10,33 +10,19 @@ fn can_atomically_melt_and_remint_with_negative_distance_and_filler() { let (old_order_out_point, old_master_out_point) = build_real_limit_order_and_master(&mut context, owner_lock.clone(), helper_type.clone()); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(100 * CKB, &funding_lock, None), Bytes::new(), ); let limit_order = limit_order_script(&mut context); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(old_order_out_point).build()) - .input(CellInput::new_builder().previous_output(old_master_out_point).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(old_order_out_point)) + .input(input(old_master_out_point)) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &limit_order, 0).pack()) - .lock(owner_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(filler_lock) - .build(), - CellOutput::new_builder() - .capacity((1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &limit_order, 0), &owner_lock, Some(&limit_order)), + cell(100 * CKB, &filler_lock, None), + cell(1_500 * CKB, &limit_order, Some(&helper_type)), ]) .outputs_data(vec![Bytes::new(), Bytes::new(), order_data_mint(0, -2, (1, 1))].pack()) .build(); @@ -61,14 +47,9 @@ fn can_atomically_melt_and_remint_with_negative_distance_and_filler() { ); let melt_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(new_order).build()) - .input(CellInput::new_builder().previous_output(new_master).build()) - .output( - CellOutput::new_builder() - .capacity((1_700 * CKB).pack()) - .lock(owner_lock) - .build(), - ) + .input(input(new_order)) + .input(input(new_master)) + .output(cell(1_700 * CKB, &owner_lock, None)) .output_data(Bytes::new().pack()) .build(); let melt_tx = context.complete_tx(melt_tx); diff --git a/scripts/tests/src/tests/limit_order/same_master.rs b/scripts/tests/src/tests/limit_order/same_master.rs index 40461f1..b068f61 100644 --- a/scripts/tests/src/tests/limit_order/same_master.rs +++ b/scripts/tests/src/tests/limit_order/same_master.rs @@ -8,29 +8,17 @@ fn match_rejects_two_outputs_sharing_one_master() { let master = OutPoint::new(Byte32::zero(), 5); let input_order_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_match(0, &master, (1, 1)), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input_order_out_point).build()) + .input(input(input_order_out_point)) .output( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_400 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_400 * CKB), &limit_order, Some(&helper_type)), ) .output( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 100 * CKB).pack()) - .lock(limit_order) - .type_(Some(helper_type).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 100 * CKB), &limit_order, Some(&helper_type)), ) .outputs_data( vec![ @@ -42,8 +30,7 @@ fn match_rejects_two_outputs_sharing_one_master() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_SAME_MASTER); + fail(&context, &tx, ERROR_LIMIT_ORDER_SAME_MASTER); } // Spend two independent match-shaped inputs that already point at the same master; verification rejects the shared metapoint collision on inputs. @@ -54,37 +41,23 @@ fn same_master_collision_on_inputs_is_rejected() { let master = OutPoint::new(Byte32::zero(), 5); let first_order = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_500 * CKB), &limit_order, Some(&helper_type)), order_data_match(0, &master, (1, 1)), ); let second_order = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &helper_type, 89, 1_400 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(deposit_capacity(&limit_order, &helper_type, 89, 1_400 * CKB), &limit_order, Some(&helper_type)), order_data_match(0, &master, (1, 1)), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(first_order).build()) - .input(CellInput::new_builder().previous_output(second_order).build()) - .output( - CellOutput::new_builder() - .capacity((2_900 * CKB).pack()) - .lock(always_success_lock(&mut context)) - .build(), - ) + .input(input(first_order)) + .input(input(second_order)) + .output(cell(2_900 * CKB, &always_success_lock(&mut context), None)) .output_data(Bytes::new().pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_LIMIT_ORDER_SAME_MASTER); + fail(&context, &tx, ERROR_LIMIT_ORDER_SAME_MASTER); } // Attempt to spend the exact same master input twice; transaction validation blocks the duplicate input before any contract duplicate-master branch can execute. @@ -96,14 +69,9 @@ fn duplicate_master_input_shape_is_blocked_before_script_invariants() { build_real_limit_order_and_master(&mut context, owner_lock.clone(), helper_type); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(real_master_out_point.clone()).build()) - .input(CellInput::new_builder().previous_output(real_master_out_point).build()) - .output( - CellOutput::new_builder() - .capacity((400 * CKB).pack()) - .lock(owner_lock) - .build(), - ) + .input(input(real_master_out_point.clone())) + .input(input(real_master_out_point)) + .output(cell(400 * CKB, &owner_lock, None)) .output_data(Bytes::new().pack()) .build(); diff --git a/scripts/tests/src/tests/owned_owner/dao_crosswiring.rs b/scripts/tests/src/tests/owned_owner/dao_crosswiring.rs index 6595508..ee569a6 100644 --- a/scripts/tests/src/tests/owned_owner/dao_crosswiring.rs +++ b/scripts/tests/src/tests/owned_owner/dao_crosswiring.rs @@ -14,58 +14,21 @@ fn crosswired_batch_is_blocked_by_dao_index_rules() { let total2 = deposit_capacity(&ickb_logic, &dao, 8, amount2); let header1 = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); let header2 = gen_header(1555, GENESIS_AR as u64, 35, 1000, 1000); - let deposit1 = context.create_cell( - CellOutput::new_builder() - .capacity(total1.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); - let deposit2 = context.create_cell( - CellOutput::new_builder() - .capacity(total2.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit1 = create_deposit(&mut context, total1, &ickb_logic, &dao); + let deposit2 = create_deposit(&mut context, total2, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit1, &header1); link_cell_to_header(&mut context, &deposit2, &header2); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user1_lock, &xudt, 16).pack()) - .lock(user1_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(amount1 + amount2)), - ); + let udt_input = create_udt(&mut context, &user1_lock, &xudt, u128::from(amount1 + amount2)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit1).build()) - .input(CellInput::new_builder().previous_output(deposit2).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit1)) + .input(input(deposit2)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(total1.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user1_lock, &owned_owner, 4).pack()) - .lock(user1_lock) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(total2.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user2_lock, &owned_owner, 4).pack()) - .lock(user2_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(total1, &owned_owner, Some(&dao)), + cell(occupied_capacity(&user1_lock, &owned_owner, 4), &user1_lock, Some(&owned_owner)), + cell(total2, &owned_owner, Some(&dao)), + cell(occupied_capacity(&user2_lock, &owned_owner, 4), &user2_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -81,8 +44,7 @@ fn crosswired_batch_is_blocked_by_dao_index_rules() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_DAO_INVALID_WITHDRAWING_CELL); + fail(&context, &tx, ERROR_DAO_INVALID_WITHDRAWING_CELL); } // This two-way batch keeps DAO index rules satisfied, so weak phase 1 owner locks are enough to rotate later claim ownership. @@ -99,59 +61,22 @@ fn weak_lock_valid_dao_batch_can_crosswire_claims() { let total2 = deposit_capacity(&ickb_logic, &dao, 8, amount2); let header1 = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); let header2 = gen_header(1555, GENESIS_AR as u64, 35, 1000, 1000); - let deposit1 = context.create_cell( - CellOutput::new_builder() - .capacity(total1.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); - let deposit2 = context.create_cell( - CellOutput::new_builder() - .capacity(total2.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit1 = create_deposit(&mut context, total1, &ickb_logic, &dao); + let deposit2 = create_deposit(&mut context, total2, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit1, &header1); link_cell_to_header(&mut context, &deposit2, &header2); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user1_lock, &xudt, 16).pack()) - .lock(user1_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(amount1 + amount2)), - ); + let udt_input = create_udt(&mut context, &user1_lock, &xudt, u128::from(amount1 + amount2)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit1).build()) - .input(CellInput::new_builder().previous_output(deposit2).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) + .input(input(deposit1)) + .input(input(deposit2)) + .input(input(udt_input)) + .input(input(funding_cell(&mut context))) .outputs(vec![ - CellOutput::new_builder() - .capacity(total1.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(total2.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user1_lock, &owned_owner, 4).pack()) - .lock(user1_lock) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user2_lock, &owned_owner, 4).pack()) - .lock(user2_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(total1, &owned_owner, Some(&dao)), + cell(total2, &owned_owner, Some(&dao)), + cell(occupied_capacity(&user1_lock, &owned_owner, 4), &user1_lock, Some(&owned_owner)), + cell(occupied_capacity(&user2_lock, &owned_owner, 4), &user2_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -188,59 +113,22 @@ fn weak_lock_crosswired_batch_reassigns_phase2_claims() { let deposit_header2 = gen_header(1555, GENESIS_AR as u64, 35, 1000, 1000); let withdraw_header1 = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let withdraw_header2 = gen_header(2_000_621, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); - let deposit1 = context.create_cell( - CellOutput::new_builder() - .capacity(total1.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); - let deposit2 = context.create_cell( - CellOutput::new_builder() - .capacity(total2.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit1 = create_deposit(&mut context, total1, &ickb_logic, &dao); + let deposit2 = create_deposit(&mut context, total2, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit1, &deposit_header1); link_cell_to_header(&mut context, &deposit2, &deposit_header2); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user1_lock, &xudt, 16).pack()) - .lock(user1_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(amount1 + amount2)), - ); + let udt_input = create_udt(&mut context, &user1_lock, &xudt, u128::from(amount1 + amount2)); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit1).build()) - .input(CellInput::new_builder().previous_output(deposit2).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) + .input(input(deposit1)) + .input(input(deposit2)) + .input(input(udt_input)) + .input(input(funding_cell(&mut context))) .outputs(vec![ - CellOutput::new_builder() - .capacity(total1.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(total2.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user1_lock, &owned_owner, 4).pack()) - .lock(user1_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user2_lock, &owned_owner, 4).pack()) - .lock(user2_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(total1, &owned_owner, Some(&dao)), + cell(total2, &owned_owner, Some(&dao)), + cell(occupied_capacity(&user1_lock, &owned_owner, 4), &user1_lock, Some(&owned_owner)), + cell(occupied_capacity(&user2_lock, &owned_owner, 4), &user2_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -287,13 +175,8 @@ fn weak_lock_crosswired_batch_reassigns_phase2_claims() { .since(0x2003e802340002f3u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner1.clone()).build()) - .output( - CellOutput::new_builder() - .capacity(exact_crosswired_capacity.pack()) - .lock(user1_lock.clone()) - .build(), - ) + .input(input(owner1.clone())) + .output(cell(exact_crosswired_capacity, &user1_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header2.hash()) .header_dep(deposit_header2.hash()) @@ -311,17 +194,14 @@ fn weak_lock_crosswired_batch_reassigns_phase2_claims() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner1).build()) + .input(input(owner1)) .output( - CellOutput::new_builder() - .capacity(dao_maximum_withdraw_capacity( + cell(dao_maximum_withdraw_capacity( &create_tx.outputs().get(0).expect("owned1 output"), withdrawal_request_data(1554).len(), GENESIS_AR as u64, SYNTHETIC_WITHDRAW_AR, - ).pack()) - .lock(user1_lock) - .build(), + ), &user1_lock, None), ) .output_data(Bytes::new().pack()) .header_dep(withdraw_header1.hash()) @@ -329,8 +209,7 @@ fn weak_lock_crosswired_batch_reassigns_phase2_claims() { .witness(header_dep_index_witness(1).pack()) .build(); let claim_with_intended_pair = context.complete_tx(claim_with_intended_pair); - let err = context.verify(&claim_with_intended_pair, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); + fail(&context, &claim_with_intended_pair, ERROR_OWNED_OWNER_MISMATCH); } // The same weak-lock claim rotation generalizes beyond two users: a three-way phase 1 crosswire can rotate later phase 2 ownership. @@ -353,34 +232,27 @@ fn weak_lock_three_way_crosswire_rotates_claims() { let deposit_header3 = gen_header(1556, GENESIS_AR as u64, 35, 1000, 1000); let withdraw_header2 = gen_header(2_000_621, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); - let deposit1 = context.create_cell(CellOutput::new_builder().capacity(total1.pack()).lock(ickb_logic.clone()).type_(Some(dao.clone()).pack()).build(), dao_deposit_data()); - let deposit2 = context.create_cell(CellOutput::new_builder().capacity(total2.pack()).lock(ickb_logic.clone()).type_(Some(dao.clone()).pack()).build(), dao_deposit_data()); - let deposit3 = context.create_cell(CellOutput::new_builder().capacity(total3.pack()).lock(ickb_logic.clone()).type_(Some(dao.clone()).pack()).build(), dao_deposit_data()); + let deposit1 = create_deposit(&mut context, total1, &ickb_logic, &dao); + let deposit2 = create_deposit(&mut context, total2, &ickb_logic, &dao); + let deposit3 = create_deposit(&mut context, total3, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit1, &deposit_header1); link_cell_to_header(&mut context, &deposit2, &deposit_header2); link_cell_to_header(&mut context, &deposit3, &deposit_header3); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user1_lock, &xudt, 16).pack()) - .lock(user1_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(amount1 + amount2 + amount3)), - ); + let udt_input = create_udt(&mut context, &user1_lock, &xudt, u128::from(amount1 + amount2 + amount3)); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit1).build()) - .input(CellInput::new_builder().previous_output(deposit2).build()) - .input(CellInput::new_builder().previous_output(deposit3).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) + .input(input(deposit1)) + .input(input(deposit2)) + .input(input(deposit3)) + .input(input(udt_input)) + .input(input(funding_cell(&mut context))) .outputs(vec![ - CellOutput::new_builder().capacity(total1.pack()).lock(owned_owner.clone()).type_(Some(dao.clone()).pack()).build(), - CellOutput::new_builder().capacity(total2.pack()).lock(owned_owner.clone()).type_(Some(dao.clone()).pack()).build(), - CellOutput::new_builder().capacity(total3.pack()).lock(owned_owner.clone()).type_(Some(dao.clone()).pack()).build(), - CellOutput::new_builder().capacity((200 * CKB).pack()).lock(user1_lock.clone()).type_(Some(owned_owner.clone()).pack()).build(), - CellOutput::new_builder().capacity((200 * CKB).pack()).lock(user2_lock.clone()).type_(Some(owned_owner.clone()).pack()).build(), - CellOutput::new_builder().capacity((200 * CKB).pack()).lock(user3_lock).type_(Some(owned_owner).pack()).build(), + cell(total1, &owned_owner, Some(&dao)), + cell(total2, &owned_owner, Some(&dao)), + cell(total3, &owned_owner, Some(&dao)), + cell(200 * CKB, &user1_lock, Some(&owned_owner)), + cell(200 * CKB, &user2_lock, Some(&owned_owner)), + cell(200 * CKB, &user3_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -429,13 +301,8 @@ fn weak_lock_three_way_crosswire_rotates_claims() { .since(0x2003e802340002f3u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner1.clone()).build()) - .output( - CellOutput::new_builder() - .capacity(claim_capacity.pack()) - .lock(user1_lock.clone()) - .build(), - ) + .input(input(owner1.clone())) + .output(cell(claim_capacity, &user1_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header2.hash()) .header_dep(deposit_header2.hash()) @@ -453,19 +320,13 @@ fn weak_lock_three_way_crosswire_rotates_claims() { .since(0x2003e802340002f3u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner2).build()) - .output( - CellOutput::new_builder() - .capacity(claim_capacity.pack()) - .lock(user2_lock) - .build(), - ) + .input(input(owner2)) + .output(cell(claim_capacity, &user2_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header2.hash()) .header_dep(deposit_header2.hash()) .witness(witness.pack()) .build(); let claim_with_intended_pair = context.complete_tx(claim_with_intended_pair); - let err = context.verify(&claim_with_intended_pair, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); + fail(&context, &claim_with_intended_pair, ERROR_OWNED_OWNER_MISMATCH); } diff --git a/scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs b/scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs index 841dcb5..2eb9e6b 100644 --- a/scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs +++ b/scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs @@ -16,37 +16,19 @@ fn foreign_dao_withdrawal_can_be_wrapped_and_claimed() { // For deposits since block 10,000,000 the node keeps a withdrawal request's lock the same size as // its deposit's, so only a deposit whose lock has Owned Owner's size (empty args) can be wrapped. let wrappable_lock = always_success_lock(&mut context); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_capacity_value.pack()) - .lock(wrappable_lock) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_capacity_value, &wrappable_lock, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(200 * CKB, &funding_lock, None), Bytes::new(), ); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(deposit_input)) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_capacity_value.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(deposit_capacity_value, &owned_owner, Some(&dao)), + cell(occupied_capacity(&user_lock, &owned_owner, 4), &user_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -88,20 +70,18 @@ fn foreign_dao_withdrawal_can_be_wrapped_and_claimed() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_out_point).build()) + .input(input(owner_out_point)) .output( - CellOutput::new_builder() - .capacity( - dao_maximum_withdraw_capacity( - &owned_output, - withdrawal_request_data(1554).len(), - GENESIS_AR as u64, - SYNTHETIC_WITHDRAW_AR, - ) - .pack(), - ) - .lock(user_lock) - .build(), + cell( + dao_maximum_withdraw_capacity( + &owned_output, + withdrawal_request_data(1554).len(), + GENESIS_AR as u64, + SYNTHETIC_WITHDRAW_AR, + ), + &user_lock, + None, + ), ) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) diff --git a/scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs b/scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs index 0679fa7..431c91d 100644 --- a/scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs +++ b/scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs @@ -11,38 +11,16 @@ fn phase1_accepts_unspendable_foreign_owner_lock() { let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); + let udt_input = create_udt(&mut context, &owner_lock, &xudt, u128::from(deposit_amount)); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&poisoned_lock, &owned_owner, 4).pack()) - .lock(poisoned_lock) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&poisoned_lock, &owned_owner, 4), &poisoned_lock, Some(&owned_owner)), ]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .header_dep(deposit_header.hash()) @@ -78,13 +56,8 @@ fn phase1_accepts_unspendable_foreign_owner_lock() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(123_468_106_670u64.pack()) - .lock(owner_lock) - .build(), - ) + .input(input(owner_out_point)) + .output(cell(123_468_106_670u64, &owner_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) @@ -92,8 +65,7 @@ fn phase1_accepts_unspendable_foreign_owner_lock() { .build(); let melt_tx = context.complete_tx(melt_tx); - let err = context.verify(&melt_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_NOT_EMPTY_ARGS); + fail(&context, &melt_tx, ERROR_NOT_EMPTY_ARGS); } // Even an empty-args foreign lock can strand the pair later if the eventual owner lock semantics do not match the claim flow. @@ -106,38 +78,16 @@ fn phase1_accepts_limit_order_owner_lock_but_claim_strands() { let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); + let udt_input = create_udt(&mut context, &owner_lock, &xudt, u128::from(deposit_amount)); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&benign_foreign_lock, &owned_owner, 4).pack()) - .lock(benign_foreign_lock) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&benign_foreign_lock, &owned_owner, 4), &benign_foreign_lock, Some(&owned_owner)), ]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .header_dep(deposit_header.hash()) @@ -173,13 +123,8 @@ fn phase1_accepts_limit_order_owner_lock_but_claim_strands() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(123_468_106_670u64.pack()) - .lock(owner_lock) - .build(), - ) + .input(input(owner_out_point)) + .output(cell(123_468_106_670u64, &owner_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) @@ -187,8 +132,7 @@ fn phase1_accepts_limit_order_owner_lock_but_claim_strands() { .build(); let melt_tx = context.complete_tx(melt_tx); - let err = context.verify(&melt_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_ENCODING); + fail(&context, &melt_tx, ERROR_ENCODING); } // Scenario: phase 1 tries to emit an owner cell whose lock and type are both limit-order driven. @@ -206,54 +150,27 @@ fn limit_order_backed_owner_is_blocked_in_phase1() { let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&burn_lock, &xudt, 16).pack()) - .lock(burn_lock) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); + let udt_input = create_udt(&mut context, &burn_lock, &xudt, u128::from(deposit_amount)); let master_out_point = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&attacker_lock, &limit_order, 0).pack()) - .lock(attacker_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), + cell(occupied_capacity(&attacker_lock, &limit_order, 0), &attacker_lock, Some(&limit_order)), Bytes::new(), ); let owner_order_data = order_data_match(u128::from(u32::MAX), &master_out_point, (1, 1)); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(deposit_capacity(&limit_order, &owned_owner, owner_order_data.len(), 1_500 * CKB).pack()) - .lock(limit_order.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(deposit_capacity(&limit_order, &owned_owner, owner_order_data.len(), 1_500 * CKB), &limit_order, Some(&owned_owner)), ]) .outputs_data(vec![withdrawal_request_data(1554), owner_order_data.clone()].pack()) .header_dep(deposit_header.hash()) .build(); let create_tx = context.complete_tx(create_tx); - let err = context.verify(&create_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_DAO_INCORRECT_CAPACITY); + fail(&context, &create_tx, ERROR_DAO_INCORRECT_CAPACITY); } diff --git a/scripts/tests/src/tests/owned_owner/live_claim_rotation.rs b/scripts/tests/src/tests/owned_owner/live_claim_rotation.rs index 9e425fe..a340844 100644 --- a/scripts/tests/src/tests/owned_owner/live_claim_rotation.rs +++ b/scripts/tests/src/tests/owned_owner/live_claim_rotation.rs @@ -17,20 +17,12 @@ fn live_claim_cannot_roll_into_fresh_pair() { context.create_cell_with_out_point( owned_input.clone(), - CellOutput::new_builder() - .capacity(123_456_780_000u64.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(123_456_780_000u64, &owned_owner, Some(&dao)), withdrawal_request_data(1554), ); context.create_cell_with_out_point( owner_input.clone(), - CellOutput::new_builder() - .capacity(occupied_capacity(&old_owner_lock, &owned_owner, 4).pack()) - .lock(old_owner_lock) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(occupied_capacity(&old_owner_lock, &owned_owner, 4), &old_owner_lock, Some(&owned_owner)), owner_distance_data(-1), ); link_cell_to_header(&mut context, &owned_input, &withdraw_header); @@ -44,18 +36,10 @@ fn live_claim_cannot_roll_into_fresh_pair() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_input).build()) + .input(input(owner_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(123_456_780_000u64.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&new_owner_lock, &owned_owner, 4).pack()) - .lock(new_owner_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(123_456_780_000u64, &owned_owner, Some(&dao)), + cell(occupied_capacity(&new_owner_lock, &owned_owner, 4), &new_owner_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -70,8 +54,7 @@ fn live_claim_cannot_roll_into_fresh_pair() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_DAO_NEWLY_CREATED_CELL); + fail(&context, &tx, ERROR_DAO_NEWLY_CREATED_CELL); } // Consuming multiple live pairs still cannot rotate them into a new set of live pairs once the full DAO claim rules are enforced. @@ -90,59 +73,22 @@ fn live_claims_cannot_rotate_into_new_pairs() { let deposit_header2 = gen_header(1555, GENESIS_AR as u64, 35, 1000, 1000); let withdraw_header1 = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let withdraw_header2 = gen_header(2_000_621, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); - let deposit1 = context.create_cell( - CellOutput::new_builder() - .capacity(total1.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); - let deposit2 = context.create_cell( - CellOutput::new_builder() - .capacity(total2.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit1 = create_deposit(&mut context, total1, &ickb_logic, &dao); + let deposit2 = create_deposit(&mut context, total2, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit1, &deposit_header1); link_cell_to_header(&mut context, &deposit2, &deposit_header2); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user1_lock, &xudt, 16).pack()) - .lock(user1_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(amount1 + amount2)), - ); + let udt_input = create_udt(&mut context, &user1_lock, &xudt, u128::from(amount1 + amount2)); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit1).build()) - .input(CellInput::new_builder().previous_output(deposit2).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) + .input(input(deposit1)) + .input(input(deposit2)) + .input(input(udt_input)) + .input(input(funding_cell(&mut context))) .outputs(vec![ - CellOutput::new_builder() - .capacity(total1.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(total2.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user1_lock, &owned_owner, 4).pack()) - .lock(user1_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user2_lock, &owned_owner, 4).pack()) - .lock(user2_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(total1, &owned_owner, Some(&dao)), + cell(total2, &owned_owner, Some(&dao)), + cell(occupied_capacity(&user1_lock, &owned_owner, 4), &user1_lock, Some(&owned_owner)), + cell(occupied_capacity(&user2_lock, &owned_owner, 4), &user2_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -207,29 +153,13 @@ fn live_claims_cannot_rotate_into_new_pairs() { .since(0x2003e802340002f3u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner1).build()) - .input(CellInput::new_builder().previous_output(owner2).build()) + .input(input(owner1)) + .input(input(owner2)) .outputs(vec![ - CellOutput::new_builder() - .capacity(total1.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(total2.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user1_lock, &owned_owner, 4).pack()) - .lock(user1_lock) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user2_lock, &owned_owner, 4).pack()) - .lock(user2_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(total1, &owned_owner, Some(&dao)), + cell(total2, &owned_owner, Some(&dao)), + cell(occupied_capacity(&user1_lock, &owned_owner, 4), &user1_lock, Some(&owned_owner)), + cell(occupied_capacity(&user2_lock, &owned_owner, 4), &user2_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -249,6 +179,5 @@ fn live_claims_cannot_rotate_into_new_pairs() { .build(); let rotate_tx = context.complete_tx(rotate_tx); - let err = context.verify(&rotate_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_DAO_NEWLY_CREATED_CELL); + fail(&context, &rotate_tx, ERROR_DAO_NEWLY_CREATED_CELL); } diff --git a/scripts/tests/src/tests/owned_owner/melt_pairing_and_witness.rs b/scripts/tests/src/tests/owned_owner/melt_pairing_and_witness.rs index a161878..df453aa 100644 --- a/scripts/tests/src/tests/owned_owner/melt_pairing_and_witness.rs +++ b/scripts/tests/src/tests/owned_owner/melt_pairing_and_witness.rs @@ -13,11 +13,7 @@ fn melt_accepts_owner_distance_trailing_bytes_on_input() { let shared_tx_hash = Byte32::from_slice(&[7u8; 32]).expect("shared tx hash"); let owned_input = OutPoint::new(shared_tx_hash.clone(), 0); let owner_input = OutPoint::new(shared_tx_hash, 1); - let owned_input_output = CellOutput::new_builder() - .capacity(123_456_780_000u64.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(); + let owned_input_output = cell(123_456_780_000u64, &owned_owner, Some(&dao)); context.create_cell_with_out_point( owned_input.clone(), owned_input_output.clone(), @@ -25,11 +21,7 @@ fn melt_accepts_owner_distance_trailing_bytes_on_input() { ); context.create_cell_with_out_point( owner_input.clone(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 6).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &owned_owner, 6), &owner_lock, Some(&owned_owner)), owner_distance_data_with_trailing_bytes(-1, &[0xaa, 0xbb]), ); link_cell_to_header(&mut context, &owned_input, &withdraw_header); @@ -49,13 +41,8 @@ fn melt_accepts_owner_distance_trailing_bytes_on_input() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_input).build()) - .output( - CellOutput::new_builder() - .capacity(exact_capacity.pack()) - .lock(owner_lock) - .build(), - ) + .input(input(owner_input)) + .output(cell(exact_capacity, &owner_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) @@ -81,11 +68,7 @@ fn valid_melt_pair_passes() { let shared_tx_hash = Byte32::from_slice(&[6u8; 32]).expect("shared tx hash"); let owned_input = OutPoint::new(shared_tx_hash.clone(), 0); let owner_input = OutPoint::new(shared_tx_hash, 1); - let owned_input_output = CellOutput::new_builder() - .capacity(123_456_780_000u64.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(); + let owned_input_output = cell(123_456_780_000u64, &owned_owner, Some(&dao)); context.create_cell_with_out_point( owned_input.clone(), owned_input_output.clone(), @@ -93,11 +76,7 @@ fn valid_melt_pair_passes() { ); context.create_cell_with_out_point( owner_input.clone(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), owner_distance_data(-1), ); link_cell_to_header(&mut context, &owned_input, &withdraw_header); @@ -117,13 +96,8 @@ fn valid_melt_pair_passes() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_input).build()) - .output( - CellOutput::new_builder() - .capacity(exact_capacity.pack()) - .lock(owner_lock) - .build(), - ) + .input(input(owner_input)) + .output(cell(exact_capacity, &owner_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) @@ -152,20 +126,12 @@ fn melt_rejects_misbound_deposit_header_index() { context.create_cell_with_out_point( owned_input.clone(), - CellOutput::new_builder() - .capacity(123_456_780_000u64.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), + cell(123_456_780_000u64, &owned_owner, Some(&dao)), withdrawal_request_data(1554), ); context.create_cell_with_out_point( owner_input.clone(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), owner_distance_data(-1), ); link_cell_to_header(&mut context, &owned_input, &withdraw_header); @@ -178,13 +144,8 @@ fn melt_rejects_misbound_deposit_header_index() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_input).build()) - .output( - CellOutput::new_builder() - .capacity(123_468_106_670u64.pack()) - .lock(owner_lock) - .build(), - ) + .input(input(owner_input)) + .output(cell(123_468_106_670u64, &owner_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) @@ -192,8 +153,7 @@ fn melt_rejects_misbound_deposit_header_index() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_DAO_INVALID_WITHDRAW_BLOCK); + fail(&context, &tx, ERROR_DAO_INVALID_WITHDRAW_BLOCK); } // Scenario: the witness input_type is too short to hold a u64 header index. @@ -212,20 +172,12 @@ fn melt_rejects_short_header_dep_index_witness() { context.create_cell_with_out_point( owned_input.clone(), - CellOutput::new_builder() - .capacity(123_456_780_000u64.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(123_456_780_000u64, &owned_owner, Some(&dao)), withdrawal_request_data(1554), ); context.create_cell_with_out_point( owner_input.clone(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), owner_distance_data(-1), ); link_cell_to_header(&mut context, &owned_input, &withdraw_header); @@ -239,13 +191,8 @@ fn melt_rejects_short_header_dep_index_witness() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_input).build()) - .output( - CellOutput::new_builder() - .capacity(123_468_106_670u64.pack()) - .lock(owner_lock) - .build(), - ) + .input(input(owner_input)) + .output(cell(123_468_106_670u64, &owner_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) @@ -253,8 +200,7 @@ fn melt_rejects_short_header_dep_index_witness() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, -11); + fail(&context, &tx, -11); } // Scenario: the witness places the header index in output_type instead of input_type. @@ -273,20 +219,12 @@ fn melt_rejects_header_dep_index_witness_in_output_type() { context.create_cell_with_out_point( owned_input.clone(), - CellOutput::new_builder() - .capacity(123_456_780_000u64.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(123_456_780_000u64, &owned_owner, Some(&dao)), withdrawal_request_data(1554), ); context.create_cell_with_out_point( owner_input.clone(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), owner_distance_data(-1), ); link_cell_to_header(&mut context, &owned_input, &withdraw_header); @@ -300,13 +238,8 @@ fn melt_rejects_header_dep_index_witness_in_output_type() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_input).build()) - .output( - CellOutput::new_builder() - .capacity(123_468_106_670u64.pack()) - .lock(owner_lock) - .build(), - ) + .input(input(owner_input)) + .output(cell(123_468_106_670u64, &owner_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) @@ -314,8 +247,7 @@ fn melt_rejects_header_dep_index_witness_in_output_type() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, -11); + fail(&context, &tx, -11); } // Scenario: the owner input distance is truncated during phase 2. @@ -333,20 +265,12 @@ fn melt_rejects_truncated_owner_distance_on_input() { let owner_input = OutPoint::new(shared_tx_hash, 1); context.create_cell_with_out_point( owned_input.clone(), - CellOutput::new_builder() - .capacity(123_456_780_000u64.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), + cell(123_456_780_000u64, &owned_owner, Some(&dao)), withdrawal_request_data(1554), ); context.create_cell_with_out_point( owner_input.clone(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), truncated_bytes(owner_distance_data(-1), 1), ); link_cell_to_header(&mut context, &owned_input, &withdraw_header); @@ -360,13 +284,8 @@ fn melt_rejects_truncated_owner_distance_on_input() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_input).build()) - .output( - CellOutput::new_builder() - .capacity(123_468_106_670u64.pack()) - .lock(owner_lock) - .build(), - ) + .input(input(owner_input)) + .output(cell(123_468_106_670u64, &owner_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) @@ -374,8 +293,7 @@ fn melt_rejects_truncated_owner_distance_on_input() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_ENCODING); + fail(&context, &tx, ERROR_ENCODING); } // Scenario: two separate Owned Owner pairs are consumed with the owner cells deliberately swapped. @@ -389,51 +307,34 @@ fn pairs_cannot_be_swapped_during_melt() { let user2_lock = named_always_success_lock(&mut context, b"user2"); let owned1 = context.create_cell( - CellOutput::new_builder() - .capacity((1000 * CKB).pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(1000 * CKB, &owned_owner, Some(&dao)), withdrawal_request_data(1554), ); let owner1 = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user1_lock, &owned_owner, 4).pack()) - .lock(user1_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(occupied_capacity(&user1_lock, &owned_owner, 4), &user1_lock, Some(&owned_owner)), owner_distance_data(1), ); let owned2 = context.create_cell( - CellOutput::new_builder() - .capacity((1000 * CKB).pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), + cell(1000 * CKB, &owned_owner, Some(&dao)), withdrawal_request_data(1555), ); let owner2 = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user2_lock, &owned_owner, 4).pack()) - .lock(user2_lock.clone()) - .type_(Some(owned_owner).pack()) - .build(), + cell(occupied_capacity(&user2_lock, &owned_owner, 4), &user2_lock, Some(&owned_owner)), owner_distance_data(-1), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(owned1).build()) - .input(CellInput::new_builder().previous_output(owner2).build()) - .input(CellInput::new_builder().previous_output(owned2).build()) - .input(CellInput::new_builder().previous_output(owner1).build()) + .input(input(owned1)) + .input(input(owner2)) + .input(input(owned2)) + .input(input(owner1)) .outputs(vec![ - CellOutput::new_builder().capacity((600 * CKB).pack()).lock(user1_lock).build(), - CellOutput::new_builder().capacity((600 * CKB).pack()).lock(user2_lock).build(), + cell(600 * CKB, &user1_lock, None), + cell(600 * CKB, &user2_lock, None), ]) .outputs_data(vec![Bytes::new(), Bytes::new()].pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); + fail(&context, &tx, ERROR_OWNED_OWNER_MISMATCH); } diff --git a/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs b/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs index 4cf5b29..c7a4b56 100644 --- a/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs +++ b/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs @@ -18,63 +18,26 @@ fn weak_lock_mixed_foreign_and_ickb_batch_can_crosswire_claims() { // For deposits since block 10,000,000 the node keeps a withdrawal request's lock the same size as // its deposit's, so only a foreign deposit whose lock has Owned Owner's size (empty args) can be wrapped. let wrappable_lock = always_success_lock(&mut context); - let foreign_deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(foreign_deposit_capacity.pack()) - .lock(wrappable_lock) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let foreign_deposit_input = create_deposit(&mut context, foreign_deposit_capacity, &wrappable_lock, &dao); link_cell_to_header(&mut context, &foreign_deposit_input, &foreign_deposit_header); let protocol_deposit_amount = 1_000 * CKB; let protocol_deposit_capacity = deposit_capacity(&ickb_logic, &dao, 8, protocol_deposit_amount); - let protocol_deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(protocol_deposit_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let protocol_deposit_input = create_deposit(&mut context, protocol_deposit_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &protocol_deposit_input, &protocol_deposit_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&protocol_owner_lock, &xudt, 16).pack()) - .lock(protocol_owner_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(protocol_deposit_amount)), - ); + let udt_input = create_udt(&mut context, &protocol_owner_lock, &xudt, u128::from(protocol_deposit_amount)); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(foreign_deposit_input).build()) - .input(CellInput::new_builder().previous_output(protocol_deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) + .input(input(foreign_deposit_input)) + .input(input(protocol_deposit_input)) + .input(input(udt_input)) + .input(input(funding_cell(&mut context))) .outputs(vec![ - CellOutput::new_builder() - .capacity(foreign_deposit_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(protocol_deposit_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&foreign_owner_lock, &owned_owner, 4).pack()) - .lock(foreign_owner_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&protocol_owner_lock, &owned_owner, 4).pack()) - .lock(protocol_owner_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(foreign_deposit_capacity, &owned_owner, Some(&dao)), + cell(protocol_deposit_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&foreign_owner_lock, &owned_owner, 4), &foreign_owner_lock, Some(&owned_owner)), + cell(occupied_capacity(&protocol_owner_lock, &owned_owner, 4), &protocol_owner_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -131,20 +94,18 @@ fn weak_lock_mixed_foreign_and_ickb_batch_can_crosswire_claims() { .since(0x2003e802340002f3u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(foreign_owner.clone()).build()) + .input(input(foreign_owner.clone())) .output( - CellOutput::new_builder() - .capacity( - dao_maximum_withdraw_capacity( - &create_tx.outputs().get(1).expect("protocol owned output"), - withdrawal_request_data(protocol_deposit_number).len(), - GENESIS_AR as u64, - SYNTHETIC_WITHDRAW_AR, - ) - .pack(), - ) - .lock(foreign_owner_lock) - .build(), + cell( + dao_maximum_withdraw_capacity( + &create_tx.outputs().get(1).expect("protocol owned output"), + withdrawal_request_data(protocol_deposit_number).len(), + GENESIS_AR as u64, + SYNTHETIC_WITHDRAW_AR, + ), + &foreign_owner_lock, + None, + ), ) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) @@ -164,20 +125,18 @@ fn weak_lock_mixed_foreign_and_ickb_batch_can_crosswire_claims() { .since(0x2003e802340002f3u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(protocol_owner).build()) + .input(input(protocol_owner)) .output( - CellOutput::new_builder() - .capacity( - dao_maximum_withdraw_capacity( - &create_tx.outputs().get(1).expect("protocol owned output"), - withdrawal_request_data(protocol_deposit_number).len(), - GENESIS_AR as u64, - SYNTHETIC_WITHDRAW_AR, - ) - .pack(), - ) - .lock(protocol_owner_lock) - .build(), + cell( + dao_maximum_withdraw_capacity( + &create_tx.outputs().get(1).expect("protocol owned output"), + withdrawal_request_data(protocol_deposit_number).len(), + GENESIS_AR as u64, + SYNTHETIC_WITHDRAW_AR, + ), + &protocol_owner_lock, + None, + ), ) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) @@ -186,8 +145,5 @@ fn weak_lock_mixed_foreign_and_ickb_batch_can_crosswire_claims() { .witness(header_dep_index_witness(2).pack()) .build(); let claim_with_intended_protocol_owner = context.complete_tx(claim_with_intended_protocol_owner); - let err = context - .verify(&claim_with_intended_protocol_owner, MAX_CYCLES) - .unwrap_err(); - assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); + fail(&context, &claim_with_intended_protocol_owner, ERROR_OWNED_OWNER_MISMATCH); } diff --git a/scripts/tests/src/tests/owned_owner/owner_distance_encoding.rs b/scripts/tests/src/tests/owned_owner/owner_distance_encoding.rs index 742195b..a65cd4c 100644 --- a/scripts/tests/src/tests/owned_owner/owner_distance_encoding.rs +++ b/scripts/tests/src/tests/owned_owner/owner_distance_encoding.rs @@ -12,46 +12,23 @@ fn truncated_owner_distance_output_is_rejected() { let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let udt_input = create_udt(&mut context, &owner_lock, &xudt, u128::from(deposit_amount)); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let owner_output = CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(); - let owned_output = CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner) - .type_(Some(dao).pack()) - .build(); + let owner_output = cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)); + let owned_output = cell(deposit_total_capacity, &owned_owner, Some(&dao)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(deposit_input).build()) + .input(input(udt_input)) + .input(input(deposit_input)) .outputs(vec![owner_output, owned_output]) .outputs_data(vec![truncated_bytes(owner_distance_data(1), 1), withdrawal_request_data(1554)].pack()) .header_dep(deposit_header.hash()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_ENCODING); + fail(&context, &tx, ERROR_ENCODING); } // Scenario: the owner distance output is empty instead of four bytes. @@ -64,46 +41,23 @@ fn zero_length_owner_distance_output_is_rejected_as_encoding() { let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let udt_input = create_udt(&mut context, &owner_lock, &xudt, u128::from(deposit_amount)); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let owner_output = CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(); - let owned_output = CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner) - .type_(Some(dao).pack()) - .build(); + let owner_output = cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)); + let owned_output = cell(deposit_total_capacity, &owned_owner, Some(&dao)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(deposit_input).build()) + .input(input(udt_input)) + .input(input(deposit_input)) .outputs(vec![owner_output, owned_output]) .outputs_data(vec![Bytes::new(), withdrawal_request_data(1554)].pack()) .header_dep(deposit_header.hash()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_ENCODING); + fail(&context, &tx, ERROR_ENCODING); } // Scenario: the owner distance has valid leading bytes plus extra trailing data. @@ -116,38 +70,16 @@ fn owner_distance_trailing_bytes_are_ignored() { let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let udt_input = create_udt(&mut context, &owner_lock, &xudt, u128::from(deposit_amount)); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let owner_output = CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 6).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(); - let owned_output = CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner) - .type_(Some(dao).pack()) - .build(); + let owner_output = cell(occupied_capacity(&owner_lock, &owned_owner, 6), &owner_lock, Some(&owned_owner)); + let owned_output = cell(deposit_total_capacity, &owned_owner, Some(&dao)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(deposit_input).build()) + .input(input(udt_input)) + .input(input(deposit_input)) .outputs(vec![owner_output, owned_output]) .outputs_data( vec![ diff --git a/scripts/tests/src/tests/owned_owner/pair_formation.rs b/scripts/tests/src/tests/owned_owner/pair_formation.rs index 0507648..3dd899e 100644 --- a/scripts/tests/src/tests/owned_owner/pair_formation.rs +++ b/scripts/tests/src/tests/owned_owner/pair_formation.rs @@ -10,37 +10,15 @@ fn valid_output_pair_passes() { let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); - let owned_output = CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(); - let owner_output = CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock) - .type_(Some(owned_owner).pack()) - .build(); + let udt_input = create_udt(&mut context, &owner_lock, &xudt, u128::from(deposit_amount)); + let owned_output = cell(deposit_total_capacity, &owned_owner, Some(&dao)); + let owner_output = cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(udt_input)) .outputs(vec![owned_output, owner_output]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .header_dep(deposit_header.hash()) @@ -66,26 +44,15 @@ fn withdrawal_shape_cannot_be_created_without_any_dao_input() { let withdrawal_capacity = 123_456_780_000u64; let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((withdrawal_capacity + 200u64).pack()) - .lock(funding_lock) - .build(), + cell(withdrawal_capacity + 200u64, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(withdrawal_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) - .lock(user_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(withdrawal_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&user_lock, &owned_owner, 4), &user_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -97,8 +64,7 @@ fn withdrawal_shape_cannot_be_created_without_any_dao_input() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_DAO_NEWLY_CREATED_CELL); + fail(&context, &tx, ERROR_DAO_NEWLY_CREATED_CELL); } // Scenario: one withdrawal output is paired with two owner outputs in the same batch. @@ -112,51 +78,22 @@ fn two_owner_cells_for_one_owned_output_are_rejected() { let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); + let udt_input = create_udt(&mut context, &owner_lock, &xudt, u128::from(deposit_amount)); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(200 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(deposit_input)) + .input(input(udt_input)) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -170,8 +107,7 @@ fn two_owner_cells_for_one_owned_output_are_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); + fail(&context, &tx, ERROR_OWNED_OWNER_MISMATCH); } // The reverse of the case above: two owned withdrawal requests and a single owner cell. @@ -186,54 +122,29 @@ fn two_owned_outputs_for_one_owner_cell_are_rejected() { let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let mut deposit = || { - let input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); - link_cell_to_header(&mut context, &input, &deposit_header); - input + let out_point = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); + link_cell_to_header(&mut context, &out_point, &deposit_header); + out_point }; let (first_deposit, second_deposit) = (deposit(), deposit()); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(2 * u128::from(deposit_amount)), - ); + let udt_input = create_udt(&mut context, &owner_lock, &xudt, 2 * u128::from(deposit_amount)); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(200 * CKB, &funding_lock, None), Bytes::new(), ); let owned_request = || { - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build() + cell(deposit_total_capacity, &owned_owner, Some(&dao)) }; let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(first_deposit).build()) - .input(CellInput::new_builder().previous_output(second_deposit).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(first_deposit)) + .input(input(second_deposit)) + .input(input(udt_input)) + .input(input(funding_input)) .outputs(vec![ owned_request(), owned_request(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -247,8 +158,7 @@ fn two_owned_outputs_for_one_owner_cell_are_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); + fail(&context, &tx, ERROR_OWNED_OWNER_MISMATCH); } // Output-lock creation can admit an orphan withdrawal request, but the later claim still fails once Owned Owner executes. @@ -261,34 +171,14 @@ fn orphan_withdrawal_request_can_be_created_but_not_claimed() { let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); + let udt_input = create_udt(&mut context, &user_lock, &xudt, u128::from(deposit_amount)); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .output( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - ) + .input(input(deposit_input)) + .input(input(udt_input)) + .output(cell(deposit_total_capacity, &owned_owner, Some(&dao))) .output_data(withdrawal_request_data(1554).pack()) .header_dep(deposit_header.hash()) .build(); @@ -315,12 +205,7 @@ fn orphan_withdrawal_request_can_be_created_but_not_claimed() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .output( - CellOutput::new_builder() - .capacity(123_468_106_670u64.pack()) - .lock(user_lock) - .build(), - ) + .output(cell(123_468_106_670u64, &user_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) @@ -328,8 +213,7 @@ fn orphan_withdrawal_request_can_be_created_but_not_claimed() { .build(); let claim_tx = context.complete_tx(claim_tx); - let err = context.verify(&claim_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); + fail(&context, &claim_tx, ERROR_OWNED_OWNER_MISMATCH); } // A type-script orphan is rejected immediately because Owned Owner sees the full output pairing and finds no matching owned cell. @@ -341,25 +225,17 @@ fn orphan_owner_output_is_rejected() { let owned_owner = owned_owner_script(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((500 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(500 * CKB, &funding_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), ) .output_data(owner_distance_data(1).pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); + fail(&context, &tx, ERROR_OWNED_OWNER_MISMATCH); } diff --git a/scripts/tests/src/tests/owned_owner/phase1_poisoning.rs b/scripts/tests/src/tests/owned_owner/phase1_poisoning.rs index 862f705..e93e30a 100644 --- a/scripts/tests/src/tests/owned_owner/phase1_poisoning.rs +++ b/scripts/tests/src/tests/owned_owner/phase1_poisoning.rs @@ -21,23 +21,12 @@ fn unrelated_non_empty_args_output_lock_poisons_withdrawal() { ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock) - .type_(Some(owned_owner).pack()) - .build(), - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(poisoned_lock) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), + cell(200 * CKB, &poisoned_lock, None), ]) .outputs_data( vec![ @@ -51,8 +40,7 @@ fn unrelated_non_empty_args_output_lock_poisons_withdrawal() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_NOT_EMPTY_ARGS); + fail(&context, &tx, ERROR_NOT_EMPTY_ARGS); } // Scenario: the batch includes an unrelated typed output that does not use Owned Owner. @@ -77,25 +65,13 @@ fn foreign_typed_output_is_ignored() { ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) + .input(input(deposit_input)) + .input(input(udt_input)) + .input(input(funding_cell(&mut context))) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock) - .type_(Some(owned_owner).pack()) - .build(), - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(foreign_lock) - .type_(Some(foreign_type).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), + cell(200 * CKB, &foreign_lock, Some(&foreign_type)), ]) .outputs_data( vec![ @@ -138,24 +114,12 @@ fn owned_shaped_non_empty_args_output_poisons_withdrawal() { ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(poisoned_lock) - .type_(Some(dao).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), + cell(deposit_total_capacity, &poisoned_lock, Some(&dao)), ]) .outputs_data( vec![ @@ -169,8 +133,7 @@ fn owned_shaped_non_empty_args_output_poisons_withdrawal() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_NOT_EMPTY_ARGS); + fail(&context, &tx, ERROR_NOT_EMPTY_ARGS); } // Scenario: a valid withdrawal consumes an owner-side sibling input that uses non-empty args. @@ -196,37 +159,22 @@ fn non_empty_args_owner_sibling_poisons_withdrawal() { 1554, ); let poisoned_owner_input = context.create_cell( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(owner_lock.clone()) - .type_(Some(poisoned_owner_type).pack()) - .build(), + cell(200 * CKB, &owner_lock, Some(&poisoned_owner_type)), owner_distance_data(-1), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(poisoned_owner_input).build()) + .input(input(deposit_input)) + .input(input(udt_input)) + .input(input(poisoned_owner_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), ]) - .outputs_data( - vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack(), - ) + .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .header_dep(deposit_header.hash()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_NOT_EMPTY_ARGS); + fail(&context, &tx, ERROR_NOT_EMPTY_ARGS); } diff --git a/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs b/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs index 94db1fd..d0be575 100644 --- a/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs +++ b/scripts/tests/src/tests/owned_owner/positive_distance_claims.rs @@ -14,49 +14,21 @@ fn adjacent_positive_distance_pair_can_complete_phase2_claim() { let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(200 * CKB, &funding_lock, None), Bytes::new(), ); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); + let udt_input = create_udt(&mut context, &owner_lock, &xudt, u128::from(deposit_amount)); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(deposit_input).build()) + .input(input(funding_input)) + .input(input(udt_input)) + .input(input(deposit_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(filler_lock) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(100 * CKB, &filler_lock, None), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), ]) .outputs_data( vec![ @@ -105,13 +77,8 @@ fn adjacent_positive_distance_pair_can_complete_phase2_claim() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(exact_capacity.pack()) - .lock(owner_lock) - .build(), - ) + .input(input(owner_out_point)) + .output(cell(exact_capacity, &owner_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) @@ -138,49 +105,21 @@ fn sparse_positive_distance_pair_can_complete_phase2_claim_at_exact_capacity() { let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(200 * CKB, &funding_lock, None), Bytes::new(), ); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let udt_input = create_udt(&mut context, &owner_lock, &xudt, u128::from(deposit_amount)); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(deposit_input).build()) + .input(input(funding_input)) + .input(input(udt_input)) + .input(input(deposit_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(filler_lock) - .build(), - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), + cell(100 * CKB, &filler_lock, None), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), ]) .outputs_data( vec![ @@ -229,13 +168,8 @@ fn sparse_positive_distance_pair_can_complete_phase2_claim_at_exact_capacity() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(exact_capacity.pack()) - .lock(owner_lock) - .build(), - ) + .input(input(owner_out_point)) + .output(cell(exact_capacity, &owner_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) @@ -260,57 +194,26 @@ fn secp_protected_sparse_pair_can_complete_signed_phase2_claim() { let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(owner_lock.clone()) - .build(), + cell(100 * CKB, &owner_lock, None), Bytes::new(), ); let filler_input = context.create_cell( - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(filler_lock.clone()) - .build(), + cell(100 * CKB, &filler_lock, None), Bytes::new(), ); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); + let udt_input = create_udt(&mut context, &owner_lock, &xudt, u128::from(deposit_amount)); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .input(CellInput::new_builder().previous_output(filler_input).build()) - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(funding_input)) + .input(input(filler_input)) + .input(input(deposit_input)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity((100 * CKB).pack()) - .lock(filler_lock) - .build(), - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), + cell(100 * CKB, &filler_lock, None), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), ]) .outputs_data( vec![ @@ -350,13 +253,8 @@ fn secp_protected_sparse_pair_can_complete_signed_phase2_claim() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_out_point).build()) - .output( - CellOutput::new_builder() - .capacity(exact_capacity.pack()) - .lock(owner_lock) - .build(), - ) + .input(input(owner_out_point)) + .output(cell(exact_capacity, &owner_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) diff --git a/scripts/tests/src/tests/owned_owner/script_misuse.rs b/scripts/tests/src/tests/owned_owner/script_misuse.rs index e84618e..9b74b2e 100644 --- a/scripts/tests/src/tests/owned_owner/script_misuse.rs +++ b/scripts/tests/src/tests/owned_owner/script_misuse.rs @@ -11,32 +11,20 @@ fn zero_distance_owner_output_is_rejected() { let dao = dao_script(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); - let owned_output = CellOutput::new_builder() - .capacity((1_000 * CKB).pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(); - let owner_output = CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock) - .type_(Some(owned_owner).pack()) - .build(); + let owned_output = cell(1_000 * CKB, &owned_owner, Some(&dao)); + let owner_output = cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![owned_output, owner_output]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(0)].pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); + fail(&context, &tx, ERROR_OWNED_OWNER_MISMATCH); } // Scenario: a live owner input uses distance `0` during phase 2. @@ -55,20 +43,12 @@ fn zero_distance_owner_input_is_rejected() { context.create_cell_with_out_point( owned_input.clone(), - CellOutput::new_builder() - .capacity(123_456_780_000u64.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), + cell(123_456_780_000u64, &owned_owner, Some(&dao)), withdrawal_request_data(1554), ); context.create_cell_with_out_point( owner_input.clone(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner).pack()) - .build(), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), owner_distance_data(0), ); link_cell_to_header(&mut context, &owned_input, &withdraw_header); @@ -82,13 +62,8 @@ fn zero_distance_owner_input_is_rejected() { .since(0x2003e800000002f4u64.pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_input).build()) - .output( - CellOutput::new_builder() - .capacity(123_468_106_670u64.pack()) - .lock(owner_lock) - .build(), - ) + .input(input(owner_input)) + .output(cell(123_468_106_670u64, &owner_lock, None)) .output_data(Bytes::new().pack()) .header_dep(withdraw_header.hash()) .header_dep(deposit_header.hash()) @@ -96,8 +71,7 @@ fn zero_distance_owner_input_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_OWNED_OWNER_MISMATCH); + fail(&context, &tx, ERROR_OWNED_OWNER_MISMATCH); } // Scenario: the owned cell uses DAO deposit bytes instead of withdrawal-request bytes. @@ -111,32 +85,20 @@ fn non_withdrawal_owned_cell_is_rejected() { let dao = dao_script(&mut context); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity((2_000 * CKB).pack()) - .lock(funding_lock) - .build(), + cell(2_000 * CKB, &funding_lock, None), Bytes::new(), ); - let owned_output = CellOutput::new_builder() - .capacity((1_000 * CKB).pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(); - let owner_output = CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock) - .type_(Some(owned_owner).pack()) - .build(); + let owned_output = cell(1_000 * CKB, &owned_owner, Some(&dao)); + let owner_output = cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![owned_output, owner_output]) .outputs_data(vec![dao_deposit_data(), owner_distance_data(-1)].pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_OWNED_OWNER_NOT_WITHDRAW_REQUEST); + fail(&context, &tx, ERROR_OWNED_OWNER_NOT_WITHDRAW_REQUEST); } // A lock-only Owned Owner look-alike can be created with arbitrary type data, but the first spend fails once Owned Owner actually classifies the cell. @@ -146,38 +108,27 @@ fn lock_only_owned_owner_non_dao_output_can_be_created_but_not_spent() { let funding_lock = always_success_lock(&mut context); let owned_owner = owned_owner_script(&mut context); let helper_type = helper_type_script(&mut context); - let funding_input = context.create_cell(CellOutput::new_builder().capacity((500 * CKB).pack()).lock(funding_lock).build(), Bytes::new()); + let funding_input = context.create_cell(cell(500 * CKB, &funding_lock, None), Bytes::new()); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .output( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(owned_owner.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), - ) + .input(input(funding_input)) + .output(cell(200 * CKB, &owned_owner, Some(&helper_type))) .output_data(Bytes::new().pack()) .build(); let create_tx = context.complete_tx(create_tx); context.verify(&create_tx, MAX_CYCLES).expect("lock-only owned_owner misuse cell can be created because output locks do not execute"); let forged_out_point = context.create_cell( - CellOutput::new_builder() - .capacity((200 * CKB).pack()) - .lock(owned_owner) - .type_(Some(helper_type).pack()) - .build(), + cell(200 * CKB, &owned_owner, Some(&helper_type)), Bytes::new(), ); let spend_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(forged_out_point).build()) - .output(CellOutput::new_builder().capacity((200 * CKB).pack()).lock(always_success_lock(&mut context)).build()) + .input(input(forged_out_point)) + .output(cell(200 * CKB, &always_success_lock(&mut context), None)) .output_data(Bytes::new().pack()) .build(); let spend_tx = context.complete_tx(spend_tx); - let err = context.verify(&spend_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_OWNED_OWNER_NOT_WITHDRAW_REQUEST); + fail(&context, &spend_tx, ERROR_OWNED_OWNER_NOT_WITHDRAW_REQUEST); } // The same creation-time gap allows a lock-only DAO-shaped look-alike, but the later spend still fails because it is not a withdrawal request pair. @@ -187,38 +138,24 @@ fn lock_only_owned_owner_dao_deposit_output_can_be_created_but_not_spent() { let funding_lock = always_success_lock(&mut context); let owned_owner = owned_owner_script(&mut context); let dao = dao_script(&mut context); - let funding_input = context.create_cell(CellOutput::new_builder().capacity((2_000 * CKB).pack()).lock(funding_lock).build(), Bytes::new()); + let funding_input = context.create_cell(cell(2_000 * CKB, &funding_lock, None), Bytes::new()); let create_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) - .output( - CellOutput::new_builder() - .capacity((1_000 * CKB).pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - ) + .input(input(funding_input)) + .output(cell(1_000 * CKB, &owned_owner, Some(&dao))) .output_data(dao_deposit_data().pack()) .build(); let create_tx = context.complete_tx(create_tx); context.verify(&create_tx, MAX_CYCLES).expect("DAO deposit with owned_owner only on the output lock can be created"); - let forged_out_point = context.create_cell( - CellOutput::new_builder() - .capacity((1_000 * CKB).pack()) - .lock(owned_owner) - .type_(Some(dao).pack()) - .build(), - dao_deposit_data(), - ); + let forged_out_point = create_deposit(&mut context, 1_000 * CKB, &owned_owner, &dao); let spend_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(forged_out_point).build()) - .output(CellOutput::new_builder().capacity((1_000 * CKB).pack()).lock(always_success_lock(&mut context)).build()) + .input(input(forged_out_point)) + .output(cell(1_000 * CKB, &always_success_lock(&mut context), None)) .output_data(Bytes::new().pack()) .build(); let spend_tx = context.complete_tx(spend_tx); - let err = context.verify(&spend_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_OWNED_OWNER_NOT_WITHDRAW_REQUEST); + fail(&context, &spend_tx, ERROR_OWNED_OWNER_NOT_WITHDRAW_REQUEST); } // Scenario: the same script is used as both lock and type on one cell. @@ -229,20 +166,15 @@ fn cell_using_owned_owner_as_both_lock_and_type_is_rejected() { let funding_lock = always_success_lock(&mut context); let owned_owner = owned_owner_script(&mut context); - let funding_input = context.create_cell(CellOutput::new_builder().capacity((500 * CKB).pack()).lock(funding_lock).build(), Bytes::new()); + let funding_input = context.create_cell(cell(500 * CKB, &funding_lock, None), Bytes::new()); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&owned_owner, &owned_owner, 4).pack()) - .lock(owned_owner.clone()) - .type_(Some(owned_owner).pack()) - .build(), + cell(occupied_capacity(&owned_owner, &owned_owner, 4), &owned_owner, Some(&owned_owner)), ) .output_data(Bytes::from(vec![0u8; 4]).pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_OWNED_OWNER_SCRIPT_MISUSE); + fail(&context, &tx, ERROR_OWNED_OWNER_SCRIPT_MISUSE); } diff --git a/scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs b/scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs index 941ae62..f27e3cc 100644 --- a/scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs +++ b/scripts/tests/src/tests/owned_owner/weak_lock_output_rebinding.rs @@ -20,20 +20,12 @@ fn weak_lock_can_reassign_withdrawal_owner_output() { 1554, ); - let owned_output = CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(); - let owner_output = CellOutput::new_builder() - .capacity(occupied_capacity(&attacker_lock, &owned_owner, 4).pack()) - .lock(attacker_lock) - .type_(Some(owned_owner).pack()) - .build(); + let owned_output = cell(deposit_total_capacity, &owned_owner, Some(&dao)); + let owner_output = cell(occupied_capacity(&attacker_lock, &owned_owner, 4), &attacker_lock, Some(&owned_owner)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(udt_input)) .outputs(vec![owned_output, owner_output]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .header_dep(deposit_header.hash()) @@ -66,19 +58,11 @@ fn sighash_lock_binds_withdrawal_owner_output_to_the_signed_transaction() { ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), ]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .witness(Bytes::new().pack()) @@ -95,20 +79,11 @@ fn sighash_lock_binds_withdrawal_owner_output_to_the_signed_transaction() { let tampered_tx = tx .as_advanced_builder() .set_outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner) - .type_(Some(dao_script(&mut context)).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&attacker_lock, &owned_owner_script(&mut context), 4).pack()) - .lock(attacker_lock) - .type_(Some(owned_owner_script(&mut context)).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao_script(&mut context))), + cell(occupied_capacity(&attacker_lock, &owned_owner_script(&mut context), 4), &attacker_lock, Some(&owned_owner_script(&mut context))), ]) .build(); - let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); + fail(&context, &tampered_tx, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } // Scenario: a batch mixes one signed owner and one weak owner. @@ -127,67 +102,23 @@ fn mixed_sighash_and_weak_udts_bind_all_withdrawal_outputs_once_signed() { let total2 = deposit_capacity(&ickb_logic, &dao, 8, amount2); let header1 = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); let header2 = gen_header(1555, GENESIS_AR as u64, 35, 1000, 1000); - let deposit1 = context.create_cell( - CellOutput::new_builder() - .capacity(total1.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); - let deposit2 = context.create_cell( - CellOutput::new_builder() - .capacity(total2.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit1 = create_deposit(&mut context, total1, &ickb_logic, &dao); + let deposit2 = create_deposit(&mut context, total2, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit1, &header1); link_cell_to_header(&mut context, &deposit2, &header2); - let strong_udt = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - udt_data(u128::from(amount1)), - ); - let weak_udt = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&weak_lock, &xudt, 16).pack()) - .lock(weak_lock) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(amount2)), - ); + let strong_udt = create_udt(&mut context, &owner_lock, &xudt, u128::from(amount1)); + let weak_udt = create_udt(&mut context, &weak_lock, &xudt, u128::from(amount2)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit1).build()) - .input(CellInput::new_builder().previous_output(deposit2).build()) - .input(CellInput::new_builder().previous_output(strong_udt).build()) - .input(CellInput::new_builder().previous_output(weak_udt).build()) + .input(input(deposit1)) + .input(input(deposit2)) + .input(input(strong_udt)) + .input(input(weak_udt)) .outputs(vec![ - CellOutput::new_builder() - .capacity(total1.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(total2.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner).pack()) - .build(), + cell(total1, &owned_owner, Some(&dao)), + cell(total2, &owned_owner, Some(&dao)), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -215,30 +146,13 @@ fn mixed_sighash_and_weak_udts_bind_all_withdrawal_outputs_once_signed() { let tampered_tx = tx .as_advanced_builder() .set_outputs(vec![ - CellOutput::new_builder() - .capacity(total1.pack()) - .lock(owned_owner_script(&mut context)) - .type_(Some(dao_script(&mut context)).pack()) - .build(), - CellOutput::new_builder() - .capacity(total2.pack()) - .lock(owned_owner_script(&mut context)) - .type_(Some(dao_script(&mut context)).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&attacker_lock, &owned_owner_script(&mut context), 4).pack()) - .lock(attacker_lock.clone()) - .type_(Some(owned_owner_script(&mut context)).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&attacker_lock, &owned_owner_script(&mut context), 4).pack()) - .lock(attacker_lock) - .type_(Some(owned_owner_script(&mut context)).pack()) - .build(), + cell(total1, &owned_owner_script(&mut context), Some(&dao_script(&mut context))), + cell(total2, &owned_owner_script(&mut context), Some(&dao_script(&mut context))), + cell(occupied_capacity(&attacker_lock, &owned_owner_script(&mut context), 4), &attacker_lock, Some(&owned_owner_script(&mut context))), + cell(occupied_capacity(&attacker_lock, &owned_owner_script(&mut context), 4), &attacker_lock, Some(&owned_owner_script(&mut context))), ]) .build(); - let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); + fail(&context, &tampered_tx, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } // Scenario: both withdrawal owners are weak locks. @@ -257,67 +171,23 @@ fn two_weak_udts_can_reassign_combined_withdrawal_owner_outputs() { let total2 = deposit_capacity(&ickb_logic, &dao, 8, amount2); let header1 = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); let header2 = gen_header(1555, GENESIS_AR as u64, 35, 1000, 1000); - let deposit1 = context.create_cell( - CellOutput::new_builder() - .capacity(total1.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); - let deposit2 = context.create_cell( - CellOutput::new_builder() - .capacity(total2.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit1 = create_deposit(&mut context, total1, &ickb_logic, &dao); + let deposit2 = create_deposit(&mut context, total2, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit1, &header1); link_cell_to_header(&mut context, &deposit2, &header2); - let weak_udt_1 = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&weak_lock_1, &xudt, 16).pack()) - .lock(weak_lock_1) - .type_(Some(xudt.clone()).pack()) - .build(), - udt_data(u128::from(amount1)), - ); - let weak_udt_2 = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&weak_lock_2, &xudt, 16).pack()) - .lock(weak_lock_2) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(amount2)), - ); + let weak_udt_1 = create_udt(&mut context, &weak_lock_1, &xudt, u128::from(amount1)); + let weak_udt_2 = create_udt(&mut context, &weak_lock_2, &xudt, u128::from(amount2)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit1).build()) - .input(CellInput::new_builder().previous_output(deposit2).build()) - .input(CellInput::new_builder().previous_output(weak_udt_1).build()) - .input(CellInput::new_builder().previous_output(weak_udt_2).build()) + .input(input(deposit1)) + .input(input(deposit2)) + .input(input(weak_udt_1)) + .input(input(weak_udt_2)) .outputs(vec![ - CellOutput::new_builder() - .capacity(total1.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(total2.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&attacker_lock, &owned_owner, 4).pack()) - .lock(attacker_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&attacker_lock, &owned_owner, 4).pack()) - .lock(attacker_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(total1, &owned_owner, Some(&dao)), + cell(total2, &owned_owner, Some(&dao)), + cell(occupied_capacity(&attacker_lock, &owned_owner, 4), &attacker_lock, Some(&owned_owner)), + cell(occupied_capacity(&attacker_lock, &owned_owner, 4), &attacker_lock, Some(&owned_owner)), ]) .outputs_data( vec![ diff --git a/scripts/tests/src/tests/owned_owner/withdrawal_amount_and_headers.rs b/scripts/tests/src/tests/owned_owner/withdrawal_amount_and_headers.rs index bf1b6e7..f12bee1 100644 --- a/scripts/tests/src/tests/owned_owner/withdrawal_amount_and_headers.rs +++ b/scripts/tests/src/tests/owned_owner/withdrawal_amount_and_headers.rs @@ -12,41 +12,22 @@ fn withdrawal_accepts_xudt_input_with_trailing_bytes() { let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); let mut udt_input_data = udt_data(u128::from(deposit_amount)).to_vec(); udt_input_data.push(0xaa); let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, udt_input_data.len()).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt).pack()) - .build(), + cell(occupied_capacity(&user_lock, &xudt, udt_input_data.len()), &user_lock, Some(&xudt)), Bytes::from(udt_input_data), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) - .lock(user_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&user_lock, &owned_owner, 4), &user_lock, Some(&owned_owner)), ]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .header_dep(deposit_header.hash()) @@ -68,47 +49,27 @@ fn withdrawal_rejects_short_xudt_input_data() { let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 8).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt).pack()) - .build(), + cell(occupied_capacity(&user_lock, &xudt, 8), &user_lock, Some(&xudt)), truncated_bytes(udt_data(u128::from(deposit_amount)), 8), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) - .lock(user_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&user_lock, &owned_owner, 4), &user_lock, Some(&owned_owner)), ]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .header_dep(deposit_header.hash()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_ENCODING); + fail(&context, &tx, ERROR_ENCODING); } // Scenario: the xUDT input data is completely empty. @@ -121,47 +82,27 @@ fn withdrawal_rejects_zero_length_xudt_input_data() { let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 0).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt).pack()) - .build(), + cell(occupied_capacity(&user_lock, &xudt, 0), &user_lock, Some(&xudt)), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) - .lock(user_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&user_lock, &owned_owner, 4), &user_lock, Some(&owned_owner)), ]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .header_dep(deposit_header.hash()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_ENCODING); + fail(&context, &tx, ERROR_ENCODING); } // Scenario: the transaction omits the deposit header dep entirely. @@ -174,45 +115,22 @@ fn withdrawal_without_deposit_header_dep_is_rejected() { let deposit_amount = 1_000 * CKB; let (deposit_total_capacity, deposit_header) = deposit_total_capacity_and_header(&ickb_logic, &dao, deposit_amount, 1554); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); + let udt_input = create_udt(&mut context, &user_lock, &xudt, u128::from(deposit_amount)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) - .lock(user_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&user_lock, &owned_owner, 4), &user_lock, Some(&owned_owner)), ]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_ITEM_MISSING); + fail(&context, &tx, ERROR_ITEM_MISSING); } // Scenario: two DAO deposits from different headers are withdrawn together with matching header deps. @@ -229,59 +147,22 @@ fn withdrawal_with_two_deposits_from_distinct_headers_passes() { let second_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, second_amount); let first_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); let second_header = gen_header(1555, GENESIS_AR as u64, 35, 1000, 1000); - let first_deposit = context.create_cell( - CellOutput::new_builder() - .capacity(first_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); - let second_deposit = context.create_cell( - CellOutput::new_builder() - .capacity(second_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let first_deposit = create_deposit(&mut context, first_total_capacity, &ickb_logic, &dao); + let second_deposit = create_deposit(&mut context, second_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &first_deposit, &first_header); link_cell_to_header(&mut context, &second_deposit, &second_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(first_amount + second_amount)), - ); + let udt_input = create_udt(&mut context, &user_lock, &xudt, u128::from(first_amount + second_amount)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(first_deposit).build()) - .input(CellInput::new_builder().previous_output(second_deposit).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(funding_cell(&mut context)).build()) + .input(input(first_deposit)) + .input(input(second_deposit)) + .input(input(udt_input)) + .input(input(funding_cell(&mut context))) .outputs(vec![ - CellOutput::new_builder() - .capacity(first_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(second_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) - .lock(user_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(first_total_capacity, &owned_owner, Some(&dao)), + cell(second_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&user_lock, &owned_owner, 4), &user_lock, Some(&owned_owner)), + cell(occupied_capacity(&user_lock, &owned_owner, 4), &user_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -316,58 +197,21 @@ fn withdrawal_with_one_missing_deposit_header_dep_is_rejected() { let second_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, second_amount); let first_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); let second_header = gen_header(1555, GENESIS_AR as u64, 35, 1000, 1000); - let first_deposit = context.create_cell( - CellOutput::new_builder() - .capacity(first_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); - let second_deposit = context.create_cell( - CellOutput::new_builder() - .capacity(second_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let first_deposit = create_deposit(&mut context, first_total_capacity, &ickb_logic, &dao); + let second_deposit = create_deposit(&mut context, second_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &first_deposit, &first_header); link_cell_to_header(&mut context, &second_deposit, &second_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(first_amount + second_amount)), - ); + let udt_input = create_udt(&mut context, &user_lock, &xudt, u128::from(first_amount + second_amount)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(first_deposit).build()) - .input(CellInput::new_builder().previous_output(second_deposit).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(first_deposit)) + .input(input(second_deposit)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(first_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(second_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) - .lock(user_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(first_total_capacity, &owned_owner, Some(&dao)), + cell(second_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&user_lock, &owned_owner, 4), &user_lock, Some(&owned_owner)), + cell(occupied_capacity(&user_lock, &owned_owner, 4), &user_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -382,8 +226,7 @@ fn withdrawal_with_one_missing_deposit_header_dep_is_rejected() { .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_ITEM_MISSING); + fail(&context, &tx, ERROR_ITEM_MISSING); } // Scenario: the deposit header is present but its accumulated rate is zero. @@ -397,46 +240,23 @@ fn withdrawal_with_zero_accumulated_rate_deposit_header_is_rejected() { let deposit_amount = 1_000 * CKB; let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, deposit_amount); let malformed_header = gen_header(1554, 0, 35, 1000, 1000); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &malformed_header); - let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &xudt, 16).pack()) - .lock(user_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(u128::from(deposit_amount)), - ); + let udt_input = create_udt(&mut context, &user_lock, &xudt, u128::from(deposit_amount)); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&user_lock, &owned_owner, 4).pack()) - .lock(user_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&user_lock, &owned_owner, 4), &user_lock, Some(&owned_owner)), ]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .header_dep(malformed_header.hash()) .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SCRIPT_PANIC); + fail(&context, &tx, ERROR_SCRIPT_PANIC); } // Scenario: the withdrawal amount is above the soft-cap boundary. @@ -450,68 +270,30 @@ fn withdrawal_applies_soft_cap_discount_above_boundary() { let amount = 100_001 * CKB; let deposit_total_capacity = deposit_capacity(&ickb_logic, &dao, 8, amount); let deposit_header = gen_header(1554, GENESIS_AR, 35, 1000, 1000); - let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - dao_deposit_data(), - ); + let deposit_input = create_deposit(&mut context, deposit_total_capacity, &ickb_logic, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); - let naive_udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - udt_data(u128::from(amount)), - ); + let naive_udt_input = create_udt(&mut context, &owner_lock, &xudt, u128::from(amount)); let naive_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input.clone()).build()) - .input(CellInput::new_builder().previous_output(naive_udt_input).build()) + .input(input(deposit_input.clone())) + .input(input(naive_udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), ]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .header_dep(deposit_header.hash()) .build(); let naive_tx = context.complete_tx(naive_tx); - let err = context.verify(&naive_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_AMOUNT_MISMATCH); - - let exact_udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &xudt, 16).pack()) - .lock(owner_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - udt_data(soft_capped_ickb(amount, GENESIS_AR)), - ); + fail(&context, &naive_tx, ERROR_AMOUNT_MISMATCH); + + let exact_udt_input = create_udt(&mut context, &owner_lock, &xudt, soft_capped_ickb(amount, GENESIS_AR)); let exact_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(exact_udt_input).build()) + .input(input(deposit_input)) + .input(input(exact_udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(deposit_total_capacity.pack()) - .lock(owned_owner.clone()) - .type_(Some(dao).pack()) - .build(), - CellOutput::new_builder() - .capacity(occupied_capacity(&owner_lock, &owned_owner, 4).pack()) - .lock(owner_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(deposit_total_capacity, &owned_owner, Some(&dao)), + cell(occupied_capacity(&owner_lock, &owned_owner, 4), &owner_lock, Some(&owned_owner)), ]) .outputs_data(vec![withdrawal_request_data(1554), owner_distance_data(-1)].pack()) .header_dep(deposit_header.hash()) diff --git a/scripts/tests/src/tests/protocol_vectors.rs b/scripts/tests/src/tests/protocol_vectors.rs index f7abd1b..905a213 100644 --- a/scripts/tests/src/tests/protocol_vectors.rs +++ b/scripts/tests/src/tests/protocol_vectors.rs @@ -21,26 +21,13 @@ fn every_deposit_vector_mints_exactly_its_expected_ickb() { let mut context = Context::default(); let funding_lock = always_success_lock(&mut context); let (ickb_logic, xudt) = ickb_logic_and_xudt_scripts(&mut context); - let receipt = context.create_cell( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &ickb_logic, 12).pack()) - .lock(funding_lock.clone()) - .type_(Some(ickb_logic).pack()) - .build(), - receipt_data(1, row.amount), - ); + let receipt = create_receipt(&mut context, &funding_lock, &ickb_logic, 1, row.amount); let header = insert_header_for_cell(&mut context, &receipt, 0, row.ar); for minted in [row.expected_ickb, row.expected_ickb + 1, row.expected_ickb - 1] { let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(receipt.clone()).build()) - .output( - CellOutput::new_builder() - .capacity(occupied_capacity(&funding_lock, &xudt, 16).pack()) - .lock(funding_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - ) + .input(input(receipt.clone())) + .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(minted).pack()) .header_dep(header.clone()) .build(); @@ -76,11 +63,7 @@ fn every_limit_order_vector_gets_the_verdict_of_the_copied_validate() { } let order = |unoccupied: u64, udt: u128| { ( - CellOutput::new_builder() - .capacity((occupied + unoccupied).pack()) - .lock(limit_order.clone()) - .type_(Some(helper_type.clone()).pack()) - .build(), + cell(occupied + unoccupied, &limit_order, Some(&helper_type)), order_data_custom( udt, 1, @@ -94,11 +77,11 @@ fn every_limit_order_vector_gets_the_verdict_of_the_copied_validate() { }; let (input_cell, input_data) = order(in_unoccupied, in_udt); let (output_cell, output_data) = order(out_unoccupied, out_udt); - let input = context.create_cell(input_cell, input_data); + let order_input = context.create_cell(input_cell, input_data); // ckb-testtool runs scripts only, so the transaction needs no capacity balancing. let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(input).build()) + .input(input(order_input)) .output(output_cell) .output_data(output_data.pack()) .build(); diff --git a/scripts/tests/src/tests/replay/family_attacker_limit_order.rs b/scripts/tests/src/tests/replay/family_attacker_limit_order.rs index 15d70e2..a42e56c 100644 --- a/scripts/tests/src/tests/replay/family_attacker_limit_order.rs +++ b/scripts/tests/src/tests/replay/family_attacker_limit_order.rs @@ -63,11 +63,7 @@ fn weak_lock_derived_five_claim_live_batch_can_flow_into_later_attacker_owned_li let out_point = OutPoint::new(batch_tx_hash.clone(), index as u32); context.create_cell_with_out_point( out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex(owned_capacities[index]).pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex(owned_capacities[index]), &owned_owner, Some(&dao)), bytes_from_hex(owned_data[index]), ); link_cell_to_header(&mut context, &out_point, &withdraw_header); @@ -80,11 +76,7 @@ fn weak_lock_derived_five_claim_live_batch_can_flow_into_later_attacker_owned_li let out_point = OutPoint::new(batch_tx_hash.clone(), (index as u32) + 5); context.create_cell_with_out_point( out_point, - CellOutput::new_builder() - .capacity(u64_from_hex("0x2540be400").pack()) - .lock(attacker_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(u64_from_hex("0x2540be400"), &attacker_lock, Some(&owned_owner)), bytes_from_hex("0xfbffffff"), ); } @@ -120,26 +112,15 @@ fn weak_lock_derived_five_claim_live_batch_can_flow_into_later_attacker_owned_li .since(u64_from_hex("0x2007080261002c79").pack()) .build(), ) - .input(CellInput::new_builder().previous_output(OutPoint::new(batch_tx_hash.clone(), 9)).build()) - .input(CellInput::new_builder().previous_output(OutPoint::new(batch_tx_hash.clone(), 8)).build()) - .input(CellInput::new_builder().previous_output(OutPoint::new(batch_tx_hash.clone(), 7)).build()) - .input(CellInput::new_builder().previous_output(OutPoint::new(batch_tx_hash.clone(), 6)).build()) - .input(CellInput::new_builder().previous_output(OutPoint::new(batch_tx_hash, 5)).build()) + .input(input(OutPoint::new(batch_tx_hash.clone(), 9))) + .input(input(OutPoint::new(batch_tx_hash.clone(), 8))) + .input(input(OutPoint::new(batch_tx_hash.clone(), 7))) + .input(input(OutPoint::new(batch_tx_hash.clone(), 6))) + .input(input(OutPoint::new(batch_tx_hash, 5))) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(attacker_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x1bea98cf00").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x34d6567f32d3").pack()) - .lock(attacker_lock.clone()) - .build(), + cell(u64_from_hex("0x23c346000"), &attacker_lock, Some(&limit_order)), + cell(u64_from_hex("0x1bea98cf00"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x34d6567f32d3"), &attacker_lock, None), ]) .outputs_data( vec![ @@ -192,13 +173,10 @@ fn weak_lock_derived_five_claim_live_batch_can_flow_into_later_attacker_owned_li ); let melt_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order_out_point).build()) - .input(CellInput::new_builder().previous_output(master_out_point).build()) + .input(input(order_out_point)) + .input(input(master_out_point)) .output( - CellOutput::new_builder() - .capacity((u64_from_hex("0x1bea98cf00") + u64_from_hex("0x23c346000")).pack()) - .lock(attacker_lock) - .build(), + cell(u64_from_hex("0x1bea98cf00") + u64_from_hex("0x23c346000"), &attacker_lock, None), ) .output_data(Bytes::new().pack()) .build(); @@ -273,11 +251,7 @@ fn weak_lock_derived_eight_claim_batch_can_flow_into_later_attacker_owned_limit_ let out_point = OutPoint::new(batch_tx_hash.clone(), index as u32); context.create_cell_with_out_point( out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex(owned_capacities[index]).pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex(owned_capacities[index]), &owned_owner, Some(&dao)), bytes_from_hex(owned_data[index]), ); link_cell_to_header(&mut context, &out_point, &withdraw_header); @@ -286,40 +260,25 @@ fn weak_lock_derived_eight_claim_batch_can_flow_into_later_attacker_owned_limit_ let out_point = OutPoint::new(batch_tx_hash.clone(), (index as u32) + 8); context.create_cell_with_out_point( out_point, - CellOutput::new_builder() - .capacity(u64_from_hex("0x2540be400").pack()) - .lock(attacker_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(u64_from_hex("0x2540be400"), &attacker_lock, Some(&owned_owner)), bytes_from_hex("0xf8ffffff"), ); } context.create_cell_with_out_point( OutPoint::new(batch_tx_hash.clone(), 16), - CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(attacker_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), + cell(u64_from_hex("0x23c346000"), &attacker_lock, Some(&limit_order)), Bytes::new(), ); context.create_cell_with_out_point( OutPoint::new(batch_tx_hash.clone(), 17), - CellOutput::new_builder() - .capacity(u64_from_hex("0x4a221e700").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x4a221e700"), &limit_order, Some(&xudt)), bytes_from_hex( "0xd45e0323c20200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff000000000000000000000000000000000000c16ff2862300fe12a4eaa0ca290021", ), ); context.create_cell_with_out_point( OutPoint::new(batch_tx_hash.clone(), 18), - CellOutput::new_builder() - .capacity(u64_from_hex("0x142514df48").pack()) - .lock(attacker_lock.clone()) - .build(), + cell(u64_from_hex("0x142514df48"), &attacker_lock, None), Bytes::new(), ); @@ -329,9 +288,9 @@ fn weak_lock_derived_eight_claim_batch_can_flow_into_later_attacker_owned_limit_ let witness_4 = header_dep_index_witness(4); let later_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(OutPoint::new(batch_tx_hash.clone(), 17)).build()) - .input(CellInput::new_builder().previous_output(OutPoint::new(batch_tx_hash.clone(), 16)).build()) - .input(CellInput::new_builder().previous_output(OutPoint::new(batch_tx_hash.clone(), 18)).build()) + .input(input(OutPoint::new(batch_tx_hash.clone(), 17))) + .input(input(OutPoint::new(batch_tx_hash.clone(), 16))) + .input(input(OutPoint::new(batch_tx_hash.clone(), 18))) .input( CellInput::new_builder() .previous_output(OutPoint::new(batch_tx_hash.clone(), 6)) @@ -374,68 +333,25 @@ fn weak_lock_derived_eight_claim_batch_can_flow_into_later_attacker_owned_limit_ .since(u64_from_hex("0x2004ad01f0003124").pack()) .build(), ) - .input(CellInput::new_builder().previous_output(OutPoint::new(batch_tx_hash.clone(), 14)).build()) - .input(CellInput::new_builder().previous_output(OutPoint::new(batch_tx_hash.clone(), 13)).build()) - .input(CellInput::new_builder().previous_output(OutPoint::new(batch_tx_hash.clone(), 12)).build()) - .input(CellInput::new_builder().previous_output(OutPoint::new(batch_tx_hash.clone(), 11)).build()) - .input(CellInput::new_builder().previous_output(OutPoint::new(batch_tx_hash.clone(), 10)).build()) - .input(CellInput::new_builder().previous_output(OutPoint::new(batch_tx_hash.clone(), 9)).build()) - .input(CellInput::new_builder().previous_output(OutPoint::new(batch_tx_hash, 8)).build()) + .input(input(OutPoint::new(batch_tx_hash.clone(), 14))) + .input(input(OutPoint::new(batch_tx_hash.clone(), 13))) + .input(input(OutPoint::new(batch_tx_hash.clone(), 12))) + .input(input(OutPoint::new(batch_tx_hash.clone(), 11))) + .input(input(OutPoint::new(batch_tx_hash.clone(), 10))) + .input(input(OutPoint::new(batch_tx_hash.clone(), 9))) + .input(input(OutPoint::new(batch_tx_hash, 8))) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0xab5f2c8d6b0").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xab5f2c8d6b0").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xab5f2c8d6b0").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xab5f2c8d6b0").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xab5f2c8d6b0").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xab5f2c8d6b0").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x283baec00").pack()) - .lock(attacker_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(attacker_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa4a505d73a0").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x372261400").pack()) - .lock(attacker_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x8c3ee380ed").pack()) - .lock(attacker_lock.clone()) - .build(), + cell(u64_from_hex("0xab5f2c8d6b0"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0xab5f2c8d6b0"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0xab5f2c8d6b0"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0xab5f2c8d6b0"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0xab5f2c8d6b0"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0xab5f2c8d6b0"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0x283baec00"), &attacker_lock, Some(&ickb_logic)), + cell(u64_from_hex("0x23c346000"), &attacker_lock, Some(&limit_order)), + cell(u64_from_hex("0xa4a505d73a0"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x372261400"), &attacker_lock, Some(&xudt)), + cell(u64_from_hex("0x8c3ee380ed"), &attacker_lock, None), ]) .outputs_data( vec![ @@ -501,13 +417,10 @@ fn weak_lock_derived_eight_claim_batch_can_flow_into_later_attacker_owned_limit_ ); let melt_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order_out_point).build()) - .input(CellInput::new_builder().previous_output(master_out_point).build()) + .input(input(order_out_point)) + .input(input(master_out_point)) .output( - CellOutput::new_builder() - .capacity((u64_from_hex("0xa4a505d73a0") + u64_from_hex("0x23c346000")).pack()) - .lock(attacker_lock) - .build(), + cell(u64_from_hex("0xa4a505d73a0") + u64_from_hex("0x23c346000"), &attacker_lock, None), ) .output_data(Bytes::new().pack()) .build(); diff --git a/scripts/tests/src/tests/replay/family_mainnet_eight_claim.rs b/scripts/tests/src/tests/replay/family_mainnet_eight_claim.rs index 23a5d1e..ea88046 100644 --- a/scripts/tests/src/tests/replay/family_mainnet_eight_claim.rs +++ b/scripts/tests/src/tests/replay/family_mainnet_eight_claim.rs @@ -53,11 +53,7 @@ fn weak_mainnet_eight_claim_batch_can_reassign_later_phase2_claimants() { let mut deposit_inputs = Vec::with_capacity(deposit_specs.len()); for (capacity, header_index) in deposit_specs { let out_point = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex(capacity).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex(capacity), &ickb_logic, Some(&dao)), bytes_from_hex("0x0000000000000000"), ); link_cell_to_header(&mut context, &out_point, &deposit_headers[header_index]); @@ -65,18 +61,11 @@ fn weak_mainnet_eight_claim_batch_can_reassign_later_phase2_claimants() { } let change_input = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex("0x2a31a45188").pack()) - .lock(weak_lock.clone()) - .build(), + cell(u64_from_hex("0x2a31a45188"), &weak_lock, None), Bytes::new(), ); let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex("0x372261400").pack()) - .lock(weak_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x372261400"), &weak_lock, Some(&xudt)), bytes_from_hex("0x4a026c96844b00000000000000000000"), ); @@ -104,49 +93,20 @@ fn weak_mainnet_eight_claim_batch_can_reassign_later_phase2_claimants() { let mut outputs = Vec::new(); let mut outputs_data = Vec::new(); for (capacity, data) in owned_capacities.iter().zip(owned_datas.iter()) { - outputs.push( - CellOutput::new_builder() - .capacity(u64_from_hex(capacity).pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - ); + outputs.push(cell(u64_from_hex(capacity), &owned_owner, Some(&dao))); outputs_data.push(bytes_from_hex(data)); } for _ in 0..8 { - outputs.push( - CellOutput::new_builder() - .capacity(u64_from_hex("0x2540be400").pack()) - .lock(attacker_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - ); + outputs.push(cell(u64_from_hex("0x2540be400"), &attacker_lock, Some(&owned_owner))); outputs_data.push(bytes_from_hex("0xf8ffffff")); } - outputs.push( - CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(weak_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), - ); + outputs.push(cell(u64_from_hex("0x23c346000"), &weak_lock, Some(&limit_order))); outputs_data.push(Bytes::new()); - outputs.push( - CellOutput::new_builder() - .capacity(u64_from_hex("0x4a221e700").pack()) - .lock(limit_order) - .type_(Some(xudt.clone()).pack()) - .build(), - ); + outputs.push(cell(u64_from_hex("0x4a221e700"), &limit_order, Some(&xudt))); outputs_data.push(bytes_from_hex( "0xd45e0323c20200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff000000000000000000000000000000000000c16ff2862300fe12a4eaa0ca290021", )); - outputs.push( - CellOutput::new_builder() - .capacity(u64_from_hex("0x142514df48").pack()) - .lock(weak_lock.clone()) - .build(), - ); + outputs.push(cell(u64_from_hex("0x142514df48"), &weak_lock, None)); outputs_data.push(Bytes::new()); let first_tx = TransactionBuilder::default() @@ -155,7 +115,7 @@ fn weak_mainnet_eight_claim_batch_can_reassign_later_phase2_claimants() { .iter() .cloned() .chain([change_input.clone(), udt_input.clone()]) - .map(|out_point| CellInput::new_builder().previous_output(out_point).build()) + .map(input) .collect::>(), ) .outputs(outputs) @@ -206,13 +166,8 @@ fn weak_mainnet_eight_claim_batch_can_reassign_later_phase2_claimants() { .since(u64_from_hex("0x2004ad01f0003124").pack()) .build(), ) - .input(CellInput::new_builder().previous_output(fresh_owner).build()) - .output( - CellOutput::new_builder() - .capacity(claim_capacity.pack()) - .lock(attacker_lock.clone()) - .build(), - ) + .input(input(fresh_owner)) + .output(cell(claim_capacity, &attacker_lock, None)) .output_data(Bytes::new().pack()) .witness(witness.pack()) .witness(empty_witness().pack()) @@ -281,11 +236,7 @@ fn sighash_mainnet_eight_claim_batch_binds_fresh_owner_outputs() { let mut deposit_inputs = Vec::with_capacity(deposit_specs.len()); for (capacity, header_index) in deposit_specs { let out_point = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex(capacity).pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex(capacity), &ickb_logic, Some(&dao)), bytes_from_hex("0x0000000000000000"), ); link_cell_to_header(&mut context, &out_point, &deposit_headers[header_index]); @@ -293,18 +244,11 @@ fn sighash_mainnet_eight_claim_batch_binds_fresh_owner_outputs() { } let change_input = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex("0x2a31a45188").pack()) - .lock(strong_lock.clone()) - .build(), + cell(u64_from_hex("0x2a31a45188"), &strong_lock, None), Bytes::new(), ); let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex("0x372261400").pack()) - .lock(strong_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x372261400"), &strong_lock, Some(&xudt)), bytes_from_hex("0x4a026c96844b00000000000000000000"), ); @@ -332,49 +276,20 @@ fn sighash_mainnet_eight_claim_batch_binds_fresh_owner_outputs() { let mut outputs = Vec::new(); let mut outputs_data = Vec::new(); for (capacity, data) in owned_capacities.iter().zip(owned_datas.iter()) { - outputs.push( - CellOutput::new_builder() - .capacity(u64_from_hex(capacity).pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - ); + outputs.push(cell(u64_from_hex(capacity), &owned_owner, Some(&dao))); outputs_data.push(bytes_from_hex(data)); } for _ in 0..8 { - outputs.push( - CellOutput::new_builder() - .capacity(u64_from_hex("0x2540be400").pack()) - .lock(weak_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - ); + outputs.push(cell(u64_from_hex("0x2540be400"), &weak_lock, Some(&owned_owner))); outputs_data.push(bytes_from_hex("0xf8ffffff")); } - outputs.push( - CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(strong_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), - ); + outputs.push(cell(u64_from_hex("0x23c346000"), &strong_lock, Some(&limit_order))); outputs_data.push(Bytes::new()); - outputs.push( - CellOutput::new_builder() - .capacity(u64_from_hex("0x4a221e700").pack()) - .lock(limit_order) - .type_(Some(xudt.clone()).pack()) - .build(), - ); + outputs.push(cell(u64_from_hex("0x4a221e700"), &limit_order, Some(&xudt))); outputs_data.push(bytes_from_hex( "0xd45e0323c20200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff000000000000000000000000000000000000c16ff2862300fe12a4eaa0ca290021", )); - outputs.push( - CellOutput::new_builder() - .capacity(u64_from_hex("0x142514df48").pack()) - .lock(strong_lock.clone()) - .build(), - ); + outputs.push(cell(u64_from_hex("0x142514df48"), &strong_lock, None)); outputs_data.push(Bytes::new()); let tx = TransactionBuilder::default() @@ -383,7 +298,7 @@ fn sighash_mainnet_eight_claim_batch_binds_fresh_owner_outputs() { .iter() .cloned() .chain([change_input.clone(), udt_input.clone()]) - .map(|out_point| CellInput::new_builder().previous_output(out_point).build()) + .map(input) .collect::>(), ) .outputs(outputs) @@ -427,11 +342,7 @@ fn sighash_mainnet_eight_claim_batch_binds_fresh_owner_outputs() { tx.outputs().get(5).expect("fresh owned output 5"), tx.outputs().get(6).expect("fresh owned output 6"), tx.outputs().get(7).expect("fresh owned output 7"), - CellOutput::new_builder() - .capacity(u64_from_hex("0x2540be400").pack()) - .lock(attacker_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(u64_from_hex("0x2540be400"), &attacker_lock, Some(&owned_owner)), tx.outputs().get(9).expect("fresh owner output 1"), tx.outputs().get(10).expect("fresh owner output 2"), tx.outputs().get(11).expect("fresh owner output 3"), @@ -444,6 +355,5 @@ fn sighash_mainnet_eight_claim_batch_binds_fresh_owner_outputs() { tx.outputs().get(18).expect("change output"), ]) .build(); - let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); + fail(&context, &tampered_tx, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } diff --git a/scripts/tests/src/tests/replay/family_mixed_restake.rs b/scripts/tests/src/tests/replay/family_mixed_restake.rs index b6f5cfa..a96e89c 100644 --- a/scripts/tests/src/tests/replay/family_mixed_restake.rs +++ b/scripts/tests/src/tests/replay/family_mixed_restake.rs @@ -31,11 +31,7 @@ fn weak_live_mixed_restake_can_reassign_later_phase2_claimants() { ); context.create_cell_with_out_point( deposit_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e67c62b2c").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa5e67c62b2c"), &ickb_logic, Some(&dao)), bytes_from_hex("0x0000000000000000"), ); link_cell_to_header(&mut context, &deposit_input, &fresh_deposit_header); @@ -46,10 +42,7 @@ fn weak_live_mixed_restake_can_reassign_later_phase2_claimants() { ); context.create_cell_with_out_point( change_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x13b71a4e3b").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0x13b71a4e3b"), &user_lock, None), Bytes::new(), ); @@ -59,11 +52,7 @@ fn weak_live_mixed_restake_can_reassign_later_phase2_claimants() { ); context.create_cell_with_out_point( udt_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), bytes_from_hex("0xca482089660200000000000000000000"), ); @@ -73,11 +62,7 @@ fn weak_live_mixed_restake_can_reassign_later_phase2_claimants() { ); context.create_cell_with_out_point( owned_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e673651b7").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa5e673651b7"), &owned_owner, Some(&dao)), bytes_from_hex("0xdb6ede0000000000"), ); link_cell_to_header(&mut context, &owned_input, &prior_withdraw_header); @@ -88,11 +73,7 @@ fn weak_live_mixed_restake_can_reassign_later_phase2_claimants() { ); context.create_cell_with_out_point( owner_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(u64_from_hex("0x248202200"), &user_lock, Some(&owned_owner)), bytes_from_hex("0xfeffffff"), ); @@ -102,11 +83,7 @@ fn weak_live_mixed_restake_can_reassign_later_phase2_claimants() { ); context.create_cell_with_out_point( order_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x2f9ea8dd8e2c").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x2f9ea8dd8e2c"), &limit_order, Some(&xudt)), bytes_from_hex( "0xfc643f14592300000000000000000000010000001594bf3a65929bf5ee706f3c34e5c92d993adc405e58c3934661aeaa4e19264704000000000000000000000000000000000000000000c16ff28623008cb96cb2f30b290021", ), @@ -115,42 +92,23 @@ fn weak_live_mixed_restake_can_reassign_later_phase2_claimants() { context.insert_header(prior_deposit_header.clone()); let first_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(change_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(change_input)) + .input(input(udt_input)) .input( CellInput::new_builder() .previous_output(owned_input) .since(u64_from_hex("0x20070804f20029d3").pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_input).build()) - .input(CellInput::new_builder().previous_output(order_input).build()) + .input(input(owner_input)) + .input(input(order_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e67c62b2c").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3a20c2ac1968").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(attacker_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x13b55a06cc").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0xa5e67c62b2c"), &owned_owner, Some(&dao)), + cell(u64_from_hex("0x3a20c2ac1968"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x248202200"), &attacker_lock, Some(&owned_owner)), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), + cell(u64_from_hex("0x13b55a06cc"), &user_lock, None), ]) .outputs_data( vec![ @@ -209,11 +167,7 @@ fn weak_live_mixed_restake_can_reassign_later_phase2_claimants() { ); context.create_cell_with_out_point( later_order_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x4487f6435e53").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x4487f6435e53"), &limit_order, Some(&xudt)), bytes_from_hex( "0x5565b9a23f1100000000000000000000010000001594bf3a65929bf5ee706f3c34e5c92d993adc405e58c3934661aeaa4e19264704000000000000000000000000000000000000000000c16ff28623008cb96cb2f30b290021", ), @@ -225,11 +179,7 @@ fn weak_live_mixed_restake_can_reassign_later_phase2_claimants() { ); context.create_cell_with_out_point( later_udt_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), bytes_from_hex("0x276736ac670b00000000000000000000"), ); @@ -239,39 +189,25 @@ fn weak_live_mixed_restake_can_reassign_later_phase2_claimants() { ); context.create_cell_with_out_point( later_change_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x30e25b5441").pack()) - .lock(user_lock) - .build(), + cell(u64_from_hex("0x30e25b5441"), &user_lock, None), Bytes::new(), ); let second_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(later_change_input).build()) - .input(CellInput::new_builder().previous_output(later_udt_input).build()) + .input(input(later_change_input)) + .input(input(later_udt_input)) .input( CellInput::new_builder() .previous_output(fresh_owned) .since(u64_from_hex("0x200708057c0029d3").pack()) .build(), ) - .input(CellInput::new_builder().previous_output(fresh_owner).build()) - .input(CellInput::new_builder().previous_output(later_order_input).build()) + .input(input(fresh_owner)) + .input(input(later_order_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0x4f0a109fcf57").pack()) - .lock(limit_order) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(attacker_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3329ed7100").pack()) - .lock(attacker_lock) - .build(), + cell(u64_from_hex("0x4f0a109fcf57"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x3663a5200"), &attacker_lock, Some(&xudt)), + cell(u64_from_hex("0x3329ed7100"), &attacker_lock, None), ]) .outputs_data( vec![ @@ -333,10 +269,7 @@ fn sighash_live_mixed_restake_binds_fresh_owner_output() { ); context.create_cell_with_out_point( change_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x13b71a4e3b").pack()) - .lock(strong_lock.clone()) - .build(), + cell(u64_from_hex("0x13b71a4e3b"), &strong_lock, None), Bytes::new(), ); let udt_input = out_point_from_hex( @@ -345,11 +278,7 @@ fn sighash_live_mixed_restake_binds_fresh_owner_output() { ); context.create_cell_with_out_point( udt_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(strong_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x3663a5200"), &strong_lock, Some(&xudt)), bytes_from_hex("0xca482089660200000000000000000000"), ); let owner_input = out_point_from_hex( @@ -358,11 +287,7 @@ fn sighash_live_mixed_restake_binds_fresh_owner_output() { ); context.create_cell_with_out_point( owner_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(weak_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(u64_from_hex("0x248202200"), &weak_lock, Some(&owned_owner)), bytes_from_hex("0xfeffffff"), ); @@ -372,11 +297,7 @@ fn sighash_live_mixed_restake_binds_fresh_owner_output() { ); context.create_cell_with_out_point( deposit_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e67c62b2c").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa5e67c62b2c"), &ickb_logic, Some(&dao)), bytes_from_hex("0x0000000000000000"), ); link_cell_to_header(&mut context, &deposit_input, &fresh_deposit_header); @@ -387,11 +308,7 @@ fn sighash_live_mixed_restake_binds_fresh_owner_output() { ); context.create_cell_with_out_point( owned_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e673651b7").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa5e673651b7"), &owned_owner, Some(&dao)), bytes_from_hex("0xdb6ede0000000000"), ); link_cell_to_header(&mut context, &owned_input, &prior_withdraw_header); @@ -402,11 +319,7 @@ fn sighash_live_mixed_restake_binds_fresh_owner_output() { ); context.create_cell_with_out_point( order_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x2f9ea8dd8e2c").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x2f9ea8dd8e2c"), &limit_order, Some(&xudt)), bytes_from_hex( "0xfc643f14592300000000000000000000010000001594bf3a65929bf5ee706f3c34e5c92d993adc405e58c3934661aeaa4e19264704000000000000000000000000000000000000000000c16ff28623008cb96cb2f30b290021", ), @@ -415,42 +328,23 @@ fn sighash_live_mixed_restake_binds_fresh_owner_output() { context.insert_header(prior_deposit_header.clone()); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(change_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(change_input)) + .input(input(udt_input)) .input( CellInput::new_builder() .previous_output(owned_input) .since(u64_from_hex("0x20070804f20029d3").pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_input).build()) - .input(CellInput::new_builder().previous_output(order_input).build()) + .input(input(owner_input)) + .input(input(order_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e67c62b2c").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3a20c2ac1968").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(weak_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(strong_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x13b55a06cc").pack()) - .lock(strong_lock.clone()) - .build(), + cell(u64_from_hex("0xa5e67c62b2c"), &owned_owner, Some(&dao)), + cell(u64_from_hex("0x3a20c2ac1968"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x248202200"), &weak_lock, Some(&owned_owner)), + cell(u64_from_hex("0x3663a5200"), &strong_lock, Some(&xudt)), + cell(u64_from_hex("0x13b55a06cc"), &strong_lock, None), ]) .outputs_data( vec![ @@ -489,15 +383,10 @@ fn sighash_live_mixed_restake_binds_fresh_owner_output() { .set_outputs(vec![ tx.outputs().get(0).expect("fresh owned output"), tx.outputs().get(1).expect("order output"), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(attacker_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(u64_from_hex("0x248202200"), &attacker_lock, Some(&owned_owner)), tx.outputs().get(3).expect("udt output"), tx.outputs().get(4).expect("change output"), ]) .build(); - let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); + fail(&context, &tampered_tx, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } diff --git a/scripts/tests/src/tests/replay/family_two_claim_restake.rs b/scripts/tests/src/tests/replay/family_two_claim_restake.rs index 75ed19c..f9b780a 100644 --- a/scripts/tests/src/tests/replay/family_two_claim_restake.rs +++ b/scripts/tests/src/tests/replay/family_two_claim_restake.rs @@ -31,11 +31,7 @@ fn weak_two_claim_live_restake_can_reassign_later_phase2_claimants() { ); context.create_cell_with_out_point( deposit_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa6386d7249d").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa6386d7249d"), &ickb_logic, Some(&dao)), bytes_from_hex("0x0000000000000000"), ); link_cell_to_header(&mut context, &deposit_input, &fresh_deposit_header); @@ -46,10 +42,7 @@ fn weak_two_claim_live_restake_can_reassign_later_phase2_claimants() { ); context.create_cell_with_out_point( change_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x13bbb34e26").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0x13bbb34e26"), &user_lock, None), Bytes::new(), ); @@ -59,11 +52,7 @@ fn weak_two_claim_live_restake_can_reassign_later_phase2_claimants() { ); context.create_cell_with_out_point( udt_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), bytes_from_hex("0xa0bfc96d660200000000000000000000"), ); @@ -77,20 +66,12 @@ fn weak_two_claim_live_restake_can_reassign_later_phase2_claimants() { ); context.create_cell_with_out_point( owned_input_1.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e609441a1").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa5e609441a1"), &owned_owner, Some(&dao)), bytes_from_hex("0x7f68de0000000000"), ); context.create_cell_with_out_point( owned_input_0.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e609441a1").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa5e609441a1"), &owned_owner, Some(&dao)), bytes_from_hex("0x7f68de0000000000"), ); link_cell_to_header(&mut context, &owned_input_1, &prior_withdraw_header); @@ -106,20 +87,12 @@ fn weak_two_claim_live_restake_can_reassign_later_phase2_claimants() { ); context.create_cell_with_out_point( owner_input_4.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(u64_from_hex("0x248202200"), &user_lock, Some(&owned_owner)), bytes_from_hex("0xfdffffff"), ); context.create_cell_with_out_point( owner_input_3.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(u64_from_hex("0x248202200"), &user_lock, Some(&owned_owner)), bytes_from_hex("0xfdffffff"), ); @@ -129,11 +102,7 @@ fn weak_two_claim_live_restake_can_reassign_later_phase2_claimants() { ); context.create_cell_with_out_point( order_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x10186de6e79f").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x10186de6e79f"), &limit_order, Some(&xudt)), bytes_from_hex( "0x7995e51aa23e00000000000000000000010000001594bf3a65929bf5ee706f3c34e5c92d993adc405e58c3934661aeaa4e19264704000000000000000000000000000000000000000000c16ff28623008cb96cb2f30b290021", ), @@ -142,9 +111,9 @@ fn weak_two_claim_live_restake_can_reassign_later_phase2_claimants() { context.insert_header(prior_deposit_header.clone()); let first_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(change_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(change_input)) + .input(input(udt_input)) .input( CellInput::new_builder() .previous_output(owned_input_1) @@ -157,34 +126,15 @@ fn weak_two_claim_live_restake_can_reassign_later_phase2_claimants() { .since(u64_from_hex("0x200708059e0029d2").pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_input_4).build()) - .input(CellInput::new_builder().previous_output(owner_input_3).build()) - .input(CellInput::new_builder().previous_output(order_input).build()) + .input(input(owner_input_4)) + .input(input(owner_input_3)) + .input(input(order_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0xa6386d7249d").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x251c9490476f").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(attacker_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x160032266c").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0xa6386d7249d"), &owned_owner, Some(&dao)), + cell(u64_from_hex("0x251c9490476f"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x248202200"), &attacker_lock, Some(&owned_owner)), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), + cell(u64_from_hex("0x160032266c"), &user_lock, None), ]) .outputs_data( vec![ @@ -259,31 +209,20 @@ fn weak_two_claim_live_restake_can_reassign_later_phase2_claimants() { link_cell_to_header(&mut context, &fresh_owned, &fresh_withdraw_header); let second_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(later_change_input).build()) - .input(CellInput::new_builder().previous_output(later_udt_input).build()) + .input(input(later_change_input)) + .input(input(later_udt_input)) .input( CellInput::new_builder() .previous_output(fresh_owned) .since(u64_from_hex("0x200708068b0029d2").pack()) .build(), ) - .input(CellInput::new_builder().previous_output(fresh_owner).build()) - .input(CellInput::new_builder().previous_output(later_order_input).build()) + .input(input(fresh_owner)) + .input(input(later_order_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0x2f83c2399248").pack()) - .lock(limit_order) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(attacker_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x332dfe9760").pack()) - .lock(attacker_lock) - .build(), + cell(u64_from_hex("0x2f83c2399248"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x3663a5200"), &attacker_lock, Some(&xudt)), + cell(u64_from_hex("0x332dfe9760"), &attacker_lock, None), ]) .outputs_data( vec![ @@ -345,11 +284,7 @@ fn sighash_two_claim_live_restake_binds_fresh_owner_output() { ); context.create_cell_with_out_point( deposit_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa6386d7249d").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa6386d7249d"), &ickb_logic, Some(&dao)), bytes_from_hex("0x0000000000000000"), ); link_cell_to_header(&mut context, &deposit_input, &fresh_deposit_header); @@ -360,10 +295,7 @@ fn sighash_two_claim_live_restake_binds_fresh_owner_output() { ); context.create_cell_with_out_point( change_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x13bbb34e26").pack()) - .lock(strong_lock.clone()) - .build(), + cell(u64_from_hex("0x13bbb34e26"), &strong_lock, None), Bytes::new(), ); @@ -373,11 +305,7 @@ fn sighash_two_claim_live_restake_binds_fresh_owner_output() { ); context.create_cell_with_out_point( udt_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(strong_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x3663a5200"), &strong_lock, Some(&xudt)), bytes_from_hex("0xa0bfc96d660200000000000000000000"), ); @@ -391,20 +319,12 @@ fn sighash_two_claim_live_restake_binds_fresh_owner_output() { ); context.create_cell_with_out_point( owned_input_1.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e609441a1").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa5e609441a1"), &owned_owner, Some(&dao)), bytes_from_hex("0x7f68de0000000000"), ); context.create_cell_with_out_point( owned_input_0.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e609441a1").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa5e609441a1"), &owned_owner, Some(&dao)), bytes_from_hex("0x7f68de0000000000"), ); link_cell_to_header(&mut context, &owned_input_1, &prior_withdraw_header); @@ -420,20 +340,12 @@ fn sighash_two_claim_live_restake_binds_fresh_owner_output() { ); context.create_cell_with_out_point( owner_input_4.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(weak_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(u64_from_hex("0x248202200"), &weak_lock, Some(&owned_owner)), bytes_from_hex("0xfdffffff"), ); context.create_cell_with_out_point( owner_input_3.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(weak_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(u64_from_hex("0x248202200"), &weak_lock, Some(&owned_owner)), bytes_from_hex("0xfdffffff"), ); @@ -443,11 +355,7 @@ fn sighash_two_claim_live_restake_binds_fresh_owner_output() { ); context.create_cell_with_out_point( order_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x10186de6e79f").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x10186de6e79f"), &limit_order, Some(&xudt)), bytes_from_hex( "0x7995e51aa23e00000000000000000000010000001594bf3a65929bf5ee706f3c34e5c92d993adc405e58c3934661aeaa4e19264704000000000000000000000000000000000000000000c16ff28623008cb96cb2f30b290021", ), @@ -456,9 +364,9 @@ fn sighash_two_claim_live_restake_binds_fresh_owner_output() { context.insert_header(prior_deposit_header.clone()); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(change_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(change_input)) + .input(input(udt_input)) .input( CellInput::new_builder() .previous_output(owned_input_1) @@ -471,34 +379,15 @@ fn sighash_two_claim_live_restake_binds_fresh_owner_output() { .since(u64_from_hex("0x200708059e0029d2").pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_input_4).build()) - .input(CellInput::new_builder().previous_output(owner_input_3).build()) - .input(CellInput::new_builder().previous_output(order_input).build()) + .input(input(owner_input_4)) + .input(input(owner_input_3)) + .input(input(order_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0xa6386d7249d").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x251c9490476f").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(weak_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(strong_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x160032266c").pack()) - .lock(strong_lock.clone()) - .build(), + cell(u64_from_hex("0xa6386d7249d"), &owned_owner, Some(&dao)), + cell(u64_from_hex("0x251c9490476f"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x248202200"), &weak_lock, Some(&owned_owner)), + cell(u64_from_hex("0x3663a5200"), &strong_lock, Some(&xudt)), + cell(u64_from_hex("0x160032266c"), &strong_lock, None), ]) .outputs_data( vec![ @@ -538,15 +427,10 @@ fn sighash_two_claim_live_restake_binds_fresh_owner_output() { .set_outputs(vec![ tx.outputs().get(0).expect("fresh owned output"), tx.outputs().get(1).expect("order output"), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(attacker_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(u64_from_hex("0x248202200"), &attacker_lock, Some(&owned_owner)), tx.outputs().get(3).expect("udt output"), tx.outputs().get(4).expect("change output"), ]) .build(); - let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); + fail(&context, &tampered_tx, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } diff --git a/scripts/tests/src/tests/replay/lineage_21ccbca0.rs b/scripts/tests/src/tests/replay/lineage_21ccbca0.rs index 100aafa..d5d85bb 100644 --- a/scripts/tests/src/tests/replay/lineage_21ccbca0.rs +++ b/scripts/tests/src/tests/replay/lineage_21ccbca0.rs @@ -20,40 +20,18 @@ fn testnet_tx_21ccbca0_phase1_and_limit_order_creation_shape() { .map(u64_from_hex) .sum::(); let funding_input = context.create_cell( - CellOutput::new_builder() - .capacity(funding_capacity.pack()) - .lock(user_lock.clone()) - .build(), + cell(funding_capacity, &user_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_input).build()) + .input(input(funding_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e5d45d23e").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x283baec00").pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(user_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x1bd2464cc2").pack()) - .lock(limit_order) - .type_(Some(xudt).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x51dde56f7306").pack()) - .lock(user_lock) - .build(), + cell(u64_from_hex("0xa5e5d45d23e"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0x283baec00"), &user_lock, Some(&ickb_logic)), + cell(u64_from_hex("0x23c346000"), &user_lock, Some(&limit_order)), + cell(u64_from_hex("0x1bd2464cc2"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x51dde56f7306"), &user_lock, None), ]) .outputs_data( vec![ @@ -90,25 +68,10 @@ fn testnet_tx_a4a8dc3d_mixed_phase2_and_limit_order_shape() { let dao = dao_script(&mut context); let xudt = xudt_script(&mut context, &ickb_logic); - let order_input = CellOutput::new_builder() - .capacity(u64_from_hex("0x1bd2464cc2").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(); - let master_input = CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(user_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(); - let change_input = CellOutput::new_builder() - .capacity(u64_from_hex("0x51dde56f7306").pack()) - .lock(user_lock.clone()) - .build(); - let receipt_input = CellOutput::new_builder() - .capacity(u64_from_hex("0x283baec00").pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(); + let order_input = cell(u64_from_hex("0x1bd2464cc2"), &limit_order, Some(&xudt)); + let master_input = cell(u64_from_hex("0x23c346000"), &user_lock, Some(&limit_order)); + let change_input = cell(u64_from_hex("0x51dde56f7306"), &user_lock, None); + let receipt_input = cell(u64_from_hex("0x283baec00"), &user_lock, Some(&ickb_logic)); let order_out_point = out_point_from_hex("0x21ccbca021f03816c7057bdfca5a60da9e2280ca1c2530affa608df9c63c7954", 3); let master_out_point = out_point_from_hex("0x21ccbca021f03816c7057bdfca5a60da9e2280ca1c2530affa608df9c63c7954", 2); let change_out_point = out_point_from_hex("0x21ccbca021f03816c7057bdfca5a60da9e2280ca1c2530affa608df9c63c7954", 4); @@ -135,40 +98,17 @@ fn testnet_tx_a4a8dc3d_mixed_phase2_and_limit_order_shape() { link_cell_to_header(&mut context, &receipt_out_point, &receipt_header); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order_out_point).build()) - .input(CellInput::new_builder().previous_output(master_out_point).build()) - .input(CellInput::new_builder().previous_output(change_out_point).build()) - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) + .input(input(order_out_point)) + .input(input(master_out_point)) + .input(input(change_out_point)) + .input(input(receipt_out_point)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e5e84cc7e").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x283baec00").pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(user_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x1bd1075282").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x372261400").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x477c16037c64").pack()) - .lock(user_lock) - .build(), + cell(u64_from_hex("0xa5e5e84cc7e"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0x283baec00"), &user_lock, Some(&ickb_logic)), + cell(u64_from_hex("0x23c346000"), &user_lock, Some(&limit_order)), + cell(u64_from_hex("0x1bd1075282"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x372261400"), &user_lock, Some(&xudt)), + cell(u64_from_hex("0x477c16037c64"), &user_lock, None), ]) .outputs_data( vec![ @@ -215,58 +155,34 @@ fn testnet_tx_088a1019_batched_withdrawal_and_limit_order_shape() { let udt_out_point = out_point_from_hex("0xffef829fc3a19246d19f4458f66c25228c3acde7e9a2613d37f66dd2ef956fd9", 2); context.create_cell_with_out_point( deposit1_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e5e84cc7e").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa5e5e84cc7e"), &ickb_logic, Some(&dao)), bytes_from_hex("0x0000000000000000"), ); context.create_cell_with_out_point( deposit2_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e5ec78350").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa5e5ec78350"), &ickb_logic, Some(&dao)), bytes_from_hex("0x0000000000000000"), ); context.create_cell_with_out_point( deposit3_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e609441a1").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa5e609441a1"), &ickb_logic, Some(&dao)), bytes_from_hex("0x0000000000000000"), ); context.create_cell_with_out_point( udt_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), bytes_from_hex("0x56b5feac722100000000000000000000"), ); context.create_cell_with_out_point( order_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x34a6e480ce1c").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x34a6e480ce1c"), &limit_order, Some(&xudt)), bytes_from_hex( "0x0000000000000000000000000000000001000000ffef829fc3a19246d19f4458f66c25228c3acde7e9a2613d37f66dd2ef956fd900000000000000000000000000000000000000000000c16ff2862300058a01b24b76280021", ), ); context.create_cell_with_out_point( master_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x230489e00").pack()) - .lock(user_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), + cell(u64_from_hex("0x230489e00"), &user_lock, Some(&limit_order)), Bytes::new(), ); @@ -290,57 +206,22 @@ fn testnet_tx_088a1019_batched_withdrawal_and_limit_order_shape() { link_cell_to_header(&mut context, &deposit3_out_point, &deposit3_header); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit1_out_point).build()) - .input(CellInput::new_builder().previous_output(deposit2_out_point).build()) - .input(CellInput::new_builder().previous_output(deposit3_out_point).build()) - .input(CellInput::new_builder().previous_output(udt_out_point).build()) - .input(CellInput::new_builder().previous_output(order_out_point).build()) - .input(CellInput::new_builder().previous_output(master_out_point).build()) + .input(input(deposit1_out_point)) + .input(input(deposit2_out_point)) + .input(input(deposit3_out_point)) + .input(input(udt_out_point)) + .input(input(order_out_point)) + .input(input(master_out_point)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e5e84cc7e").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e5ec78350").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa5e609441a1").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x230489e00").pack()) - .lock(user_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x4a221e700").pack()) - .lock(limit_order) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x349ed038bab7").pack()) - .lock(user_lock) - .build(), + cell(u64_from_hex("0xa5e5e84cc7e"), &owned_owner, Some(&dao)), + cell(u64_from_hex("0xa5e5ec78350"), &owned_owner, Some(&dao)), + cell(u64_from_hex("0xa5e609441a1"), &owned_owner, Some(&dao)), + cell(u64_from_hex("0x248202200"), &user_lock, Some(&owned_owner)), + cell(u64_from_hex("0x248202200"), &user_lock, Some(&owned_owner)), + cell(u64_from_hex("0x248202200"), &user_lock, Some(&owned_owner)), + cell(u64_from_hex("0x230489e00"), &user_lock, Some(&limit_order)), + cell(u64_from_hex("0x4a221e700"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x349ed038bab7"), &user_lock, None), ]) .outputs_data( vec![ diff --git a/scripts/tests/src/tests/replay/lineage_30f8ed8a.rs b/scripts/tests/src/tests/replay/lineage_30f8ed8a.rs index 2c01788..1b921c9 100644 --- a/scripts/tests/src/tests/replay/lineage_30f8ed8a.rs +++ b/scripts/tests/src/tests/replay/lineage_30f8ed8a.rs @@ -10,67 +10,30 @@ fn mainnet_tx_30f8ed8a_phase1_and_limit_order_shape() { let xudt = xudt_script(&mut context, &ickb_logic); let ckb_input_1 = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex("0x4dac4518c238").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0x4dac4518c238"), &user_lock, None), Bytes::new(), ); let ckb_input_2 = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex("0x2e90edcf91").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0x2e90edcf91"), &user_lock, None), Bytes::new(), ); let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex("0x372261400").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x372261400"), &user_lock, Some(&xudt)), bytes_from_hex("0x3dc895f28c4300000000000000000000"), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(ckb_input_1).build()) - .input(CellInput::new_builder().previous_output(ckb_input_2).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(ckb_input_1)) + .input(input(ckb_input_2)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0xadd2b97d89e").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xadd2b97d89e").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x283baec00").pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(user_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x641d5c5e1c4").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x372261400").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x31d9e921a329").pack()) - .lock(user_lock) - .build(), + cell(u64_from_hex("0xadd2b97d89e"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0xadd2b97d89e"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0x283baec00"), &user_lock, Some(&ickb_logic)), + cell(u64_from_hex("0x23c346000"), &user_lock, Some(&limit_order)), + cell(u64_from_hex("0x641d5c5e1c4"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x372261400"), &user_lock, Some(&xudt)), + cell(u64_from_hex("0x31d9e921a329"), &user_lock, None), ]) .outputs_data( vec![ @@ -113,11 +76,7 @@ fn mainnet_tx_f9404724_mixed_phase2_and_limit_order_shape() { ); context.create_cell_with_out_point( order_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x4a221e700").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x4a221e700"), &limit_order, Some(&xudt)), bytes_from_hex( "0x12f549ca3705000000000000000000000100000030f8ed8a415adae46b94626ddd986179ab9c3d88513c7c96edc2a62e46f250b9030000000000c16ff28623005b03be74cf7a2a000000000000000000000000000000000021", ), @@ -128,26 +87,15 @@ fn mainnet_tx_f9404724_mixed_phase2_and_limit_order_shape() { ); context.create_cell_with_out_point( master_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(user_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), + cell(u64_from_hex("0x23c346000"), &user_lock, Some(&limit_order)), Bytes::new(), ); let change_input = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex("0x31d9e921a329").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0x31d9e921a329"), &user_lock, None), Bytes::new(), ); let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex("0x372261400").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x372261400"), &user_lock, Some(&xudt)), bytes_from_hex("0x3dc895f28c4300000000000000000000"), ); let receipt_out_point = out_point_from_hex( @@ -156,11 +104,7 @@ fn mainnet_tx_f9404724_mixed_phase2_and_limit_order_shape() { ); context.create_cell_with_out_point( receipt_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x283baec00").pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), + cell(u64_from_hex("0x283baec00"), &user_lock, Some(&ickb_logic)), bytes_from_hex("0x020000009ec6d542db0a0000"), ); let receipt_header = rpc_header( @@ -171,21 +115,14 @@ fn mainnet_tx_f9404724_mixed_phase2_and_limit_order_shape() { link_cell_to_header(&mut context, &receipt_out_point, &receipt_header); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order_out_point).build()) - .input(CellInput::new_builder().previous_output(master_input).build()) - .input(CellInput::new_builder().previous_output(change_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(receipt_out_point).build()) + .input(input(order_out_point)) + .input(input(master_input)) + .input(input(change_input)) + .input(input(udt_input)) + .input(input(receipt_out_point)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0x372261400").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x31e34b32ce59").pack()) - .lock(user_lock) - .build(), + cell(u64_from_hex("0x372261400"), &user_lock, Some(&xudt)), + cell(u64_from_hex("0x31e34b32ce59"), &user_lock, None), ]) .outputs_data( vec![ diff --git a/scripts/tests/src/tests/replay/lineage_86d442e2.rs b/scripts/tests/src/tests/replay/lineage_86d442e2.rs index 87d5870..312c9e6 100644 --- a/scripts/tests/src/tests/replay/lineage_86d442e2.rs +++ b/scripts/tests/src/tests/replay/lineage_86d442e2.rs @@ -10,18 +10,11 @@ fn mainnet_tx_8aaf4923_deposit_and_limit_order_match_shape() { let xudt = xudt_script(&mut context, &ickb_logic); let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), bytes_from_hex("0x3ea3bf63450100000000000000000000"), ); let ckb_input = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex("0x1c64f893723e").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0x1c64f893723e"), &user_lock, None), Bytes::new(), ); let order_input = out_point_from_hex( @@ -30,45 +23,22 @@ fn mainnet_tx_8aaf4923_deposit_and_limit_order_match_shape() { ); context.create_cell_with_out_point( order_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa6d17e8d17c").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0xa6d17e8d17c"), &limit_order, Some(&xudt)), bytes_from_hex( "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000c16ff2862300f76adf1f9a792a000000000000000000000000000000000021", ), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(ckb_input).build()) - .input(CellInput::new_builder().previous_output(order_input).build()) + .input(input(udt_input)) + .input(input(ckb_input)) + .input(input(order_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0x903384caedb").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xadcdc889e23").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x277cf2a00").pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x12ef83d72ac6").pack()) - .lock(user_lock) - .build(), + cell(u64_from_hex("0x903384caedb"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0xadcdc889e23"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0x277cf2a00"), &user_lock, Some(&ickb_logic)), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), + cell(u64_from_hex("0x12ef83d72ac6"), &user_lock, None), ]) .outputs_data( vec![ @@ -109,10 +79,7 @@ fn mainnet_tx_42fe6a4c_phase2_and_limit_order_match_shape() { ); context.create_cell_with_out_point( change_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x12ef83d72ac6").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0x12ef83d72ac6"), &user_lock, None), Bytes::new(), ); let udt_input = out_point_from_hex( @@ -121,11 +88,7 @@ fn mainnet_tx_42fe6a4c_phase2_and_limit_order_match_shape() { ); context.create_cell_with_out_point( udt_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), bytes_from_hex("0x3edbb5b5160000000000000000000000"), ); let receipt_input = out_point_from_hex( @@ -134,11 +97,7 @@ fn mainnet_tx_42fe6a4c_phase2_and_limit_order_match_shape() { ); context.create_cell_with_out_point( receipt_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x277cf2a00").pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), + cell(u64_from_hex("0x277cf2a00"), &user_lock, Some(&ickb_logic)), bytes_from_hex("0x01000000238cc6f3da0a0000"), ); let receipt_header = rpc_header( @@ -153,36 +112,21 @@ fn mainnet_tx_42fe6a4c_phase2_and_limit_order_match_shape() { ); context.create_cell_with_out_point( order_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x903384caedb").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x903384caedb"), &limit_order, Some(&xudt)), bytes_from_hex( "0x00c809ae2e01000000000000000000000100000086d442e2c056386b114b021194c8dbae30c97be8c943513d5bb0aa67a1ab38e8020000000000c16ff2862300f76adf1f9a792a000000000000000000000000000000000021", ), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(change_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(receipt_input).build()) - .input(CellInput::new_builder().previous_output(order_input).build()) + .input(input(change_input)) + .input(input(udt_input)) + .input(input(receipt_input)) + .input(input(order_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0x4a221e700").pack()) - .lock(limit_order) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x1bf091d09adb").pack()) - .lock(user_lock) - .build(), + cell(u64_from_hex("0x4a221e700"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), + cell(u64_from_hex("0x1bf091d09adb"), &user_lock, None), ]) .outputs_data( vec![ @@ -223,10 +167,7 @@ fn mainnet_tx_86d442e2_claim_and_restake_shape() { ); context.create_cell_with_out_point( funding_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x2540be391").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0x2540be391"), &user_lock, None), Bytes::new(), ); @@ -247,16 +188,8 @@ fn mainnet_tx_86d442e2_claim_and_restake_shape() { 2, ); - let owned1 = CellOutput::new_builder() - .capacity(u64_from_hex("0xa923feb5eef").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(); - let owned0 = CellOutput::new_builder() - .capacity(u64_from_hex("0xabe8fa4120f").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(); + let owned1 = cell(u64_from_hex("0xa923feb5eef"), &owned_owner, Some(&dao)); + let owned0 = cell(u64_from_hex("0xabe8fa4120f"), &owned_owner, Some(&dao)); context.create_cell_with_out_point( owned1_out_point.clone(), owned1.clone(), @@ -269,20 +202,12 @@ fn mainnet_tx_86d442e2_claim_and_restake_shape() { ); context.create_cell_with_out_point( owner3_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x2540be400").pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(u64_from_hex("0x2540be400"), &user_lock, Some(&owned_owner)), bytes_from_hex("0xfeffffff"), ); context.create_cell_with_out_point( owner2_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x2540be400").pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(u64_from_hex("0x2540be400"), &user_lock, Some(&owned_owner)), bytes_from_hex("0xfeffffff"), ); @@ -307,7 +232,7 @@ fn mainnet_tx_86d442e2_claim_and_restake_shape() { context.insert_header(deposit_header_2.clone()); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_out_point).build()) + .input(input(funding_out_point)) .input( CellInput::new_builder() .previous_output(owned1_out_point) @@ -320,33 +245,14 @@ fn mainnet_tx_86d442e2_claim_and_restake_shape() { .since(u64_from_hex("0x20065100af0035ea").pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner3_out_point).build()) - .input(CellInput::new_builder().previous_output(owner2_out_point).build()) + .input(input(owner3_out_point)) + .input(input(owner2_out_point)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0xadcdc7bbf67").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x283baec00").pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(user_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa6d17e8d17c").pack()) - .lock(limit_order) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x63eb5b3469").pack()) - .lock(user_lock) - .build(), + cell(u64_from_hex("0xadcdc7bbf67"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0x283baec00"), &user_lock, Some(&ickb_logic)), + cell(u64_from_hex("0x23c346000"), &user_lock, Some(&limit_order)), + cell(u64_from_hex("0xa6d17e8d17c"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x63eb5b3469"), &user_lock, None), ]) .outputs_data( vec![ @@ -394,10 +300,7 @@ fn mainnet_live_claims_cannot_rotate_into_new_owned_owner_pairs() { ); context.create_cell_with_out_point( funding_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x2540be391").pack()) - .lock(user1_lock.clone()) - .build(), + cell(u64_from_hex("0x2540be391"), &user1_lock, None), Bytes::new(), ); @@ -420,38 +323,22 @@ fn mainnet_live_claims_cannot_rotate_into_new_owned_owner_pairs() { context.create_cell_with_out_point( owned1_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa923feb5eef").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa923feb5eef"), &owned_owner, Some(&dao)), bytes_from_hex("0xf1b6e60000000000"), ); context.create_cell_with_out_point( owned0_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xabe8fa4120f").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xabe8fa4120f"), &owned_owner, Some(&dao)), bytes_from_hex("0xd5280b0100000000"), ); context.create_cell_with_out_point( owner3_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x2540be400").pack()) - .lock(user1_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(u64_from_hex("0x2540be400"), &user1_lock, Some(&owned_owner)), bytes_from_hex("0xfeffffff"), ); context.create_cell_with_out_point( owner2_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x2540be400").pack()) - .lock(user2_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(u64_from_hex("0x2540be400"), &user2_lock, Some(&owned_owner)), bytes_from_hex("0xfeffffff"), ); @@ -479,7 +366,7 @@ fn mainnet_live_claims_cannot_rotate_into_new_owned_owner_pairs() { let witness2 = header_dep_index_witness(2); let rotate_tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(funding_out_point).build()) + .input(input(funding_out_point)) .input( CellInput::new_builder() .previous_output(owned1_out_point) @@ -492,33 +379,14 @@ fn mainnet_live_claims_cannot_rotate_into_new_owned_owner_pairs() { .since(u64_from_hex("0x20065100af0035ea").pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner3_out_point).build()) - .input(CellInput::new_builder().previous_output(owner2_out_point).build()) + .input(input(owner3_out_point)) + .input(input(owner2_out_point)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0x2540be391").pack()) - .lock(user1_lock.clone()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa923feb5eef").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xabe8fa4120f").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x2540be400").pack()) - .lock(user1_lock) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x2540be400").pack()) - .lock(user2_lock) - .type_(Some(owned_owner).pack()) - .build(), + cell(u64_from_hex("0x2540be391"), &user1_lock, None), + cell(u64_from_hex("0xa923feb5eef"), &owned_owner, Some(&dao)), + cell(u64_from_hex("0xabe8fa4120f"), &owned_owner, Some(&dao)), + cell(u64_from_hex("0x2540be400"), &user1_lock, Some(&owned_owner)), + cell(u64_from_hex("0x2540be400"), &user2_lock, Some(&owned_owner)), ]) .outputs_data( vec![ @@ -539,6 +407,5 @@ fn mainnet_live_claims_cannot_rotate_into_new_owned_owner_pairs() { .build(); let rotate_tx = context.complete_tx(rotate_tx); - let err = context.verify(&rotate_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_DAO_NEWLY_CREATED_CELL); + fail(&context, &rotate_tx, ERROR_DAO_NEWLY_CREATED_CELL); } diff --git a/scripts/tests/src/tests/replay/lineage_b866945c.rs b/scripts/tests/src/tests/replay/lineage_b866945c.rs index 233637b..554bb2b 100644 --- a/scripts/tests/src/tests/replay/lineage_b866945c.rs +++ b/scripts/tests/src/tests/replay/lineage_b866945c.rs @@ -14,10 +14,7 @@ fn mainnet_tx_b866945c_claim_and_limit_order_match_shape() { ); context.create_cell_with_out_point( change_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xce749cf8e0d").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0xce749cf8e0d"), &user_lock, None), Bytes::new(), ); @@ -27,11 +24,7 @@ fn mainnet_tx_b866945c_claim_and_limit_order_match_shape() { ); context.create_cell_with_out_point( udt_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), bytes_from_hex("0x04f06631280500000000000000000000"), ); @@ -41,11 +34,7 @@ fn mainnet_tx_b866945c_claim_and_limit_order_match_shape() { ); context.create_cell_with_out_point( owned_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa923feb5eef").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa923feb5eef"), &owned_owner, Some(&dao)), bytes_from_hex("0xf1b6e60000000000"), ); @@ -55,11 +44,7 @@ fn mainnet_tx_b866945c_claim_and_limit_order_match_shape() { ); context.create_cell_with_out_point( owner_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner).pack()) - .build(), + cell(u64_from_hex("0x248202200"), &user_lock, Some(&owned_owner)), bytes_from_hex("0xffffffff"), ); @@ -69,11 +54,7 @@ fn mainnet_tx_b866945c_claim_and_limit_order_match_shape() { ); context.create_cell_with_out_point( order_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x13ab81f230").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x13ab81f230"), &limit_order, Some(&xudt)), bytes_from_hex( "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000c16ff286230016037f080e722a000000000000000000000000000000000021", ), @@ -93,31 +74,20 @@ fn mainnet_tx_b866945c_claim_and_limit_order_match_shape() { context.insert_header(deposit_header.clone()); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(change_input_out_point).build()) - .input(CellInput::new_builder().previous_output(udt_input_out_point).build()) + .input(input(change_input_out_point)) + .input(input(udt_input_out_point)) .input( CellInput::new_builder() .previous_output(owned_input_out_point) .since(u64_from_hex("0x20041d018a0035ee").pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_input_out_point).build()) - .input(CellInput::new_builder().previous_output(order_input_out_point).build()) + .input(input(owner_input_out_point)) + .input(input(order_input_out_point)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0x4a221e700").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x17cf7b1158b3").pack()) - .lock(user_lock) - .build(), + cell(u64_from_hex("0x4a221e700"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), + cell(u64_from_hex("0x17cf7b1158b3"), &user_lock, None), ]) .outputs_data( vec![ @@ -164,10 +134,7 @@ fn mainnet_tx_b866945c_is_input_poisoned_by_non_empty_args_owned_owner_sibling() ); context.create_cell_with_out_point( change_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xce749cf8e0d").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0xce749cf8e0d"), &user_lock, None), Bytes::new(), ); @@ -177,11 +144,7 @@ fn mainnet_tx_b866945c_is_input_poisoned_by_non_empty_args_owned_owner_sibling() ); context.create_cell_with_out_point( udt_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), bytes_from_hex("0x04f06631280500000000000000000000"), ); @@ -191,11 +154,7 @@ fn mainnet_tx_b866945c_is_input_poisoned_by_non_empty_args_owned_owner_sibling() ); context.create_cell_with_out_point( owned_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xa923feb5eef").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xa923feb5eef"), &owned_owner, Some(&dao)), bytes_from_hex("0xf1b6e60000000000"), ); @@ -205,21 +164,13 @@ fn mainnet_tx_b866945c_is_input_poisoned_by_non_empty_args_owned_owner_sibling() ); context.create_cell_with_out_point( owner_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(u64_from_hex("0x248202200"), &user_lock, Some(&owned_owner)), bytes_from_hex("0xffffffff"), ); // The one-byte args make the mainnet owner cell one CKB larger. let poisoned_owner_input = context.create_cell( - CellOutput::new_builder() - .capacity((u64_from_hex("0x248202200") + CKB).pack()) - .lock(user_lock.clone()) - .type_(Some(poisoned_owned_owner).pack()) - .build(), + cell(u64_from_hex("0x248202200") + CKB, &user_lock, Some(&poisoned_owned_owner)), bytes_from_hex("0xffffffff"), ); @@ -229,11 +180,7 @@ fn mainnet_tx_b866945c_is_input_poisoned_by_non_empty_args_owned_owner_sibling() ); context.create_cell_with_out_point( order_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x13ab81f230").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x13ab81f230"), &limit_order, Some(&xudt)), bytes_from_hex( "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000c16ff286230016037f080e722a000000000000000000000000000000000021", ), @@ -253,32 +200,21 @@ fn mainnet_tx_b866945c_is_input_poisoned_by_non_empty_args_owned_owner_sibling() context.insert_header(deposit_header.clone()); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(change_input_out_point).build()) - .input(CellInput::new_builder().previous_output(udt_input_out_point).build()) + .input(input(change_input_out_point)) + .input(input(udt_input_out_point)) .input( CellInput::new_builder() .previous_output(owned_input_out_point) .since(u64_from_hex("0x20041d018a0035ee").pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_input_out_point).build()) - .input(CellInput::new_builder().previous_output(poisoned_owner_input).build()) - .input(CellInput::new_builder().previous_output(order_input_out_point).build()) + .input(input(owner_input_out_point)) + .input(input(poisoned_owner_input)) + .input(input(order_input_out_point)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0x4a221e700").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x17cf7b1158b3").pack()) - .lock(user_lock) - .build(), + cell(u64_from_hex("0x4a221e700"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), + cell(u64_from_hex("0x17cf7b1158b3"), &user_lock, None), ]) .outputs_data( vec![ @@ -303,8 +239,7 @@ fn mainnet_tx_b866945c_is_input_poisoned_by_non_empty_args_owned_owner_sibling() .build(); let tx = context.complete_tx(tx); - let err = context.verify(&tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_NOT_EMPTY_ARGS); + fail(&context, &tx, ERROR_NOT_EMPTY_ARGS); } // Replays the live mixed deposit plus phase2 follow-up from the same lineage without mutating protocol ownership, so the repeated deposit batch and reminted order should verify unchanged. @@ -322,11 +257,7 @@ fn mainnet_tx_dc92e6a3_mixed_deposit_phase2_and_limit_order_shape() { ); context.create_cell_with_out_point( order_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x4a221e700").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x4a221e700"), &limit_order, Some(&xudt)), bytes_from_hex( "0xfaadf2950c0000000000000000000000010000004472915f75bb991221c620ddde53bdcd9f5529600ec2a001ca4b709989d3af8f020000000000c16ff286230016037f080e722a000000000000000000000000000000000021", ), @@ -338,11 +269,7 @@ fn mainnet_tx_dc92e6a3_mixed_deposit_phase2_and_limit_order_shape() { ); context.create_cell_with_out_point( master_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(user_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), + cell(u64_from_hex("0x23c346000"), &user_lock, Some(&limit_order)), Bytes::new(), ); @@ -352,11 +279,7 @@ fn mainnet_tx_dc92e6a3_mixed_deposit_phase2_and_limit_order_shape() { ); context.create_cell_with_out_point( receipt_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x283baec00").pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), + cell(u64_from_hex("0x283baec00"), &user_lock, Some(&ickb_logic)), bytes_from_hex("0x01000000d0a29a05d90a0000"), ); @@ -366,11 +289,7 @@ fn mainnet_tx_dc92e6a3_mixed_deposit_phase2_and_limit_order_shape() { ); context.create_cell_with_out_point( udt_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x372261400").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x372261400"), &user_lock, Some(&xudt)), bytes_from_hex("0xab216b4e180900000000000000000000"), ); @@ -380,10 +299,7 @@ fn mainnet_tx_dc92e6a3_mixed_deposit_phase2_and_limit_order_shape() { ); context.create_cell_with_out_point( change_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3be3a5b1d278").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0x3be3a5b1d278"), &user_lock, None), Bytes::new(), ); @@ -395,61 +311,22 @@ fn mainnet_tx_dc92e6a3_mixed_deposit_phase2_and_limit_order_shape() { link_cell_to_header(&mut context, &receipt_input_out_point, &receipt_header); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order_input_out_point).build()) - .input(CellInput::new_builder().previous_output(master_input_out_point).build()) - .input(CellInput::new_builder().previous_output(change_input_out_point).build()) - .input(CellInput::new_builder().previous_output(udt_input_out_point).build()) - .input(CellInput::new_builder().previous_output(receipt_input_out_point).build()) + .input(input(order_input_out_point)) + .input(input(master_input_out_point)) + .input(input(change_input_out_point)) + .input(input(udt_input_out_point)) + .input(input(receipt_input_out_point)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0xadaee77b40f").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xadaee77b40f").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xadaee77b40f").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xadaee77b40f").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xadaee77b40f").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x283baec00").pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(user_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x49a1fa47875").pack()) - .lock(limit_order) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x372261400").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x1077fd7ab48").pack()) - .lock(user_lock) - .build(), + cell(u64_from_hex("0xadaee77b40f"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0xadaee77b40f"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0xadaee77b40f"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0xadaee77b40f"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0xadaee77b40f"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0x283baec00"), &user_lock, Some(&ickb_logic)), + cell(u64_from_hex("0x23c346000"), &user_lock, Some(&limit_order)), + cell(u64_from_hex("0x49a1fa47875"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x372261400"), &user_lock, Some(&xudt)), + cell(u64_from_hex("0x1077fd7ab48"), &user_lock, None), ]) .outputs_data( vec![ diff --git a/scripts/tests/src/tests/replay/lineage_b923f354.rs b/scripts/tests/src/tests/replay/lineage_b923f354.rs index 5f22a6e..5018b3c 100644 --- a/scripts/tests/src/tests/replay/lineage_b923f354.rs +++ b/scripts/tests/src/tests/replay/lineage_b923f354.rs @@ -13,10 +13,7 @@ fn mainnet_tx_b923f354_live_limit_order_match_shape() { ); context.create_cell_with_out_point( change_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x17ca7ad60207").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0x17ca7ad60207"), &user_lock, None), Bytes::new(), ); let udt_input = out_point_from_hex( @@ -25,11 +22,7 @@ fn mainnet_tx_b923f354_live_limit_order_match_shape() { ); context.create_cell_with_out_point( udt_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), bytes_from_hex("0x4e83e3e7250500000000000000000000"), ); let order_input = out_point_from_hex( @@ -38,35 +31,20 @@ fn mainnet_tx_b923f354_live_limit_order_match_shape() { ); context.create_cell_with_out_point( order_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x4a221e700").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x4a221e700"), &limit_order, Some(&xudt)), bytes_from_hex( "0xff2222085e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff000000000000000000000000000000000000c16ff28623000a1338d4d7672a0021", ), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(change_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) - .input(CellInput::new_builder().previous_output(order_input).build()) + .input(input(change_input)) + .input(input(udt_input)) + .input(input(order_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0x74deeef1ad").pack()) - .lock(limit_order) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x175a3e080786").pack()) - .lock(user_lock) - .build(), + cell(u64_from_hex("0x74deeef1ad"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), + cell(u64_from_hex("0x175a3e080786"), &user_lock, None), ]) .outputs_data( vec![ @@ -105,11 +83,7 @@ fn mainnet_tx_3d26da3b_limit_order_melt_shape() { ); context.create_cell_with_out_point( order_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x74deeef1ad").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x74deeef1ad"), &limit_order, Some(&xudt)), bytes_from_hex( "0x000000000000000000000000000000000100000004f46b529e33c003d9c75a8cd1cc384bcf4a5e21b1712423ebc664fbcde7df4000000000000000000000000000000000000000000000c16ff28623000a1338d4d7672a0021", ), @@ -121,11 +95,7 @@ fn mainnet_tx_3d26da3b_limit_order_melt_shape() { ); context.create_cell_with_out_point( master_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x230489e00").pack()) - .lock(user_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), + cell(u64_from_hex("0x230489e00"), &user_lock, Some(&limit_order)), Bytes::new(), ); @@ -135,10 +105,7 @@ fn mainnet_tx_3d26da3b_limit_order_melt_shape() { ); context.create_cell_with_out_point( change_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x1e4155fb4f").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0x1e4155fb4f"), &user_lock, None), Bytes::new(), ); @@ -148,10 +115,7 @@ fn mainnet_tx_3d26da3b_limit_order_melt_shape() { ); context.create_cell_with_out_point( funding_out_point_1.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x5256bc3fd7").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0x5256bc3fd7"), &user_lock, None), Bytes::new(), ); @@ -161,25 +125,17 @@ fn mainnet_tx_3d26da3b_limit_order_melt_shape() { ); context.create_cell_with_out_point( funding_out_point_2.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xbbe5fd5f6").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0xbbe5fd5f6"), &user_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(order_out_point).build()) - .input(CellInput::new_builder().previous_output(master_out_point).build()) - .input(CellInput::new_builder().previous_output(funding_out_point_1).build()) - .input(CellInput::new_builder().previous_output(change_out_point).build()) - .input(CellInput::new_builder().previous_output(funding_out_point_2).build()) - .output( - CellOutput::new_builder() - .capacity(u64_from_hex("0xf365a998f9").pack()) - .lock(user_lock) - .build(), - ) + .input(input(order_out_point)) + .input(input(master_out_point)) + .input(input(funding_out_point_1)) + .input(input(change_out_point)) + .input(input(funding_out_point_2)) + .output(cell(u64_from_hex("0xf365a998f9"), &user_lock, None)) .output_data(Bytes::new().pack()) .witness(Bytes::new().pack()) .witness( diff --git a/scripts/tests/src/tests/replay/tx_5f6d0d5b.rs b/scripts/tests/src/tests/replay/tx_5f6d0d5b.rs index e8aa441..6cc54c8 100644 --- a/scripts/tests/src/tests/replay/tx_5f6d0d5b.rs +++ b/scripts/tests/src/tests/replay/tx_5f6d0d5b.rs @@ -14,10 +14,7 @@ fn mainnet_tx_5f6d0d5b_claim_deposit_and_limit_order_shape() { ); context.create_cell_with_out_point( change_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xce777783bd6").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0xce777783bd6"), &user_lock, None), Bytes::new(), ); @@ -27,11 +24,7 @@ fn mainnet_tx_5f6d0d5b_claim_deposit_and_limit_order_shape() { ); context.create_cell_with_out_point( udt_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), bytes_from_hex("0x85026831280500000000000000000000"), ); @@ -39,11 +32,7 @@ fn mainnet_tx_5f6d0d5b_claim_deposit_and_limit_order_shape() { "0x1a8e8a211427f1ac9d07f380638acc915ceebb62d9dfdae2e29529f19bf045cd", 0, ); - let owned_input = CellOutput::new_builder() - .capacity(u64_from_hex("0xab4adefc030").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(); + let owned_input = cell(u64_from_hex("0xab4adefc030"), &owned_owner, Some(&dao)); context.create_cell_with_out_point( owned_input_out_point.clone(), owned_input.clone(), @@ -56,11 +45,7 @@ fn mainnet_tx_5f6d0d5b_claim_deposit_and_limit_order_shape() { ); context.create_cell_with_out_point( owner_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x248202200").pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), + cell(u64_from_hex("0x248202200"), &user_lock, Some(&owned_owner)), bytes_from_hex("0xffffffff"), ); @@ -70,11 +55,7 @@ fn mainnet_tx_5f6d0d5b_claim_deposit_and_limit_order_shape() { ); context.create_cell_with_out_point( order_input_out_point.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x710eb256272").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x710eb256272"), &limit_order, Some(&xudt)), bytes_from_hex( "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000c16ff286230054043b34e65b2a000000000000000000000000000000000021", ), @@ -94,41 +75,22 @@ fn mainnet_tx_5f6d0d5b_claim_deposit_and_limit_order_shape() { context.insert_header(deposit_header.clone()); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(change_input_out_point).build()) - .input(CellInput::new_builder().previous_output(udt_input_out_point).build()) + .input(input(change_input_out_point)) + .input(input(udt_input_out_point)) .input( CellInput::new_builder() .previous_output(owned_input_out_point) .since(u64_from_hex("0x2005f30163003532").pack()) .build(), ) - .input(CellInput::new_builder().previous_output(owner_input_out_point).build()) - .input(CellInput::new_builder().previous_output(order_input_out_point).build()) + .input(input(owner_input_out_point)) + .input(input(order_input_out_point)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0xfe564f2176").pack()) - .lock(limit_order) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0xad543dd639c").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x277cf2a00").pack()) - .lock(user_lock.clone()) - .type_(Some(ickb_logic.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x3663a5200").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x12f6704164db").pack()) - .lock(user_lock) - .build(), + cell(u64_from_hex("0xfe564f2176"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0xad543dd639c"), &ickb_logic, Some(&dao)), + cell(u64_from_hex("0x277cf2a00"), &user_lock, Some(&ickb_logic)), + cell(u64_from_hex("0x3663a5200"), &user_lock, Some(&xudt)), + cell(u64_from_hex("0x12f6704164db"), &user_lock, None), ]) .outputs_data( vec![ diff --git a/scripts/tests/src/tests/replay/tx_9df44c51.rs b/scripts/tests/src/tests/replay/tx_9df44c51.rs index e5d2f21..b884247 100644 --- a/scripts/tests/src/tests/replay/tx_9df44c51.rs +++ b/scripts/tests/src/tests/replay/tx_9df44c51.rs @@ -9,11 +9,7 @@ fn mainnet_tx_9df44c51_withdrawal_and_owned_owner_shape() { ickb_logic_limit_order_owned_owner_dao_and_xudt_scripts(&mut context); let deposit_input = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex("0xad543d30c47").pack()) - .lock(ickb_logic.clone()) - .type_(Some(dao.clone()).pack()) - .build(), + cell(u64_from_hex("0xad543d30c47"), &ickb_logic, Some(&dao)), bytes_from_hex("0x0000000000000000"), ); let deposit_header = rpc_header( @@ -24,11 +20,7 @@ fn mainnet_tx_9df44c51_withdrawal_and_owned_owner_shape() { link_cell_to_header(&mut context, &deposit_input, &deposit_header); let order_input = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex("0xa67ecbf8ac4").pack()) - .lock(limit_order.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0xa67ecbf8ac4"), &limit_order, Some(&xudt)), bytes_from_hex( "0x0000000000000000000000000000000001000000814c44c45e33a496dc30f18131e01bf4b72282be58abd7f0fefff9a95b5c0dbc00000000000000000000000000000000000000000000c16ff2862300a714425582642a0021", ), @@ -39,60 +31,30 @@ fn mainnet_tx_9df44c51_withdrawal_and_owned_owner_shape() { ); context.create_cell_with_out_point( master_input.clone(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(user_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), + cell(u64_from_hex("0x23c346000"), &user_lock, Some(&limit_order)), Bytes::new(), ); let udt_input = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex("0x372261400").pack()) - .lock(user_lock.clone()) - .type_(Some(xudt.clone()).pack()) - .build(), + cell(u64_from_hex("0x372261400"), &user_lock, Some(&xudt)), bytes_from_hex("0xfc3c6a4e180900000000000000000000"), ); let change_input = context.create_cell( - CellOutput::new_builder() - .capacity(u64_from_hex("0x180631dd8a2f").pack()) - .lock(user_lock.clone()) - .build(), + cell(u64_from_hex("0x180631dd8a2f"), &user_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(deposit_input).build()) - .input(CellInput::new_builder().previous_output(order_input).build()) - .input(CellInput::new_builder().previous_output(master_input).build()) - .input(CellInput::new_builder().previous_output(change_input).build()) - .input(CellInput::new_builder().previous_output(udt_input).build()) + .input(input(deposit_input)) + .input(input(order_input)) + .input(input(master_input)) + .input(input(change_input)) + .input(input(udt_input)) .outputs(vec![ - CellOutput::new_builder() - .capacity(u64_from_hex("0xad543d30c47").pack()) - .lock(owned_owner.clone()) - .type_(Some(dao.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x2540be400").pack()) - .lock(user_lock.clone()) - .type_(Some(owned_owner.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x23c346000").pack()) - .lock(user_lock.clone()) - .type_(Some(limit_order.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x4a221e700").pack()) - .lock(limit_order) - .type_(Some(xudt.clone()).pack()) - .build(), - CellOutput::new_builder() - .capacity(u64_from_hex("0x226a9a954e53").pack()) - .lock(user_lock) - .build(), + cell(u64_from_hex("0xad543d30c47"), &owned_owner, Some(&dao)), + cell(u64_from_hex("0x2540be400"), &user_lock, Some(&owned_owner)), + cell(u64_from_hex("0x23c346000"), &user_lock, Some(&limit_order)), + cell(u64_from_hex("0x4a221e700"), &limit_order, Some(&xudt)), + cell(u64_from_hex("0x226a9a954e53"), &user_lock, None), ]) .outputs_data( vec![ diff --git a/scripts/tests/src/tests/replay_helpers.rs b/scripts/tests/src/tests/replay_helpers.rs index b7084cd..af01017 100644 --- a/scripts/tests/src/tests/replay_helpers.rs +++ b/scripts/tests/src/tests/replay_helpers.rs @@ -22,11 +22,7 @@ pub(super) fn build_many_header_phase2_batch( for i in 0..input_count { let deposit_number = 1_554u64 + i as u64; let deposit_header = gen_header(deposit_number, GENESIS_AR as u64, 35, 1000, 1000); - let withdrawing_output = CellOutput::new_builder() - .capacity(input_capacity.pack()) - .lock(owner_lock.clone()) - .type_(Some(dao.clone()).pack()) - .build(); + let withdrawing_output = cell(input_capacity, &owner_lock, Some(&dao)); let withdrawing_input = context.create_cell( withdrawing_output.clone(), withdrawal_request_data(deposit_number), @@ -40,18 +36,16 @@ pub(super) fn build_many_header_phase2_batch( .build(), ); outputs.push( - CellOutput::new_builder() - .capacity( - dao_maximum_withdraw_capacity( - &withdrawing_output, - withdrawal_request_data(deposit_number).len(), - GENESIS_AR as u64, - SYNTHETIC_WITHDRAW_AR, - ) - .pack(), - ) - .lock(owner_lock.clone()) - .build(), + cell( + dao_maximum_withdraw_capacity( + &withdrawing_output, + withdrawal_request_data(deposit_number).len(), + GENESIS_AR as u64, + SYNTHETIC_WITHDRAW_AR, + ), + &owner_lock, + None, + ), ); outputs_data.push(Bytes::new()); header_deps.push(deposit_header.hash()); @@ -131,9 +125,7 @@ mod tests { assert_eq!(u64_from_hex("0x2a"), 42); assert_eq!(bytes_from_hex("0x1234"), Bytes::from(vec![0x12, 0x34])); assert_eq!( - byte32_from_hex( - "0x1111111111111111111111111111111111111111111111111111111111111111", - ) + byte32_from_hex("0x1111111111111111111111111111111111111111111111111111111111111111") .as_slice(), [0x11; 32], ); diff --git a/scripts/tests/src/tests/signing.rs b/scripts/tests/src/tests/signing.rs index dfc5476..0d6e18d 100644 --- a/scripts/tests/src/tests/signing.rs +++ b/scripts/tests/src/tests/signing.rs @@ -104,14 +104,12 @@ fn sign_tx_by_input_group_covers_group_witnesses_and_trailing_extras_only() { let build_tx = |target_lock: &[u8], grouped_lock: &[u8], other_group_lock: &[u8], trailing_extra: &[u8]| { let inputs = (0..4) .map(|index| { - CellInput::new_builder() - .previous_output( - OutPoint::new_builder() - .tx_hash(Byte32::from_slice(&[index as u8; 32]).expect("tx hash")) - .index((index as u32).pack()) - .build(), - ) - .build() + input( + OutPoint::new_builder() + .tx_hash(Byte32::from_slice(&[index as u8; 32]).expect("tx hash")) + .index((index as u32).pack()) + .build(), + ) }) .collect::>(); let witnesses = vec![ @@ -182,14 +180,12 @@ fn sign_tx_binds_the_full_witness_set() { let build_tx = |trailing_lock: &[u8]| { let inputs = (0..2) .map(|index| { - CellInput::new_builder() - .previous_output( - OutPoint::new_builder() - .tx_hash(Byte32::from_slice(&[index as u8; 32]).expect("tx hash")) - .index((index as u32).pack()) - .build(), - ) - .build() + input( + OutPoint::new_builder() + .tx_hash(Byte32::from_slice(&[index as u8; 32]).expect("tx hash")) + .index((index as u32).pack()) + .build(), + ) }) .collect::>(); let witnesses = vec![ @@ -234,30 +230,19 @@ fn sign_tx_by_input_group_covers_trailing_extra_witnesses_for_later_groups() { let (privkey, protected_lock, secp_data_dep) = secp_lock(&mut context); let passthrough_input = context.create_cell( - CellOutput::new_builder() - .capacity((1_000 * CKB).pack()) - .lock(passthrough_lock.clone()) - .build(), + cell(1_000 * CKB, &passthrough_lock, None), Bytes::new(), ); let protected_input = context.create_cell( - CellOutput::new_builder() - .capacity((1_000 * CKB).pack()) - .lock(protected_lock) - .build(), + cell(1_000 * CKB, &protected_lock, None), Bytes::new(), ); let trailing_extra = Bytes::from_static(b"trailing-extra"); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(passthrough_input).build()) - .input(CellInput::new_builder().previous_output(protected_input).build()) - .output( - CellOutput::new_builder() - .capacity((1_800 * CKB).pack()) - .lock(passthrough_lock) - .build(), - ) + .input(input(passthrough_input)) + .input(input(protected_input)) + .output(cell(1_800 * CKB, &passthrough_lock, None)) .output_data(Bytes::new().pack()) .witness(Bytes::new().pack()) .witness(empty_witness().pack()) @@ -278,8 +263,7 @@ fn sign_tx_by_input_group_covers_trailing_extra_witnesses_for_later_groups() { Bytes::from_static(b"trailing-extra-updated").pack(), ]) .build(); - let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); + fail(&context, &tampered_tx, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } #[test] @@ -289,37 +273,23 @@ fn sign_tx_by_input_indices_signs_a_noncontiguous_secp_group() { let (privkey, protected_lock, secp_data_dep) = secp_lock(&mut context); let protected_input_0 = context.create_cell( - CellOutput::new_builder() - .capacity((1_000 * CKB).pack()) - .lock(protected_lock.clone()) - .build(), + cell(1_000 * CKB, &protected_lock, None), Bytes::new(), ); let passthrough_input = context.create_cell( - CellOutput::new_builder() - .capacity((1_000 * CKB).pack()) - .lock(passthrough_lock.clone()) - .build(), + cell(1_000 * CKB, &passthrough_lock, None), Bytes::new(), ); let protected_input_2 = context.create_cell( - CellOutput::new_builder() - .capacity((1_000 * CKB).pack()) - .lock(protected_lock) - .build(), + cell(1_000 * CKB, &protected_lock, None), Bytes::new(), ); let tx = TransactionBuilder::default() - .input(CellInput::new_builder().previous_output(protected_input_0).build()) - .input(CellInput::new_builder().previous_output(passthrough_input).build()) - .input(CellInput::new_builder().previous_output(protected_input_2).build()) - .output( - CellOutput::new_builder() - .capacity((2_800 * CKB).pack()) - .lock(passthrough_lock) - .build(), - ) + .input(input(protected_input_0)) + .input(input(passthrough_input)) + .input(input(protected_input_2)) + .output(cell(2_800 * CKB, &passthrough_lock, None)) .output_data(Bytes::new().pack()) .witness(empty_witness().pack()) .witness(Bytes::new().pack()) @@ -340,6 +310,5 @@ fn sign_tx_by_input_indices_signs_a_noncontiguous_secp_group() { Bytes::from_static(b"tampered-group-witness").pack(), ]) .build(); - let err = context.verify(&tampered_tx, MAX_CYCLES).unwrap_err(); - assert_script_error(err, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); + fail(&context, &tampered_tx, ERROR_SECP256K1_BLAKE160_SIGHASH_ALL); } From 5a731c433d102fc16e3902029abd0778cd2c4683 Mon Sep 17 00:00:00 2001 From: phroi <90913182+phroi@users.noreply.github.com> Date: Sat, 26 Sep 2026 16:23:36 +0200 Subject: [PATCH 11/13] test: accepted transactions also pass the node's capacity checks The previous check stopped short of two node rules, so some passing fixtures described transactions a node would reject, and one rule was applied more strictly than the node does. - CapacityVerifier: outputs may not hold more than inputs, unless a DAO input is present and the DAO script checks compensation instead. Thirty tests minted, melted, matched or replayed vectors while creating CKB; each such transaction now gains a funding input, appended so existing input indices keep their meaning. The vector replay funds exactly the CKB each order gains. A signed phase 2 test now signs only its secp input group. - DaoScriptSizeVerifier exempts deposits committed before block 10,000,000, which the check ignored. It now honors that exemption. The two foreign-wrapping tests keep their original user locks, valid again for their legacy deposits. The self-test rejects a post-10,000,000 withdrawal and a control accepts a legacy one. Every assertion is unchanged. Two crosswire tests already accept either of two error codes, which vary between runs with the random out points. The report's scope statement and the tests README describe both rules, and the test count becomes 231. --- ICKB-Audit-Report.md | 6 +-- scripts/tests/README.md | 2 +- scripts/tests/src/tests.rs | 49 ++++++++++++++----- scripts/tests/src/tests/fixtures.rs | 11 +++-- .../tests/ickb_logic/economic_precision.rs | 2 + .../ickb_logic/multi_quantity_receipts.rs | 1 + .../ickb_logic/phase2_recipient_binding.rs | 5 +- .../phase2_sibling_classification.rs | 3 ++ .../ickb_logic/phase2_xudt_output_data.rs | 1 + .../src/tests/ickb_logic/receipt_encoding.rs | 1 + .../tests/src/tests/ickb_logic/soft_cap.rs | 3 ++ .../tests/limit_order/crosswire_live_match.rs | 3 ++ .../limit_order/crosswire_mint_creation.rs | 3 ++ .../tests/limit_order/fake_match_lineage.rs | 1 + scripts/tests/src/tests/limit_order/remint.rs | 1 + .../tests/owned_owner/foreign_dao_wrapping.rs | 7 ++- .../owned_owner/mixed_asset_crosswiring.rs | 7 ++- scripts/tests/src/tests/protocol_vectors.rs | 6 ++- 18 files changed, 83 insertions(+), 29 deletions(-) diff --git a/ICKB-Audit-Report.md b/ICKB-Audit-Report.md index 3918d70..a4d7cd9 100644 --- a/ICKB-Audit-Report.md +++ b/ICKB-Audit-Report.md @@ -156,7 +156,7 @@ The `nervosnetwork/ckb` pin is release `v0.210.0`. The review prioritized executable behavior over static plausibility and classified issues by their concrete impact. - Reviewed the deployed release binaries and the transaction semantics they actually enforce, not just the latest source-level intent. -- Reproduced deployed-script behavior locally with `ckb-testtool`. Its `Context::verify_tx` checks output/data cardinality and executes scripts, but does not run the full node non-contextual or contextual transaction verifiers. The suite therefore holds every input and output to its occupied capacity before verifying, and every accepted DAO withdrawal to the node's lock-size rule, so no fixture builds a cell or withdrawal the node would reject; other consensus-level conclusions are separately source-backed. +- Reproduced deployed-script behavior locally with `ckb-testtool`. Its `Context::verify_tx` checks output/data cardinality and executes scripts, but does not run the full node non-contextual or contextual transaction verifiers. The suite therefore holds every input and output to its occupied capacity before verifying, and every transaction the scripts accept to the node's capacity balance and DAO lock-size rules, so no fixture builds a cell or transaction those node checks would reject; other consensus-level conclusions are separately source-backed. - Reused and extended the existing test suite, including replayed transaction shapes from observed protocol flows. - Computed NervosDAO accounting with the exact DAO withdrawal math before classifying any claim-path discrepancy as a finding. - Separated findings that affect the current deployment from weak-lock assumptions, operator mistakes, or broader integration-only scenarios. @@ -171,7 +171,7 @@ A [module wiring overview](scripts/tests/src/tests.rs) plus the [test layout not - **Scenario suite roots:** [ickb_logic](scripts/tests/src/tests/ickb_logic.rs), [owned_owner](scripts/tests/src/tests/owned_owner.rs), [limit_order](scripts/tests/src/tests/limit_order.rs), and [replay](scripts/tests/src/tests/replay.rs), each wiring topic-focused files under the matching subdirectory. - **Helper-focused unit coverage:** [helpers](scripts/tests/src/tests/helpers.rs), which checks the shared encoders and witness/data builders used by the larger suites. -A fresh `cargo test -p tests` run passed `230` tests with no failures. Those tests cover deployment-hash sanity checks, helper encodings, core flows, blocked-path regressions, and replayed transaction shapes across `iCKB Logic`, `Owned Owner`, and `Limit Order`. +A fresh `cargo test -p tests` run passed `231` tests with no failures. Those tests cover deployment-hash sanity checks, helper encodings, core flows, blocked-path regressions, and replayed transaction shapes across `iCKB Logic`, `Owned Owner`, and `Limit Order`. The type-role scan regression verifies a phase-2 conversion with 512 unrelated outputs within the suite's `10,000,000`-cycle ceiling. Lock-role transactions also execute NervosDAO, whose separately tested 64-output boundary caps their outputs. @@ -351,7 +351,7 @@ For inputs and outputs separately, the script enforces the same pairing rules: - **Live claim rotation remains blocked:** Attempts to roll a live claim into fresh `Owned Owner` pairs or to crosswire a fully DAO-constrained batch are rejected before a new live pairing survives. The [fresh-pair rotation block test](scripts/tests/src/tests/owned_owner/live_claim_rotation.rs), [new-pair rotation block test](scripts/tests/src/tests/owned_owner/live_claim_rotation.rs), and the [DAO index-rule crosswire block test](scripts/tests/src/tests/owned_owner/dao_crosswiring.rs) show that block. - **Signed lifecycle:** A [secp-protected sparse pair](scripts/tests/src/tests/owned_owner/positive_distance_claims.rs) completes phase 1 with a noncontiguous signed input group and then completes the signed owner spend in DAO phase 2. This establishes signature and pairing behavior under script verification; `ckb-testtool` does not establish `since` maturity. - **Crosswired later-claim ownership still depends on weak phase-1 authorization:** When phase-1 owner outputs use weak or otherwise non-output-binding locks, later DAO claims can be reassigned across mixed foreign-plus-iCKB batches (with foreign deposits limited as below) or fully iCKB batches. The [mixed foreign-plus-iCKB weak-lock crosswire test](scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs), [two-way weak-lock crosswire claim test](scripts/tests/src/tests/owned_owner/dao_crosswiring.rs), and [three-way weak-lock crosswire claim test](scripts/tests/src/tests/owned_owner/dao_crosswiring.rs) show that boundary case. Under the current strong-lock deployment assumption, this is not a present finding. -- **Foreign DAO withdrawal wrapping is allowed:** The [foreign DAO wrapping test](scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs) shows that a DAO withdrawal request can be wrapped and later claimed, because the script checks only DAO type plus withdrawal-shaped data on the owned cell. For deposits committed at or after block 10,000,000, the node's `DaoScriptSizeVerifier` keeps a request's lock the same serialized size as its deposit's, so among those this applies only to deposits whose lock matches Owned Owner's size (empty args), not to deposits under ordinary user locks; older deposits can be wrapped regardless. +- **Foreign DAO withdrawal wrapping is allowed:** The [foreign DAO wrapping test](scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs) shows that a DAO withdrawal request can be wrapped and later claimed, because the script checks only DAO type plus withdrawal-shaped data on the owned cell. For deposits committed at or after block 10,000,000, the node's `DaoScriptSizeVerifier` keeps a request's lock the same serialized size as its deposit's, so among those this applies only to deposits whose lock matches Owned Owner's size (empty args), not to deposits under ordinary user locks; older deposits can be wrapped regardless, as the test shows with one under an ordinary user lock. - **Creator-side dead states are narrower than arbitrary malformed pairs:** When `Owned Owner` actually executes as a type script, it rejects orphan and count-mismatch shapes, as shown by the [orphan-owner rejection test](scripts/tests/src/tests/owned_owner/pair_formation.rs) and the [two-owner mismatch test](scripts/tests/src/tests/owned_owner/pair_formation.rs), with the reverse shape, two owned requests for one owner, covered by the [two-owned mismatch test](scripts/tests/src/tests/owned_owner/pair_formation.rs). But creation still accepts pairs whose owner lock never validated, as shown by the [unspendable foreign-owner-lock test](scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs) and the [limit-order owner-lock stranding test](scripts/tests/src/tests/owned_owner/foreign_owner_lock_boundaries.rs). It also allows lock-only `Owned Owner` look-alikes that later fail on spend, as shown by the [lock-only non-DAO look-alike test](scripts/tests/src/tests/owned_owner/script_misuse.rs) and the [lock-only DAO-deposit look-alike test](scripts/tests/src/tests/owned_owner/script_misuse.rs). --- diff --git a/scripts/tests/README.md b/scripts/tests/README.md index 3348cb4..d28a9f9 100644 --- a/scripts/tests/README.md +++ b/scripts/tests/README.md @@ -14,4 +14,4 @@ Some replay tests intentionally rebuild live transaction shapes instead of minim Current strong-lock coverage is direct for `secp256k1_blake160_sighash_all`, which the signed-flow tests use as the representative whole-transaction-binding lock. This repo does not include a `QRL` fixture or harness, so conclusions for other strong-lock deployments rely on the same binding property and deployment assumptions rather than a separate replay in this suite. -`ckb-testtool`'s `Context::verify_tx` executes `OutputsDataVerifier`, which checks that the output and output-data counts match, and then executes the transaction scripts through `TransactionScriptsVerifier`. It does not run the full node non-contextual or contextual transaction verifiers, so it does not establish checks such as occupied capacity, `since`, or cellbase maturity. Tests therefore verify through `VerifyRealistic::verify` in `src/tests.rs`, which first holds every input and output to its occupied capacity and then holds every accepted DAO withdrawal to the node's lock-size rule, so no fixture builds a cell or withdrawal the node would reject. Other consensus-level conclusions rely on CKB source evidence rather than `Context::verify_tx` alone. +`ckb-testtool`'s `Context::verify_tx` executes `OutputsDataVerifier`, which checks that the output and output-data counts match, and then executes the transaction scripts through `TransactionScriptsVerifier`. It does not run the full node non-contextual or contextual transaction verifiers, so it does not establish checks such as occupied capacity, `since`, or cellbase maturity. Tests therefore verify through `VerifyRealistic::verify` in `src/tests.rs`, which first holds every input and output to its occupied capacity, then holds every transaction the scripts accept to the node's capacity balance (outputs may not exceed inputs unless a DAO input is present) and to its DAO lock-size rule (for deposits committed since block 10,000,000). So no fixture builds a cell or transaction those node checks would reject. Other consensus-level conclusions rely on CKB source evidence rather than `Context::verify_tx` alone. diff --git a/scripts/tests/src/tests.rs b/scripts/tests/src/tests.rs index 8e25b01..112e10e 100644 --- a/scripts/tests/src/tests.rs +++ b/scripts/tests/src/tests.rs @@ -55,19 +55,33 @@ impl VerifyRealistic for Context { check("output", index, &cell, data.raw_data().len()); } let cycles = self.verify_tx(tx, max_cycles)?; - // A transaction the scripts accept must also pass the node's DaoScriptSizeVerifier: a - // deposit and the withdrawal request at its index use locks of the same serialized size. + // A transaction the scripts accept must also pass the node's transaction checks that + // ckb-testtool skips: CapacityVerifier and DaoScriptSizeVerifier. let dao_code_hash = build_genesis_type_id_script(OUTPUT_INDEX_DAO).calc_script_hash(); let is_dao = |cell: &CellOutput| { cell.type_().to_opt().map_or(false, |script| { script.code_hash() == dao_code_hash && script.hash_type() == ScriptHashType::Type.into() }) }; - for (index, (input, output)) in tx.inputs().into_iter().zip(tx.outputs()).enumerate() { - let Some((deposit, data)) = self.get_cell(&input.previous_output()) else { + let inputs: Vec<_> = tx.inputs().into_iter().map(|input| (input.previous_output(), self.get_cell(&input.previous_output()))).collect(); + // Outputs may not exceed inputs, except in a transaction with a DAO input, whose + // compensation the DAO script checks instead. + if !inputs.iter().any(|(_, cell)| cell.as_ref().map_or(false, |(cell, _)| is_dao(cell))) { + let inputs_sum: u64 = inputs.iter().filter_map(|(_, cell)| cell.as_ref()).map(|(cell, _)| Unpack::::unpack(&cell.capacity())).sum(); + let outputs_sum: u64 = tx.outputs().into_iter().map(|cell| Unpack::::unpack(&cell.capacity())).sum(); + assert!(outputs_sum <= inputs_sum, "outputs hold {outputs_sum} shannons, more than the inputs' {inputs_sum}"); + } + // A deposit committed since the node's starting block and the withdrawal request at its + // index use locks of the same serialized size; older deposits are exempt. + for (index, ((out_point, deposit), output)) in inputs.iter().zip(tx.outputs()).enumerate() { + let Some((deposit, data)) = deposit else { continue; }; - if is_dao(&deposit) && is_dao(&output) && data.iter().all(|byte| *byte == 0) { + let exempt = self + .transaction_infos + .get(out_point) + .map_or(false, |info| info.block_number < DAO_LOCK_SIZE_RULE_START_BLOCK); + if !exempt && is_dao(deposit) && is_dao(&output) && data.iter().all(|byte| *byte == 0) { assert_eq!( deposit.lock().total_size(), output.lock().total_size(), @@ -97,29 +111,42 @@ fn verify_rejects_a_cell_below_its_occupied_capacity() { let _ = context.verify(&tx, MAX_CYCLES); } -#[test] -#[should_panic(expected = "changes the lock size of the deposit it withdraws")] -fn verify_rejects_a_withdrawal_request_whose_lock_size_differs() { +/// A phase 1 withdrawal whose request lock is smaller than its deposit's, for a deposit +/// committed at `block_number`. +fn verify_withdrawal_with_smaller_request_lock(block_number: u64) { let mut context = Context::default(); let deposit_lock = named_always_success_lock(&mut context, b"depositor"); let request_lock = always_success_lock(&mut context); let dao = dao_script(&mut context); let capacity = 1_000 * CKB; let deposit = create_deposit(&mut context, capacity, &deposit_lock, &dao); - let header = gen_header(1554, GENESIS_AR, 35, 1000, 1000); + let header = gen_header(block_number, GENESIS_AR, 35, block_number - 10, 1000); link_cell_to_header(&mut context, &deposit, &header); let tx = TransactionBuilder::default() .input(input(deposit)) .output(cell(capacity, &request_lock, Some(&dao))) - .output_data(withdrawal_request_data(1554).pack()) + .output_data(withdrawal_request_data(block_number).pack()) .header_dep(header.hash()) .build(); let tx = context.complete_tx(tx); - let _ = context.verify(&tx, MAX_CYCLES); + context.verify(&tx, MAX_CYCLES).expect("the DAO script accepts the withdrawal"); +} + +#[test] +#[should_panic(expected = "changes the lock size of the deposit it withdraws")] +fn verify_rejects_a_withdrawal_request_whose_lock_size_differs() { + verify_withdrawal_with_smaller_request_lock(DAO_LOCK_SIZE_RULE_START_BLOCK); +} + +#[test] +fn verify_exempts_deposits_older_than_the_lock_size_rule() { + verify_withdrawal_with_smaller_request_lock(DAO_LOCK_SIZE_RULE_START_BLOCK - 1); } // Shared test constants and on-chain error codes. const MAX_CYCLES: u64 = 10_000_000; +// The node's starting_block_limiting_dao_withdrawing_lock (ckb spec/src/consensus.rs). +const DAO_LOCK_SIZE_RULE_START_BLOCK: u64 = 10_000_000; const CKB: u64 = 100_000_000; const GENESIS_AR: u64 = 10_000_000_000_000_000; const SIGNATURE_SIZE: usize = 65; diff --git a/scripts/tests/src/tests/fixtures.rs b/scripts/tests/src/tests/fixtures.rs index 8e8a1bc..820347d 100644 --- a/scripts/tests/src/tests/fixtures.rs +++ b/scripts/tests/src/tests/fixtures.rs @@ -179,11 +179,13 @@ pub(super) fn create_deposit(context: &mut Context, capacity: u64, lock: &Script /// A plain CKB cell that funds a transaction's outputs, as a wallet adds one on chain. pub(super) fn funding_cell(context: &mut Context) -> OutPoint { + funding_cell_of(context, 1_000 * CKB) +} + +/// A plain CKB cell holding exactly `capacity`. +pub(super) fn funding_cell_of(context: &mut Context, capacity: u64) -> OutPoint { let lock = named_always_success_lock(context, b"funding"); - context.create_cell( - cell(1_000 * CKB, &lock, None), - Bytes::new(), - ) + context.create_cell(cell(capacity, &lock, None), Bytes::new()) } /// The least capacity a cell with this lock, type and data length can hold on chain. @@ -361,6 +363,7 @@ pub(super) fn build_real_limit_order_and_master_with_capacity( ); let tx = TransactionBuilder::default() .input(input(funding_input)) + .input(input(funding_cell(context))) .output(cell(capacity, &limit_order, Some(&helper_type))) .output( cell(occupied_capacity(&owner_lock, &limit_order, 0), &owner_lock, Some(&limit_order)), diff --git a/scripts/tests/src/tests/ickb_logic/economic_precision.rs b/scripts/tests/src/tests/ickb_logic/economic_precision.rs index d58f370..6db4bec 100644 --- a/scripts/tests/src/tests/ickb_logic/economic_precision.rs +++ b/scripts/tests/src/tests/ickb_logic/economic_precision.rs @@ -30,6 +30,7 @@ fn reported_rounding_claim_is_blocked_by_actual_shannon_precision() { let mint_exact_1152_tx = TransactionBuilder::default() .input(input(receipt_1152)) + .input(input(funding_cell(&mut context))) .output(cell(occupied_capacity(&owner_lock, &xudt, 16), &owner_lock, Some(&xudt))) .output_data(udt_data(exact_ickb_1152).pack()) .header_dep(receipt_1152_header.hash()) @@ -78,6 +79,7 @@ fn non_genesis_ar_soft_cap_boundary_preserves_integer_operation_order() { link_cell_to_header(&mut context, &receipt, &receipt_header); let tx = TransactionBuilder::default() .input(input(receipt)) + .input(input(funding_cell(&mut context))) .output(cell(occupied_capacity(&owner_lock, &xudt, 16), &owner_lock, Some(&xudt))) .output_data(udt_data(minted).pack()) .header_dep(receipt_header.hash()) diff --git a/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs b/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs index 54308b0..36ae5f0 100644 --- a/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs +++ b/scripts/tests/src/tests/ickb_logic/multi_quantity_receipts.rs @@ -43,6 +43,7 @@ fn multi_quantity_receipt_can_be_converted_in_phase2() { let tx = TransactionBuilder::default() .input(input(receipt_out_point)) + .input(input(funding_cell(&mut context))) .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(u128::from(2 * deposit_amount)).pack()) .header_dep(receipt_header.clone()) diff --git a/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs b/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs index 96d7aa7..70c1e3a 100644 --- a/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs +++ b/scripts/tests/src/tests/ickb_logic/phase2_recipient_binding.rs @@ -20,6 +20,7 @@ fn weak_lock_receipt_can_reassign_phase2_mint_recipient() { let tx = TransactionBuilder::default() .input(input(receipt_out_point)) + .input(input(funding_cell(&mut context))) .output(cell(occupied_capacity(&attacker_lock, &xudt, 16), &attacker_lock, Some(&xudt))) .output_data(udt_data(u128::from(deposit_amount)).pack()) .header_dep(receipt_header.clone()) @@ -45,6 +46,7 @@ fn sighash_lock_binds_phase2_mint_outputs_to_the_signed_transaction() { let tx = TransactionBuilder::default() .input(input(receipt_out_point)) + .input(input(funding_cell(&mut context))) .output(cell(occupied_capacity(&owner_lock, &xudt, 16), &owner_lock, Some(&xudt))) .output_data(udt_data(u128::from(deposit_amount)).pack()) .witness(empty_witness().pack()) @@ -52,7 +54,8 @@ fn sighash_lock_binds_phase2_mint_outputs_to_the_signed_transaction() { .header_dep(receipt_header.clone()) .build(); - let tx = sign_tx(context.complete_tx(tx), &privkey); + // Only the receipt is under the secp lock; the funding input is its own lock group. + let tx = sign_tx_by_input_group(context.complete_tx(tx), &privkey, 0, 1); context .verify(&tx, MAX_CYCLES) .expect("signed owner transaction should verify"); diff --git a/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs b/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs index a60dc6a..b236456 100644 --- a/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs +++ b/scripts/tests/src/tests/ickb_logic/phase2_sibling_classification.rs @@ -111,6 +111,7 @@ fn foreign_xudt_output_lock_is_ignored() { let tx = TransactionBuilder::default() .input(input(receipt_out_point)) .input(input(extra_input)) + .input(input(funding_cell(&mut context))) .outputs(vec![ cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt)), cell(capacity_for_data(16), &foreign_xudt, None), @@ -145,6 +146,7 @@ fn foreign_xudt_type_output_is_ignored() { let tx = TransactionBuilder::default() .input(input(receipt_out_point)) .input(input(extra_input)) + .input(input(funding_cell(&mut context))) .outputs(vec![ cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt)), cell(occupied_capacity(&funding_lock, &foreign_xudt, 16), &funding_lock, Some(&foreign_xudt)), @@ -177,6 +179,7 @@ fn withdrawal_request_shaped_dao_output_lock_is_ignored() { let tx = TransactionBuilder::default() .input(input(receipt_out_point)) .input(input(extra_input)) + .input(input(funding_cell(&mut context))) .outputs(vec![ cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt)), cell(capacity_for_data(8), &dao, None), diff --git a/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs b/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs index 2d33399..1694161 100644 --- a/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs +++ b/scripts/tests/src/tests/ickb_logic/phase2_xudt_output_data.rs @@ -15,6 +15,7 @@ fn phase2_mint_accepts_xudt_data_with_trailing_bytes() { output_data.push(0xaa); let tx = TransactionBuilder::default() .input(input(receipt_out_point)) + .input(input(funding_cell(&mut context))) .output( cell(occupied_capacity(&funding_lock, &xudt, output_data.len()), &funding_lock, Some(&xudt)), ) diff --git a/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs b/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs index 4433310..c2899c1 100644 --- a/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs +++ b/scripts/tests/src/tests/ickb_logic/receipt_encoding.rs @@ -52,6 +52,7 @@ fn receipt_trailing_bytes_do_not_change_phase2_conversion() { let tx = TransactionBuilder::default() .input(input(receipt_out_point)) + .input(input(funding_cell(&mut context))) .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(u128::from(deposit_amount)).pack()) .header_dep(receipt_header.clone()) diff --git a/scripts/tests/src/tests/ickb_logic/soft_cap.rs b/scripts/tests/src/tests/ickb_logic/soft_cap.rs index 55c0d26..5db499b 100644 --- a/scripts/tests/src/tests/ickb_logic/soft_cap.rs +++ b/scripts/tests/src/tests/ickb_logic/soft_cap.rs @@ -22,6 +22,7 @@ fn phase2_mint_applies_soft_cap_discount_above_boundary() { let exact_tx = TransactionBuilder::default() .input(input(receipt_out_point)) + .input(input(funding_cell(&mut context))) .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(soft_capped_ickb(amount, GENESIS_AR)).pack()) .header_dep(receipt_header.clone()) @@ -47,6 +48,7 @@ fn phase2_mint_does_not_discount_at_soft_cap_boundary() { let tx = TransactionBuilder::default() .input(input(receipt_out_point)) + .input(input(funding_cell(&mut context))) .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(u128::from(amount)).pack()) .header_dep(receipt_header) @@ -86,6 +88,7 @@ fn multi_quantity_phase2_mint_applies_soft_cap_per_deposit() { let exact_tx = TransactionBuilder::default() .input(input(receipt_out_point)) + .input(input(funding_cell(&mut context))) .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(exact).pack()) .header_dep(receipt_header.clone()) diff --git a/scripts/tests/src/tests/limit_order/crosswire_live_match.rs b/scripts/tests/src/tests/limit_order/crosswire_live_match.rs index 44620bd..9300dbe 100644 --- a/scripts/tests/src/tests/limit_order/crosswire_live_match.rs +++ b/scripts/tests/src/tests/limit_order/crosswire_live_match.rs @@ -37,6 +37,7 @@ fn cloned_live_orders_can_permute_without_stranding_either_master() { let rebound_melt = TransactionBuilder::default() .input(input(crosswired_order1.clone())) .input(input(master2_input.clone())) + .input(input(funding_cell(&mut context))) .output(cell(1_600 * CKB, &owner2_lock, None)) .output_data(Bytes::new().pack()) .witness(Bytes::new().pack()) @@ -51,6 +52,7 @@ fn cloned_live_orders_can_permute_without_stranding_either_master() { let other_melt = TransactionBuilder::default() .input(input(crosswired_order2)) .input(input(master1_input)) + .input(input(funding_cell(&mut context))) .output(cell(1_600 * CKB, &owner1_lock, None)) .output_data(Bytes::new().pack()) .witness(Bytes::new().pack()) @@ -113,6 +115,7 @@ fn hybrid_fake_and_real_limit_order_match_keeps_real_master_on_real_metapoint() let real_lineage_melt = TransactionBuilder::default() .input(input(real_lineage_output)) .input(input(real_master_input.clone())) + .input(input(funding_cell(&mut context))) .output(cell(1_600 * CKB, &owner_lock, None)) .output_data(Bytes::new().pack()) .witness(Bytes::new().pack()) diff --git a/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs b/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs index cd8a5a6..b24654f 100644 --- a/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs +++ b/scripts/tests/src/tests/limit_order/crosswire_mint_creation.rs @@ -66,6 +66,7 @@ fn mint_crosswire_swaps_order_masters() { let melt_other_users_order = TransactionBuilder::default() .input(input(order2)) .input(input(master1.clone())) + .input(input(funding_cell(&mut context))) .output(cell(1_700 * CKB, &owner1_lock, None)) .output_data(Bytes::new().pack()) .build(); @@ -159,6 +160,7 @@ fn sparse_far_distance_limit_order_crosswire_still_rebinds_master_assignment() { let melt_crosswired = TransactionBuilder::default() .input(input(order1.clone())) .input(input(master2.clone())) + .input(input(funding_cell(&mut context))) .output(cell(1_700 * CKB, &owner2_lock, None)) .output_data(Bytes::new().pack()) .build(); @@ -198,6 +200,7 @@ fn mint_pairs_each_order_with_exactly_one_master() { let (cells, data): (Vec<_>, Vec<_>) = outputs.into_iter().unzip(); let tx = TransactionBuilder::default() .input(input(funding)) + .input(input(funding_cell(&mut context))) .outputs(cells) .outputs_data(data.pack()) .build(); diff --git a/scripts/tests/src/tests/limit_order/fake_match_lineage.rs b/scripts/tests/src/tests/limit_order/fake_match_lineage.rs index d5358b7..faa9d6f 100644 --- a/scripts/tests/src/tests/limit_order/fake_match_lineage.rs +++ b/scripts/tests/src/tests/limit_order/fake_match_lineage.rs @@ -92,6 +92,7 @@ fn foreign_token_fake_order_with_arbitrary_info_can_strand_real_order() { let tx = TransactionBuilder::default() .input(input(phantom_order_out_point)) .input(input(real_master_out_point.clone())) + .input(input(funding_cell(&mut context))) .output(cell(1_700 * CKB, &owner_lock, None)) .output_data(Bytes::new().pack()) .build(); diff --git a/scripts/tests/src/tests/limit_order/remint.rs b/scripts/tests/src/tests/limit_order/remint.rs index 866bfba..24f3d16 100644 --- a/scripts/tests/src/tests/limit_order/remint.rs +++ b/scripts/tests/src/tests/limit_order/remint.rs @@ -49,6 +49,7 @@ fn can_atomically_melt_and_remint_with_negative_distance_and_filler() { let melt_tx = TransactionBuilder::default() .input(input(new_order)) .input(input(new_master)) + .input(input(funding_cell(&mut context))) .output(cell(1_700 * CKB, &owner_lock, None)) .output_data(Bytes::new().pack()) .build(); diff --git a/scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs b/scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs index 2eb9e6b..746c01a 100644 --- a/scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs +++ b/scripts/tests/src/tests/owned_owner/foreign_dao_wrapping.rs @@ -13,10 +13,9 @@ fn foreign_dao_withdrawal_can_be_wrapped_and_claimed() { let deposit_capacity_value = 123_456_780_000u64; let deposit_header = gen_header(1554, GENESIS_AR as u64, 35, 1000, 1000); let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); - // For deposits since block 10,000,000 the node keeps a withdrawal request's lock the same size as - // its deposit's, so only a deposit whose lock has Owned Owner's size (empty args) can be wrapped. - let wrappable_lock = always_success_lock(&mut context); - let deposit_input = create_deposit(&mut context, deposit_capacity_value, &wrappable_lock, &dao); + // A deposit from before block 10,000,000 is exempt from the node's lock-size rule, so one under an + // ordinary user lock can be wrapped; since then, only a lock of Owned Owner's size can. + let deposit_input = create_deposit(&mut context, deposit_capacity_value, &user_lock, &dao); link_cell_to_header(&mut context, &deposit_input, &deposit_header); let funding_input = context.create_cell( cell(200 * CKB, &funding_lock, None), diff --git a/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs b/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs index c7a4b56..30dbb1c 100644 --- a/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs +++ b/scripts/tests/src/tests/owned_owner/mixed_asset_crosswiring.rs @@ -15,10 +15,9 @@ fn weak_lock_mixed_foreign_and_ickb_batch_can_crosswire_claims() { let withdraw_header = gen_header(2_000_610, SYNTHETIC_WITHDRAW_AR, 575, 2_000_000, 1100); let foreign_deposit_capacity = 123_456_780_000u64; - // For deposits since block 10,000,000 the node keeps a withdrawal request's lock the same size as - // its deposit's, so only a foreign deposit whose lock has Owned Owner's size (empty args) can be wrapped. - let wrappable_lock = always_success_lock(&mut context); - let foreign_deposit_input = create_deposit(&mut context, foreign_deposit_capacity, &wrappable_lock, &dao); + // The foreign deposit predates block 10,000,000, so the node's lock-size rule does not stop its + // ordinary user lock from being wrapped. + let foreign_deposit_input = create_deposit(&mut context, foreign_deposit_capacity, &foreign_owner_lock, &dao); link_cell_to_header(&mut context, &foreign_deposit_input, &foreign_deposit_header); let protocol_deposit_amount = 1_000 * CKB; diff --git a/scripts/tests/src/tests/protocol_vectors.rs b/scripts/tests/src/tests/protocol_vectors.rs index 905a213..f2205d4 100644 --- a/scripts/tests/src/tests/protocol_vectors.rs +++ b/scripts/tests/src/tests/protocol_vectors.rs @@ -27,6 +27,7 @@ fn every_deposit_vector_mints_exactly_its_expected_ickb() { for minted in [row.expected_ickb, row.expected_ickb + 1, row.expected_ickb - 1] { let tx = TransactionBuilder::default() .input(input(receipt.clone())) + .input(input(funding_cell(&mut context))) .output(cell(occupied_capacity(&funding_lock, &xudt, 16), &funding_lock, Some(&xudt))) .output_data(udt_data(minted).pack()) .header_dep(header.clone()) @@ -79,9 +80,12 @@ fn every_limit_order_vector_gets_the_verdict_of_the_copied_validate() { let (output_cell, output_data) = order(out_unoccupied, out_udt); let order_input = context.create_cell(input_cell, input_data); - // ckb-testtool runs scripts only, so the transaction needs no capacity balancing. + // The matcher funds any CKB the order gains; the extra 100 CKB covers the funding cell's own + // 61 CKB of occupied capacity and leaves the rest as fee. + let funding = funding_cell_of(&mut context, out_unoccupied.saturating_sub(in_unoccupied) + 100 * CKB); let tx = TransactionBuilder::default() .input(input(order_input)) + .input(input(funding)) .output(output_cell) .output_data(output_data.pack()) .build(); From b9e15f92f1f0188d88cc56a6c54adae0bcbcccf9 Mon Sep 17 00:00:00 2001 From: phroi <90913182+phroi@users.noreply.github.com> Date: Sat, 26 Sep 2026 16:07:25 +0200 Subject: [PATCH 12/13] docs: the withdrawal bonus follows a deposit's iCKB value, not its size Scenario 3B said withdrawing the smallest deposits first is optimal. Below the soft cap, the claim per iCKB burned is AR_n / AR_0 plus 82 CKB divided by the deposit's iCKB value, and that value depends on the deposit's accumulated rate as well as its unoccupied capacity. At a withdrawal AR of 1.3e16, a 1,050 CKB deposit made at 1.2e16 pays more per iCKB than a 1,000 CKB deposit made at 1.1e16. The report now says to withdraw the deposits with the smallest iCKB value first. --- ICKB-Audit-Report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ICKB-Audit-Report.md b/ICKB-Audit-Report.md index a4d7cd9..df307b5 100644 --- a/ICKB-Audit-Report.md +++ b/ICKB-Audit-Report.md @@ -483,7 +483,7 @@ Net profit = 0. Deposits with higher `AR_m` require less nominal `iCKB` because the formula values them lower in `iCKB`, not because the pool applies a discount. -The formula values only unoccupied capacity, while the phase 2 claim also returns the deposit's occupied capacity (82 CKB for a standard deposit cell). Per `iCKB` burned, a withdrawer therefore receives about `82 CKB / unoccupied` more from a small deposit: about 8.2% at 1,000 CKB, against 0.082% at 100k CKB, so among deposits within the bounds and below the soft cap, withdrawing the smallest first is optimal. Oversized deposits also pay more per `iCKB`, through the soft-cap discount (about 9.9% at 1M CKB). This is the whitepaper's intended [penalty on small deposits](https://github.com/ickb/whitepaper/blob/master/README.md#deposit-phase-1), paid by the depositor and collected by the withdrawer ([small-versus-standard withdrawal test](scripts/tests/src/tests/ickb_logic/economic_precision.rs)). +The formula values only unoccupied capacity, while the phase 2 claim also returns the deposit's occupied capacity (82 CKB for a standard deposit cell). Below the soft cap, a withdrawer therefore receives an extra `82 CKB` divided by the deposit's `iCKB` value for each `iCKB` burned, on top of the `AR_n / AR_0` every deposit returns: 0.082 CKB per `iCKB` from a deposit worth 1,000 `iCKB`, against 0.00082 CKB from one worth 100k. Withdrawing the deposits with the smallest `iCKB` value first is optimal; that value depends on the deposit's accumulated rate as well as its unoccupied capacity, so the smallest deposit in CKB is not always the smallest in `iCKB`. Oversized deposits also pay more per `iCKB`, through the soft-cap discount (about 9.9% at 1M CKB at the genesis rate). This is the whitepaper's intended [penalty on small deposits](https://github.com/ickb/whitepaper/blob/master/README.md#deposit-phase-1), paid by the depositor and collected by the withdrawer ([small-versus-standard withdrawal test](scripts/tests/src/tests/ickb_logic/economic_precision.rs)). **Result:** **No mispricing.** Each deposit's unoccupied capacity is priced by the same formula, up to integer-division rounding; the unaccounted occupied capacity is an intended incentive, not an error. From be28246a6ab1c790c01f5dbbe0b22a70368b2398 Mon Sep 17 00:00:00 2001 From: phroi <90913182+phroi@users.noreply.github.com> Date: Sat, 26 Sep 2026 15:15:55 +0200 Subject: [PATCH 13/13] ci: run the contract tests on pull requests and master pushes Nothing ran the suite outside a local checkout, so a change could break the tests or the vector generator unnoticed. The workflow runs the test crate, which executes the committed release binaries, checks their deployment hashes and replays the golden vectors. It also builds the vector-gen writer, which the suite does not compile. rustup takes the pinned Rust from scripts/rust-toolchain; the checkout action is pinned by commit, and the job has read-only permissions. --- .github/workflows/tests.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..85c4fb7 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,27 @@ +name: tests + +on: + push: + branches: [master] + pull_request: + +permissions: + contents: read + +jobs: + tests: + runs-on: ubuntu-24.04 + defaults: + run: + working-directory: scripts + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + # rustup reads scripts/rust-toolchain, so both steps use the pinned Rust. + - name: Test the release binaries + run: cargo test --locked -p tests + # The suite compiles only vector-gen/src/vectors.rs; build the JSON writer too. + - name: Build the vector generator + working-directory: scripts/vector-gen + run: cargo build --locked --release