1+ use ckb_hash:: blake2b_256;
12use ckb_jsonrpc_types as json_types;
23use std:: collections:: HashMap ;
34
45use crate :: {
56 constants:: { ONE_CKB , SIGHASH_TYPE_HASH } ,
7+ test_util:: random_out_point,
68 tests:: {
79 build_sighash_script, init_context,
810 omni_lock:: { build_omnilock_script, build_omnilock_unlockers, OMNILOCK_BIN } ,
911 ACCOUNT0_ARG , ACCOUNT0_KEY , ACCOUNT1_ARG , ACCOUNT1_KEY , ACCOUNT2_ARG , ACCOUNT2_KEY ,
10- ACCOUNT3_ARG , ACCOUNT3_KEY , FEE_RATE ,
12+ ACCOUNT3_ARG , ACCOUNT3_KEY , FEE_RATE , SUDT_BIN ,
1113 } ,
1214 traits:: { CellCollector , CellQueryOptions , SecpCkbRawKeySigner } ,
1315 tx_builder:: {
14- omni_lock:: OmniLockTransferBuilder , transfer:: CapacityTransferBuilderWithTransaction ,
16+ omni_lock:: OmniLockTransferBuilder , transfer:: CapacityTransferBuilder ,
17+ udt:: UdtTransferBuilder ,
1518 } ,
1619 unlock:: {
1720 opentx:: OpentxWitness , MultisigConfig , OmniLockConfig , OmniUnlockMode , ScriptUnlocker ,
@@ -24,35 +27,40 @@ use crate::{
2427use ckb_crypto:: secp:: { Pubkey , SECP256K1 } ;
2528use ckb_types:: {
2629 bytes:: Bytes ,
27- packed:: { CellOutput , WitnessArgs } ,
30+ core:: { Capacity , ScriptHashType } ,
31+ packed:: { CellInput , CellOutput , Script , WitnessArgs } ,
2832 prelude:: * ,
33+ H160 , H256 ,
2934} ;
3035use rand:: Rng ;
3136
3237use crate :: tx_builder:: { unlock_tx, CapacityBalancer , TxBuilder } ;
3338const ZERO_FEE_RATE : u64 = 0 ;
3439
35- #[ test]
36- fn test_omnilock_transfer_from_sighash ( ) {
37- let sender_key = secp256k1:: SecretKey :: from_slice ( ACCOUNT0_KEY . as_bytes ( ) )
40+ fn build_simple_config ( key : H256 ) -> OmniLockConfig {
41+ let priv_key = secp256k1:: SecretKey :: from_slice ( key. as_bytes ( ) )
3842 . map_err ( |err| format ! ( "invalid sender secret key: {}" , err) )
3943 . unwrap ( ) ;
40- let pubkey = secp256k1:: PublicKey :: from_secret_key ( & SECP256K1 , & sender_key) ;
41- let cfg = OmniLockConfig :: new_pubkey_hash ( blake160 ( & pubkey. serialize ( ) ) ) ;
42- test_omnilock_simple_hash ( cfg) ;
44+ let pubkey = secp256k1:: PublicKey :: from_secret_key ( & SECP256K1 , & priv_key) ;
45+ OmniLockConfig :: new_pubkey_hash ( blake160 ( & pubkey. serialize ( ) ) )
46+ }
47+ #[ test]
48+ fn test_opentx_pay_from_sighash ( ) {
49+ let cfg = build_simple_config ( ACCOUNT0_KEY ) ;
50+ test_opentx_pay_simple_hash ( cfg) ;
4351}
4452
4553#[ test]
46- fn test_omnilock_transfer_from_ethereum ( ) {
54+ fn test_opentx_pay_from_ethereum ( ) {
4755 let account0_key = secp256k1:: SecretKey :: from_slice ( ACCOUNT0_KEY . as_bytes ( ) ) . unwrap ( ) ;
4856 let pubkey = secp256k1:: PublicKey :: from_secret_key ( & SECP256K1 , & account0_key) ;
4957 let cfg = OmniLockConfig :: new_ethereum ( keccak160 ( Pubkey :: from ( pubkey) . as_ref ( ) ) ) ;
50- test_omnilock_simple_hash ( cfg) ;
58+ test_opentx_pay_simple_hash ( cfg) ;
5159}
5260
5361/// account0(200) => account0(exchange 199) + open pay 1,
5462/// account2(100) => account2(101 - transaction fee)
55- fn test_omnilock_simple_hash ( mut cfg : OmniLockConfig ) {
63+ fn test_opentx_pay_simple_hash ( mut cfg : OmniLockConfig ) {
5664 cfg. set_opentx_mode ( ) ;
5765 let unlock_mode = OmniUnlockMode :: Normal ;
5866 let sender = build_omnilock_script ( & cfg) ;
@@ -135,7 +143,7 @@ fn test_omnilock_simple_hash(mut cfg: OmniLockConfig) {
135143 // .lock(receiver.clone())
136144 // .capacity((100 * ONE_CKB).pack())
137145 // .build();
138- let builder = CapacityTransferBuilderWithTransaction :: new (
146+ let builder = CapacityTransferBuilder :: new_with_transaction (
139147 vec ! [ /*(output.clone(), Bytes::default())*/ ] ,
140148 tx,
141149 ) ;
@@ -165,7 +173,7 @@ fn test_omnilock_simple_hash(mut cfg: OmniLockConfig) {
165173/// multisig(200) => multisig(exchange 199) + open pay 1, locked by account0, account1, account2
166174/// account3(400) => account2(401 - transaction fee)
167175#[ test]
168- fn test_omnilock_transfer_from_multisig ( ) {
176+ fn test_opentx_pay_from_multisig ( ) {
169177 let unlock_mode = OmniUnlockMode :: Normal ;
170178 let lock_args = vec ! [
171179 ACCOUNT0_ARG . clone( ) ,
@@ -263,7 +271,7 @@ fn test_omnilock_transfer_from_multisig() {
263271 // .lock(receiver.clone())
264272 // .capacity((100 * ONE_CKB).pack())
265273 // .build();
266- let builder = CapacityTransferBuilderWithTransaction :: new (
274+ let builder = CapacityTransferBuilder :: new_with_transaction (
267275 vec ! [ /*(output.clone(), Bytes::default())*/ ] ,
268276 tx,
269277 ) ;
@@ -296,36 +304,28 @@ fn test_omnilock_transfer_from_multisig() {
296304}
297305
298306#[ test]
299- fn test_omnilock_transfer_from_sighash_absolute_from_start ( ) {
300- test_omnilock_transfer_from_sighash_absolute ( true ) ;
307+ fn test_opentx_pay_receive_sighash_absolute_from_start ( ) {
308+ test_opentx_pay_receive_sighash_absolute ( true ) ;
301309}
302310#[ test]
303- fn test_omnilock_transfer_from_sighash_absolute_self ( ) {
304- test_omnilock_transfer_from_sighash_absolute ( false ) ;
311+ fn test_opentx_pay_receive_sighash_absolute_self ( ) {
312+ test_opentx_pay_receive_sighash_absolute ( false ) ;
305313}
306- fn test_omnilock_transfer_from_sighash_absolute ( from_start : bool ) {
307- let cfgs: Vec < OmniLockConfig > = [ ACCOUNT0_KEY , ACCOUNT2_KEY ]
308- . iter ( )
309- . map ( |key| {
310- let priv_key = secp256k1:: SecretKey :: from_slice ( key. as_bytes ( ) )
311- . map_err ( |err| format ! ( "invalid sender secret key: {}" , err) )
312- . unwrap ( ) ;
313- let pubkey = secp256k1:: PublicKey :: from_secret_key ( & SECP256K1 , & priv_key) ;
314- OmniLockConfig :: new_pubkey_hash ( blake160 ( & pubkey. serialize ( ) ) )
315- } )
316- . collect ( ) ;
317- test_omnilock_simple_hash_absolute ( cfgs[ 0 ] . clone ( ) , cfgs[ 1 ] . clone ( ) , from_start) ;
314+ fn test_opentx_pay_receive_sighash_absolute ( from_start : bool ) {
315+ let sender_cfg = build_simple_config ( ACCOUNT0_KEY ) ;
316+ let receiver_cfg = build_simple_config ( ACCOUNT2_KEY ) ;
317+ test_opentx_pay_receive_simple_hash_absolute ( sender_cfg, receiver_cfg, from_start) ;
318318}
319319
320320#[ test]
321- fn test_omnilock_transfer_from_ethereum_absolute_from_start ( ) {
322- test_omnilock_transfer_from_ethereum_absolute ( true ) ;
321+ fn test_opentx_pay_receive_ethereum_absolute_from_start ( ) {
322+ test_opentx_pay_receive_ethereum_absolute ( true ) ;
323323}
324324#[ test]
325- fn test_omnilock_transfer_from_ethereum_absolute_from_self ( ) {
326- test_omnilock_transfer_from_ethereum_absolute ( false ) ;
325+ fn test_opentx_pay_receive_ethereum_absolute_from_self ( ) {
326+ test_opentx_pay_receive_ethereum_absolute ( false ) ;
327327}
328- fn test_omnilock_transfer_from_ethereum_absolute ( from_start : bool ) {
328+ fn test_opentx_pay_receive_ethereum_absolute ( from_start : bool ) {
329329 let cfgs: Vec < OmniLockConfig > = [ ACCOUNT0_KEY , ACCOUNT2_KEY ]
330330 . iter ( )
331331 . map ( |key| {
@@ -334,12 +334,12 @@ fn test_omnilock_transfer_from_ethereum_absolute(from_start: bool) {
334334 OmniLockConfig :: new_ethereum ( keccak160 ( Pubkey :: from ( pubkey) . as_ref ( ) ) )
335335 } )
336336 . collect ( ) ;
337- test_omnilock_simple_hash_absolute ( cfgs[ 0 ] . clone ( ) , cfgs[ 1 ] . clone ( ) , from_start) ;
337+ test_opentx_pay_receive_simple_hash_absolute ( cfgs[ 0 ] . clone ( ) , cfgs[ 1 ] . clone ( ) , from_start) ;
338338}
339339
340340/// account0(200) => account0(exchange 199) + open pay 1,
341341/// account2(100) => account2(101 - transaction fee)
342- fn test_omnilock_simple_hash_absolute (
342+ fn test_opentx_pay_receive_simple_hash_absolute (
343343 mut sender_cfg : OmniLockConfig ,
344344 mut receiver_cfg : OmniLockConfig ,
345345 from_start : bool ,
@@ -410,7 +410,7 @@ fn test_omnilock_simple_hash_absolute(
410410 // If adjust the transaction fee later, the exchange may mot be enough to maintain the minimal capacity.
411411 let balancer = CapacityBalancer :: new_simple ( receiver. clone ( ) , placeholder_witness, FEE_RATE ) ;
412412
413- let builder = CapacityTransferBuilderWithTransaction :: new (
413+ let builder = CapacityTransferBuilder :: new_with_transaction (
414414 vec ! [ /*(output.clone(), Bytes::default())*/ ] ,
415415 tx,
416416 ) ;
@@ -464,18 +464,18 @@ fn test_omnilock_simple_hash_absolute(
464464 ctx. verify ( tx, FEE_RATE ) . unwrap ( ) ;
465465}
466466#[ test]
467- fn test_omnilock_transfer_from_multisig_absolute_from_start ( ) {
468- test_omnilock_transfer_from_multisig_absolute ( true ) ;
467+ fn test_opentx_pay_receive_multisig_absolute_from_start ( ) {
468+ test_opentx_pay_receive_multisig_absolute ( true ) ;
469469}
470470
471471#[ test]
472- fn test_omnilock_transfer_from_multisig_absolute_from_self ( ) {
473- test_omnilock_transfer_from_multisig_absolute ( false ) ;
472+ fn test_opentx_pay_receive_multisig_absolute_from_self ( ) {
473+ test_opentx_pay_receive_multisig_absolute ( false ) ;
474474}
475475
476476/// multisig(200) => multisig(exchange 199) + open pay 1, locked by account0, account1, account2
477477/// account3(400) => account2(401 - transaction fee)
478- fn test_omnilock_transfer_from_multisig_absolute ( from_start : bool ) {
478+ fn test_opentx_pay_receive_multisig_absolute ( from_start : bool ) {
479479 let unlock_mode = OmniUnlockMode :: Normal ;
480480 let lock_args = vec ! [
481481 ACCOUNT0_ARG . clone( ) ,
@@ -564,7 +564,7 @@ fn test_omnilock_transfer_from_multisig_absolute(from_start: bool) {
564564 let placeholder_witness = receiver_cfg. placeholder_witness ( unlock_mode) . unwrap ( ) ;
565565 let balancer = CapacityBalancer :: new_simple ( receiver. clone ( ) , placeholder_witness, FEE_RATE ) ;
566566
567- let builder = CapacityTransferBuilderWithTransaction :: new ( vec ! [ ] , tx) ;
567+ let builder = CapacityTransferBuilder :: new_with_transaction ( vec ! [ ] , tx) ;
568568 let mut tx = builder
569569 . build_balanced ( & mut cell_collector, & ctx, & ctx, & ctx, & balancer, & unlockers)
570570 . unwrap ( ) ;
@@ -613,3 +613,139 @@ fn test_omnilock_transfer_from_multisig_absolute(from_start: bool) {
613613 assert_eq ! ( tx. witnesses( ) . len( ) , 2 ) ;
614614 ctx. verify ( tx, FEE_RATE ) . unwrap ( ) ;
615615}
616+
617+ #[ test]
618+ fn test_opentx_udt_open_buy ( ) {
619+ // ACCOUNT1(alice) will spend 50.01 CKB with fee to buy 1,000,000 SUDT
620+ // ACCOUNT2(bob) collect the 50 CKB with the transfer 1,000,000 SUDT
621+ let unlock_mode = OmniUnlockMode :: Normal ;
622+ let mut alice_cfg = build_simple_config ( ACCOUNT1_KEY ) ;
623+ alice_cfg. set_opentx_mode ( ) ;
624+ let alice = build_omnilock_script ( & alice_cfg) ;
625+ let bob = build_sighash_script ( ACCOUNT2_ARG ) ;
626+
627+ let mut ctx = init_context (
628+ vec ! [ ( OMNILOCK_BIN , true ) , ( SUDT_BIN , false ) ] ,
629+ vec ! [
630+ ( alice. clone( ) , Some ( 300 * ONE_CKB ) ) ,
631+ ( bob. clone( ) , Some ( 400 * ONE_CKB ) ) ,
632+ ] ,
633+ ) ;
634+ let sudt_data_hash = H256 :: from ( blake2b_256 ( SUDT_BIN ) ) ;
635+ let owner = build_sighash_script ( H160 :: default ( ) ) ;
636+ let type_script = Script :: new_builder ( )
637+ . code_hash ( sudt_data_hash. pack ( ) )
638+ . hash_type ( ScriptHashType :: Data1 . into ( ) )
639+ . args ( owner. calc_script_hash ( ) . as_bytes ( ) . pack ( ) )
640+ . build ( ) ;
641+ let sudt_input = CellInput :: new ( random_out_point ( ) , 0 ) ;
642+ let sudt_output = CellOutput :: new_builder ( )
643+ . capacity ( ONE_CKB . pack ( ) )
644+ . lock ( bob. clone ( ) )
645+ . type_ ( Some ( type_script. clone ( ) ) . pack ( ) )
646+ . build ( ) ;
647+ let sudt_capacity = sudt_output
648+ . occupied_capacity ( Capacity :: bytes ( 16 ) . unwrap ( ) )
649+ . unwrap ( )
650+ . as_u64 ( ) ;
651+ println ! ( "sudt_capacity: {}" , sudt_capacity) ;
652+ let sudt_output = sudt_output
653+ . as_builder ( )
654+ . capacity ( sudt_capacity. pack ( ) )
655+ . build ( ) ;
656+ let sudt_data = Bytes :: from ( 1_000_000u128 . to_le_bytes ( ) . to_vec ( ) ) ;
657+ ctx. add_live_cell ( sudt_input, sudt_output, sudt_data. clone ( ) , None ) ;
658+
659+ let fee = 100_0000u64 ;
660+ // build opentx alice's input
661+ let builder = OmniLockTransferBuilder :: new_open (
662+ ( 50 * ONE_CKB + sudt_capacity + fee) . into ( ) ,
663+ vec ! [ ] ,
664+ alice_cfg. clone ( ) ,
665+ None ,
666+ ) ;
667+ let placeholder_witness = alice_cfg. placeholder_witness ( unlock_mode) . unwrap ( ) ;
668+ let balancer = CapacityBalancer :: new_simple ( alice. clone ( ) , placeholder_witness, ZERO_FEE_RATE ) ;
669+
670+ let mut cell_collector = ctx. to_live_cells_context ( ) ;
671+ let alice_key = secp256k1:: SecretKey :: from_slice ( ACCOUNT1_KEY . as_bytes ( ) ) . unwrap ( ) ;
672+ let unlockers = build_omnilock_unlockers ( alice_key, alice_cfg. clone ( ) , unlock_mode) ;
673+ let mut tx = builder
674+ . build_balanced ( & mut cell_collector, & ctx, & ctx, & ctx, & balancer, & unlockers)
675+ . unwrap ( ) ;
676+ // add sudt output
677+ let sudt_output = CellOutput :: new_builder ( )
678+ . capacity ( ( sudt_capacity) . pack ( ) )
679+ . lock ( alice. clone ( ) )
680+ . type_ ( Some ( type_script. clone ( ) ) . pack ( ) )
681+ . build ( ) ;
682+ tx = tx
683+ . as_advanced_builder ( )
684+ . output ( sudt_output. clone ( ) )
685+ . output_data ( sudt_data. pack ( ) )
686+ . build ( ) ;
687+ // update opentx input list
688+ let mut rng = rand:: thread_rng ( ) ;
689+ let salt: u32 = rng. gen ( ) ;
690+ let wit = OpentxWitness :: new_sig_all_relative ( & tx, Some ( salt) ) . unwrap ( ) ;
691+ alice_cfg. set_opentx_input ( wit) ;
692+ tx = OmniLockTransferBuilder :: update_opentx_witness (
693+ tx,
694+ & alice_cfg,
695+ OmniUnlockMode :: Normal ,
696+ & ctx,
697+ & alice,
698+ )
699+ . unwrap ( ) ;
700+ // config updated, so unlockers must rebuilt.
701+ let unlockers = build_omnilock_unlockers ( alice_key, alice_cfg. clone ( ) , unlock_mode) ;
702+ let ( new_tx, new_locked_groups) = unlock_tx ( tx. clone ( ) , & ctx, & unlockers) . unwrap ( ) ;
703+ assert ! ( new_locked_groups. is_empty( ) ) ;
704+ tx = new_tx;
705+ println ! (
706+ "> tx: {}" ,
707+ serde_json:: to_string_pretty( & json_types:: TransactionView :: from( tx. clone( ) ) ) . unwrap( )
708+ ) ;
709+ // use opentx
710+ let builder = UdtTransferBuilder :: new_with_transaction ( type_script, bob. clone ( ) , vec ! [ ] , tx) ;
711+ let placeholder_witness = WitnessArgs :: new_builder ( )
712+ . lock ( Some ( Bytes :: from ( vec ! [ 0u8 ; 65 ] ) ) . pack ( ) )
713+ . build ( ) ;
714+ let balancer = CapacityBalancer :: new_simple ( bob, placeholder_witness, FEE_RATE ) ;
715+
716+ let bob_key = secp256k1:: SecretKey :: from_slice ( ACCOUNT2_KEY . as_bytes ( ) ) . unwrap ( ) ;
717+ let signer = SecpCkbRawKeySigner :: new_with_secret_keys ( vec ! [ bob_key] ) ;
718+ let script_unlocker = SecpSighashUnlocker :: from ( Box :: new ( signer) as Box < _ > ) ;
719+ let mut unlockers: HashMap < ScriptId , Box < dyn ScriptUnlocker > > = HashMap :: default ( ) ;
720+ unlockers. insert (
721+ ScriptId :: new_type ( SIGHASH_TYPE_HASH . clone ( ) ) ,
722+ Box :: new ( script_unlocker) ,
723+ ) ;
724+
725+ let mut cell_collector = ctx. to_live_cells_context ( ) ;
726+ let ( tx, locked_groups) = builder
727+ . build_unlocked ( & mut cell_collector, & ctx, & ctx, & ctx, & balancer, & unlockers)
728+ . unwrap ( ) ;
729+ println ! (
730+ "> tx: {}" ,
731+ serde_json:: to_string_pretty( & json_types:: TransactionView :: from( tx. clone( ) ) ) . unwrap( )
732+ ) ;
733+ assert_eq ! ( locked_groups. len( ) , 1 ) ;
734+ assert_eq ! ( tx. header_deps( ) . len( ) , 0 ) ;
735+ assert_eq ! ( tx. cell_deps( ) . len( ) , 3 ) ;
736+ assert_eq ! ( tx. inputs( ) . len( ) , 3 ) ;
737+ let outputs = tx. outputs ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
738+ assert_eq ! ( outputs. len( ) , 4 ) ;
739+ assert_eq ! ( outputs[ 1 ] , sudt_output) ;
740+ let expected_outputs_data = vec ! [
741+ Bytes :: from( 1_000_000u128 . to_le_bytes( ) . to_vec( ) ) ,
742+ Bytes :: from( 0u128 . to_le_bytes( ) . to_vec( ) ) ,
743+ ] ;
744+ let outputs_data = tx
745+ . outputs_data ( )
746+ . into_iter ( )
747+ . map ( |d| d. raw_data ( ) )
748+ . collect :: < Vec < _ > > ( ) ;
749+ assert_eq ! ( outputs_data[ 1 ..3 ] , expected_outputs_data) ;
750+ ctx. verify ( tx, FEE_RATE ) . unwrap ( ) ;
751+ }
0 commit comments