Skip to content

Commit

Permalink
add taker tests
Browse files Browse the repository at this point in the history
  • Loading branch information
duanyytop committed Jan 31, 2024
1 parent e738bff commit e3c0416
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 76 deletions.
69 changes: 0 additions & 69 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions contracts/dex-lock/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ pub fn main() -> Result<(), Error> {
if args.owner_lock != output_lock {
return Err(Error::DexOwnerLockNotMatch);
}
let output_capacity = load_cell_capacity(dex_index, Source::Output)?;
if args.total_value > output_capacity.into() {

let dex_input_capacity = load_cell_capacity(dex_index, Source::Input)? as u128;
let output_capacity = load_cell_capacity(dex_index, Source::Output)? as u128;
if (args.total_value + dex_input_capacity) > output_capacity {
return Err(Error::DexTotalValueNotMatch);
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/dex-lock/src/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl DexArgs {
}
let owner_size = u32::from_le_bytes(parse_array::<4>(&data[0..4])?) as usize;
let required_size = owner_size + 17;
if data.len() < (required_size + 17) {
if data.len() < required_size {
return Err(Error::LockArgsInvalid);
}

Expand Down
5 changes: 1 addition & 4 deletions tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,5 @@ edition = "2021"

[dependencies]
ckb-testtool = "0.10.1"
rand_core = "0.6.3"
hex = "0.4"
blake2b-rs = "0.2"
rand = "0.8.5"
openssl = "0.10.38"
rand = "0.8.5"
27 changes: 27 additions & 0 deletions tests/src/helper.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#![allow(dead_code)]

use ckb_testtool::ckb_types::{packed::Script, prelude::Entity};

#[derive(Debug, Clone)]
pub struct DexArgs {
pub owner_lock: Script,
pub setup: u8,
pub total_value: u128,
pub receiver_lock: Option<Script>,
pub unit_type_hash: Option<[u8; 20]>,
}

impl DexArgs {
pub fn to_vec(&self) -> Vec<u8> {
let mut ret: Vec<u8> = self.owner_lock.as_bytes().to_vec();
ret.extend([self.setup]);
ret.extend(self.total_value.to_be_bytes());
if let Some(lock) = &self.receiver_lock {
ret.extend(lock.as_bytes());
}
if let Some(unit_hash) = self.unit_type_hash {
ret.extend(unit_hash);
}
ret
}
}
4 changes: 4 additions & 0 deletions tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ use std::fs;
use std::path::PathBuf;
use std::str::FromStr;

mod helper;
#[cfg(test)]
mod taker_tests;

const TEST_ENV_VAR: &str = "CAPSULE_TEST_ENV";

pub enum TestEnv {
Expand Down
217 changes: 217 additions & 0 deletions tests/src/taker_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
use self::helper::DexArgs;

use super::*;
use ckb_testtool::builtin::ALWAYS_SUCCESS;
use ckb_testtool::ckb_hash::blake2b_256;
use ckb_testtool::ckb_types::{
bytes::Bytes,
core::{TransactionBuilder, TransactionView},
packed::*,
prelude::*,
};
use ckb_testtool::context::Context;
use rand::{thread_rng, Rng};

const MAX_CYCLES: u64 = 70_000_000;

// error numbers
const LOCK_ARGS_INVALID: i8 = 5;
const DEX_OWNER_LOCK_NOT_MATCH: i8 = 6;
const DEX_TOTAL_VALUE_NOT_MATCH: i8 = 7;
const DEX_SETUP_INVALID: i8 = 8;

#[derive(PartialEq, Eq, Clone, Copy)]
enum DexError {
NoError,
LockArgsInvalid,
DexOwnerLockNotMatch,
DexTotalValueNotMatch,
DexSetupInvalid,
}

fn create_test_context(error: DexError) -> (Context, TransactionView) {
// deploy contract
let mut context = Context::default();
let dex_bin: Bytes = Loader::default().load_binary("dex-lock");
let dex_out_point = context.deploy_cell(dex_bin);
let dex_dep = CellDep::new_builder()
.out_point(dex_out_point.clone())
.build();

let always_success_code_hash = blake2b_256(ALWAYS_SUCCESS.clone());
let always_success_out_point = context.deploy_cell(ALWAYS_SUCCESS.clone());
let always_success_dep = CellDep::new_builder()
.out_point(always_success_out_point.clone())
.build();

let mut rng = thread_rng();
let owner_lock1 = context
.build_script(
&always_success_out_point,
rng.gen::<[u8; 20]>().to_vec().into(),
)
.expect("script");
let owner_lock2 = context
.build_script(
&always_success_out_point,
rng.gen::<[u8; 20]>().to_vec().into(),
)
.expect("script");
let other_lock = context
.build_script(
&always_success_out_point,
rng.gen::<[u8; 20]>().to_vec().into(),
)
.expect("script");

let setup = if error == DexError::DexSetupInvalid {
3u8
} else {
0u8
};
let dex_args1 = DexArgs {
owner_lock: owner_lock1.clone(),
setup,
total_value: 1234_5678_0000u128,
receiver_lock: None,
unit_type_hash: None,
};
let dex_lock_script1 = context
.build_script(&dex_out_point, dex_args1.to_vec().into())
.expect("script");

let dex_args2 = DexArgs {
owner_lock: owner_lock2.clone(),
setup: 0u8,
total_value: 9_8765_0000_1234u128,
receiver_lock: None,
unit_type_hash: None,
};
let mut dex_args2_vec = dex_args2.to_vec();
if error == DexError::LockArgsInvalid {
dex_args2_vec.reverse();
}
let dex_lock_script2 = context
.build_script(&dex_out_point, dex_args2_vec.into())
.expect("script");

let asset_type = ScriptBuilder::default()
.code_hash(Byte32::from_slice(&always_success_code_hash).unwrap())
.hash_type(Byte::from(2u8))
.build();

let asset_amount1 = Bytes::try_from(1000_0000_0000u128.to_le_bytes().to_vec()).unwrap();
let input_out_point1 = context.create_cell(
CellOutput::new_builder()
.capacity(300_0000_0000u64.pack())
.lock(dex_lock_script1)
.type_(Some(asset_type.clone()).pack())
.build(),
asset_amount1.clone(),
);
let asset_amount2 = Bytes::try_from(3456_0000_0000u128.to_le_bytes().to_vec()).unwrap();
let input_out_point2 = context.create_cell(
CellOutput::new_builder()
.capacity(240_0000_0000u64.pack())
.lock(dex_lock_script2)
.type_(Some(asset_type.clone()).pack())
.build(),
asset_amount2.clone(),
);

let inputs = vec![
CellInput::new_builder()
.previous_output(input_out_point1)
.build(),
CellInput::new_builder()
.previous_output(input_out_point2)
.build(),
];

let output1_capacity = if error == DexError::DexTotalValueNotMatch {
1234_5678_0000u64
} else {
1234_5678_0000u64 + 300_0000_0000u64
};
let output2_capacity = 9_8765_0000_1234u64 + 240_0000_0000u64;
let output2_lock = if error == DexError::DexOwnerLockNotMatch {
other_lock
} else {
owner_lock2
};
let outputs = vec![
CellOutput::new_builder()
.capacity(output1_capacity.pack())
.lock(owner_lock1)
.type_(Some(asset_type.clone()).pack())
.build(),
CellOutput::new_builder()
.capacity(output2_capacity.pack())
.lock(output2_lock)
.type_(Some(asset_type).pack())
.build(),
];

let outputs_data = vec![asset_amount1, asset_amount2];

let mut witnesses = vec![];
for _ in 0..inputs.len() {
witnesses.push(Bytes::new())
}

let cell_deps = vec![always_success_dep, dex_dep];
// build transaction
let tx = TransactionBuilder::default()
.inputs(inputs)
.outputs(outputs)
.outputs_data(outputs_data.pack())
.cell_deps(cell_deps)
.witnesses(witnesses.pack())
.build();
let tx = context.complete_tx(tx);

// sign
(context, tx)
}

#[test]
fn test_dex_taker_order_success() {
let (context, tx) = create_test_context(DexError::NoError);
// run
let cycles = context
.verify_tx(&tx, MAX_CYCLES)
.expect("pass verification");
println!("consume cycles: {}", cycles);
}

#[test]
fn test_dex_taker_order_lock_args_error() {
let (context, tx) = create_test_context(DexError::LockArgsInvalid);
// run
let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err();
assert_script_error(err, LOCK_ARGS_INVALID);
}

#[test]
fn test_dex_taker_order_owner_lock_not_match_error() {
let (context, tx) = create_test_context(DexError::DexOwnerLockNotMatch);
// run
let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err();
assert_script_error(err, DEX_OWNER_LOCK_NOT_MATCH);
}

#[test]
fn test_dex_taker_order_total_value_not_match_error() {
let (context, tx) = create_test_context(DexError::DexTotalValueNotMatch);
// run
let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err();
assert_script_error(err, DEX_TOTAL_VALUE_NOT_MATCH);
}

#[test]
fn test_dex_taker_order_total_setup_invalid_error() {
let (context, tx) = create_test_context(DexError::DexSetupInvalid);
// run
let err = context.verify_tx(&tx, MAX_CYCLES).unwrap_err();
assert_script_error(err, DEX_SETUP_INVALID);
}

0 comments on commit e3c0416

Please sign in to comment.