@@ -7,10 +7,10 @@ use std::str::FromStr;
7
7
8
8
use ckb_jsonrpc_types as json_types;
9
9
use ckb_jsonrpc_types:: JsonBytes ;
10
+ use ckb_sdk:: constants:: MultisigScript ;
10
11
use ckb_sdk:: {
11
- constants:: { MULTISIG_TYPE_HASH , SECP_SIGNATURE_SIZE } ,
12
- unlock:: MultisigConfig ,
13
- Address , AddressPayload , HumanCapacity , NetworkType ,
12
+ constants:: SECP_SIGNATURE_SIZE , unlock:: MultisigConfig , Address , AddressPayload , HumanCapacity ,
13
+ NetworkType ,
14
14
} ;
15
15
use ckb_types:: {
16
16
bytes:: Bytes ,
@@ -24,7 +24,10 @@ use clap::{App, Arg, ArgMatches};
24
24
use faster_hex:: hex_string;
25
25
use serde_derive:: { Deserialize , Serialize } ;
26
26
27
- use super :: { CliSubCommand , Output , ALLOW_ZERO_LOCK_HELP_MSG } ;
27
+ use super :: {
28
+ arg_get_multisig_code_hash, arg_multisig_code_hash, CliSubCommand , Output ,
29
+ ALLOW_ZERO_LOCK_HELP_MSG ,
30
+ } ;
28
31
use crate :: plugin:: { KeyStoreHandler , PluginManager , SignTarget } ;
29
32
use crate :: utils:: {
30
33
arg,
@@ -107,6 +110,7 @@ impl<'a> TxSubCommand<'a> {
107
110
App :: new( "add-multisig-config" )
108
111
. about( "Add multisig config" )
109
112
. arg( arg_sighash_address. clone( ) )
113
+ . arg( arg_multisig_code_hash( ) . required( true ) )
110
114
. arg( arg_require_first_n. clone( ) )
111
115
. arg( arg_threshold. clone( ) )
112
116
. arg( arg_tx_file. clone( ) ) ,
@@ -160,14 +164,25 @@ impl<'a> TxSubCommand<'a> {
160
164
. long( "to-short-multisig-address" )
161
165
. conflicts_with( "to-long-multisig-address" )
162
166
. takes_value( true )
163
- . validator( |input| AddressParser :: new_multisig( ) . validate( input) )
164
- . about( "To short multisig address" ) ,
167
+ . validator( |input| {
168
+ AddressParser :: new_multisig( MultisigScript :: Legacy )
169
+ . validate( input)
170
+ . or( AddressParser :: new_multisig( MultisigScript :: V2 )
171
+ . validate( input) )
172
+ } )
173
+ . about( "To short multisig address(encode with lagacy multisig script)" ) ,
165
174
)
166
175
. arg(
167
176
Arg :: with_name( "to-long-multisig-address" )
168
177
. long( "to-long-multisig-address" )
169
178
. takes_value( true )
170
- . validator( |input| AddressParser :: new_multisig( ) . validate( input) )
179
+ . requires( "multisig-code-hash" )
180
+ . validator( |input| {
181
+ AddressParser :: new_multisig( MultisigScript :: Legacy )
182
+ . validate( input)
183
+ . or( AddressParser :: new_multisig( MultisigScript :: V2 )
184
+ . validate( input) )
185
+ } )
171
186
. about( "To long multisig address (special case, include since)" ) ,
172
187
)
173
188
. arg( arg:: capacity( ) . required( true ) )
@@ -234,6 +249,7 @@ impl<'a> TxSubCommand<'a> {
234
249
)
235
250
. arg( arg_sighash_address. clone( ) )
236
251
. arg( arg_require_first_n. clone( ) )
252
+ . arg( arg_multisig_code_hash( ) . required( true ) )
237
253
. arg( arg_threshold. clone( ) )
238
254
. arg( arg_since_absolute_epoch. clone( ) ) ,
239
255
] )
@@ -308,13 +324,22 @@ impl CliSubCommand for TxSubCommand<'_> {
308
324
( "add-output" , Some ( m) ) => {
309
325
let tx_file: PathBuf = FilePathParser :: new ( true ) . from_matches ( m, "tx-file" ) ?;
310
326
let capacity: u64 = CapacityParser . from_matches ( m, "capacity" ) ?;
327
+
311
328
let to_sighash_address_opt: Option < Address > =
312
329
AddressParser :: new_sighash ( ) . from_matches_opt ( m, "to-sighash-address" ) ?;
313
- let to_short_multisig_address_opt: Option < Address > = AddressParser :: new_multisig ( )
314
- . from_matches_opt ( m, "to-short-multisig-address" ) ?;
315
- let to_long_multisig_address_opt: Option < Address > =
316
- AddressParser :: new_multisig ( )
317
- . from_matches_opt ( m, "to-long-multisig-address" ) ?;
330
+ let to_short_multisig_address_opt: Option < Address > =
331
+ AddressParser :: new_multisig ( MultisigScript :: Legacy )
332
+ . from_matches_opt ( m, "to-short-multisig-address" )
333
+ . or_else ( |_| {
334
+ AddressParser :: new_multisig ( MultisigScript :: V2 )
335
+ . from_matches_opt ( m, "to-short-multisig-address" )
336
+ } ) ?;
337
+ let to_long_multisig_address_opt: Option < Address > = {
338
+ AddressParser :: new_multisig ( MultisigScript :: Legacy )
339
+ . from_matches_opt ( m, "to-long-multisig-address" )
340
+ . or ( AddressParser :: new_multisig ( MultisigScript :: V2 )
341
+ . from_matches_opt ( m, "to-long-multisig-address" ) ) ?
342
+ } ;
318
343
319
344
let to_data = get_to_data ( m) ?;
320
345
check_capacity ( capacity, to_data. len ( ) ) ?;
@@ -355,6 +380,15 @@ impl CliSubCommand for TxSubCommand<'_> {
355
380
Ok ( Output :: new_success ( ) )
356
381
}
357
382
( "add-multisig-config" , Some ( m) ) => {
383
+ let multisig_lock_code_hash: H256 = arg_get_multisig_code_hash ( m) ?;
384
+ let multisig_script = MultisigScript :: try_from ( multisig_lock_code_hash. clone ( ) )
385
+ . map_err ( |_err| {
386
+ format ! (
387
+ "invalid multisig lock code hash: {}" ,
388
+ multisig_lock_code_hash
389
+ )
390
+ } ) ?;
391
+
358
392
let tx_file: PathBuf = FilePathParser :: new ( false ) . from_matches ( m, "tx-file" ) ?;
359
393
let sighash_addresses: Vec < Address > = AddressParser :: new_sighash ( )
360
394
. set_network ( network)
@@ -367,8 +401,13 @@ impl CliSubCommand for TxSubCommand<'_> {
367
401
. into_iter ( )
368
402
. map ( |address| H160 :: from_slice ( address. payload ( ) . args ( ) . as_ref ( ) ) . unwrap ( ) )
369
403
. collect :: < Vec < _ > > ( ) ;
370
- let cfg = MultisigConfig :: new_with ( sighash_addresses, require_first_n, threshold)
371
- . map_err ( |err| err. to_string ( ) ) ?;
404
+ let cfg = MultisigConfig :: new_with (
405
+ multisig_script,
406
+ sighash_addresses,
407
+ require_first_n,
408
+ threshold,
409
+ )
410
+ . map_err ( |err| err. to_string ( ) ) ?;
372
411
modify_tx_file ( & tx_file, network, |helper| {
373
412
helper. add_multisig_config ( cfg) ;
374
413
Ok ( ( ) )
@@ -567,6 +606,15 @@ impl CliSubCommand for TxSubCommand<'_> {
567
606
Ok ( Output :: new_output ( resp) )
568
607
}
569
608
( "build-multisig-address" , Some ( m) ) => {
609
+ let multisig_lock_code_hash: H256 = arg_get_multisig_code_hash ( m) ?;
610
+ let multisig_script = MultisigScript :: try_from ( multisig_lock_code_hash. clone ( ) )
611
+ . map_err ( |_err| {
612
+ format ! (
613
+ "invalid multisig lock code hash: {}" ,
614
+ multisig_lock_code_hash
615
+ )
616
+ } ) ?;
617
+
570
618
let sighash_addresses: Vec < Address > = AddressParser :: new_sighash ( )
571
619
. set_network ( network)
572
620
. from_matches_vec ( m, "sighash-address" ) ?;
@@ -580,9 +628,15 @@ impl CliSubCommand for TxSubCommand<'_> {
580
628
. into_iter ( )
581
629
. map ( |address| H160 :: from_slice ( address. payload ( ) . args ( ) . as_ref ( ) ) . unwrap ( ) )
582
630
. collect :: < Vec < _ > > ( ) ;
583
- let cfg = MultisigConfig :: new_with ( sighash_addresses, require_first_n, threshold)
584
- . map_err ( |err| err. to_string ( ) ) ?;
585
- let address_payload = cfg. to_address_payload ( since_absolute_epoch_opt) ;
631
+ let cfg = MultisigConfig :: new_with (
632
+ multisig_script,
633
+ sighash_addresses,
634
+ require_first_n,
635
+ threshold,
636
+ )
637
+ . map_err ( |err| err. to_string ( ) ) ?;
638
+ let address_payload =
639
+ cfg. to_address_payload ( multisig_script, since_absolute_epoch_opt) ;
586
640
let lock_script = Script :: from ( & address_payload) ;
587
641
let resp = serde_json:: json!( {
588
642
"mainnet" : Address :: new( NetworkType :: Mainnet , address_payload. clone( ) , true ) . to_string( ) ,
@@ -606,7 +660,12 @@ fn print_cell_info(
606
660
type_script_empty : bool ,
607
661
) {
608
662
let address_payload = AddressPayload :: from ( lock) ;
609
- let lock_kind = if address_payload. code_hash ( Some ( network) ) == MULTISIG_TYPE_HASH . pack ( ) {
663
+ let lock_kind = if [
664
+ MultisigScript :: Legacy . script_id ( ) . code_hash . pack ( ) ,
665
+ MultisigScript :: V2 . script_id ( ) . code_hash . pack ( ) ,
666
+ ]
667
+ . contains ( & address_payload. code_hash ( Some ( network) ) )
668
+ {
610
669
if address_payload. args ( ) . len ( ) == 20 {
611
670
"multisig without since"
612
671
} else {
@@ -787,11 +846,18 @@ impl TryFrom<ReprTxHelper> for TxHelper {
787
846
#[ derive( Clone , Default , Serialize , Deserialize , PartialEq , Eq , Debug ) ]
788
847
#[ serde( deny_unknown_fields) ]
789
848
pub struct ReprMultisigConfig {
849
+ #[ serde( default = "compatibility_lock_code_hash" ) ]
850
+ pub lock_code_hash : H256 ,
790
851
pub sighash_addresses : Vec < String > ,
791
852
pub require_first_n : u8 ,
792
853
pub threshold : u8 ,
793
854
}
794
855
856
+ // for compatibility
857
+ fn compatibility_lock_code_hash ( ) -> H256 {
858
+ MultisigScript :: Legacy . script_id ( ) . code_hash
859
+ }
860
+
795
861
impl ReprMultisigConfig {
796
862
pub ( crate ) fn new ( cfg : MultisigConfig , network : NetworkType ) -> Self {
797
863
let sighash_addresses = cfg
@@ -803,6 +869,7 @@ impl ReprMultisigConfig {
803
869
} )
804
870
. collect ( ) ;
805
871
ReprMultisigConfig {
872
+ lock_code_hash : cfg. lock_code_hash ( ) ,
806
873
sighash_addresses,
807
874
require_first_n : cfg. require_first_n ( ) ,
808
875
threshold : cfg. threshold ( ) ,
@@ -822,7 +889,14 @@ impl TryFrom<ReprMultisigConfig> for MultisigConfig {
822
889
. map_err ( |err| format ! ( "invalid address: {address_string} error: {err:?}" ) )
823
890
} )
824
891
. collect :: < Result < Vec < _ > , String > > ( ) ?;
825
- MultisigConfig :: new_with ( sighash_addresses, repr. require_first_n , repr. threshold )
826
- . map_err ( |err| err. to_string ( ) )
892
+ let multisig_script = MultisigScript :: try_from ( repr. lock_code_hash . clone ( ) )
893
+ . map_err ( |_err| format ! ( "invalid lock_code_hash {}" , repr. lock_code_hash) ) ?;
894
+ MultisigConfig :: new_with (
895
+ multisig_script,
896
+ sighash_addresses,
897
+ repr. require_first_n ,
898
+ repr. threshold ,
899
+ )
900
+ . map_err ( |err| err. to_string ( ) )
827
901
}
828
902
}
0 commit comments