@@ -4,15 +4,18 @@ use std::path::Path;
4
4
5
5
use crate :: {
6
6
cli:: { self , traits:: * } ,
7
- common:: wallet:: { prompt_to_use_wallet, request_signature} ,
7
+ common:: {
8
+ chain:: { self , Chain } ,
9
+ wallet:: { self , prompt_to_use_wallet} ,
10
+ } ,
8
11
} ;
9
12
use anyhow:: { anyhow, Result } ;
10
13
use clap:: Args ;
11
14
use pop_parachains:: {
12
15
construct_extrinsic, construct_sudo_extrinsic, decode_call_data, encode_call_data,
13
- find_dispatchable_by_name, find_pallet_by_name, parse_chain_metadata , set_up_client ,
14
- sign_and_submit_extrinsic , submit_signed_extrinsic , supported_actions , Action , CallData ,
15
- DynamicPayload , Function , OnlineClient , Pallet , Param , Payload , SubstrateConfig ,
16
+ find_dispatchable_by_name, find_pallet_by_name, sign_and_submit_extrinsic , supported_actions ,
17
+ Action , CallData , DynamicPayload , Function , OnlineClient , Pallet , Param , Payload ,
18
+ SubstrateConfig ,
16
19
} ;
17
20
use url:: Url ;
18
21
@@ -67,10 +70,17 @@ impl CallChainCommand {
67
70
/// Executes the command.
68
71
pub ( crate ) async fn execute ( mut self ) -> Result < ( ) > {
69
72
let mut cli = cli:: Cli ;
73
+ cli. intro ( "Call a chain" ) ?;
70
74
// Check if all fields are specified via the command line.
71
75
let prompt_to_repeat_call = self . requires_user_input ( ) ;
72
76
// Configure the chain.
73
- let chain = self . configure_chain ( & mut cli) . await ?;
77
+ let chain = chain:: configure (
78
+ "Which chain would you like to interact with?" ,
79
+ DEFAULT_URL ,
80
+ & self . url ,
81
+ & mut cli,
82
+ )
83
+ . await ?;
74
84
// Execute the call if call_data is provided.
75
85
if let Some ( call_data) = self . call_data . as_ref ( ) {
76
86
if let Err ( e) = self
@@ -109,7 +119,9 @@ impl CallChainCommand {
109
119
// Sign and submit the extrinsic.
110
120
let result = if self . use_wallet {
111
121
let call_data = xt. encode_call_data ( & chain. client . metadata ( ) ) ?;
112
- submit_extrinsic_with_wallet ( & chain. client , & chain. url , call_data, & mut cli) . await
122
+ wallet:: submit_extrinsic ( & chain. client , & chain. url , call_data, & mut cli)
123
+ . await
124
+ . map ( |_| ( ) ) // Mapping to `()` since we don't need events returned
113
125
} else {
114
126
call. submit_extrinsic ( & chain. client , & chain. url , xt, & mut cli) . await
115
127
} ;
@@ -132,33 +144,6 @@ impl CallChainCommand {
132
144
Ok ( ( ) )
133
145
}
134
146
135
- // Configures the chain by resolving the URL and fetching its metadata.
136
- async fn configure_chain ( & self , cli : & mut impl Cli ) -> Result < Chain > {
137
- cli. intro ( "Call a chain" ) ?;
138
- // Resolve url.
139
- let url = match & self . url {
140
- Some ( url) => url. clone ( ) ,
141
- None => {
142
- // Prompt for url.
143
- let url: String = cli
144
- . input ( "Which chain would you like to interact with?" )
145
- . default_input ( DEFAULT_URL )
146
- . interact ( ) ?;
147
- Url :: parse ( & url) ?
148
- } ,
149
- } ;
150
-
151
- // Parse metadata from chain url.
152
- let client = set_up_client ( url. as_str ( ) ) . await ?;
153
- let mut pallets = parse_chain_metadata ( & client) . map_err ( |e| {
154
- anyhow ! ( format!( "Unable to fetch the chain metadata: {}" , e. to_string( ) ) )
155
- } ) ?;
156
- // Sort by name for display.
157
- pallets. sort_by ( |a, b| a. name . cmp ( & b. name ) ) ;
158
- pallets. iter_mut ( ) . for_each ( |p| p. functions . sort_by ( |a, b| a. name . cmp ( & b. name ) ) ) ;
159
- Ok ( Chain { url, client, pallets } )
160
- }
161
-
162
147
// Configure the call based on command line arguments/call UI.
163
148
fn configure_call ( & mut self , chain : & Chain , cli : & mut impl Cli ) -> Result < Call > {
164
149
loop {
@@ -244,7 +229,7 @@ impl CallChainCommand {
244
229
if use_wallet {
245
230
let call_data_bytes =
246
231
decode_call_data ( call_data) . map_err ( |err| anyhow ! ( "{}" , format!( "{err:?}" ) ) ) ?;
247
- submit_extrinsic_with_wallet ( client, url, call_data_bytes, cli)
232
+ wallet :: submit_extrinsic ( client, url, call_data_bytes, cli)
248
233
. await
249
234
. map_err ( |err| anyhow ! ( "{}" , format!( "{err:?}" ) ) ) ?;
250
235
display_message ( "Call complete." , true , cli) ?;
@@ -357,41 +342,31 @@ impl CallChainCommand {
357
342
}
358
343
}
359
344
360
- // Represents a chain, including its URL, client connection, and available pallets.
361
- struct Chain {
362
- // Websocket endpoint of the node.
363
- url : Url ,
364
- // The client used to interact with the chain.
365
- client : OnlineClient < SubstrateConfig > ,
366
- // A list of pallets available on the chain.
367
- pallets : Vec < Pallet > ,
368
- }
369
-
370
345
/// Represents a configured dispatchable function call, including the pallet, function, arguments,
371
346
/// and signing options.
372
- #[ derive( Clone ) ]
373
- struct Call {
347
+ #[ derive( Clone , Default ) ]
348
+ pub ( crate ) struct Call {
374
349
/// The dispatchable function to execute.
375
- function : Function ,
350
+ pub ( crate ) function : Function ,
376
351
/// The dispatchable function arguments, encoded as strings.
377
- args : Vec < String > ,
352
+ pub ( crate ) args : Vec < String > ,
378
353
/// Secret key URI for the account signing the extrinsic.
379
354
///
380
355
/// e.g.
381
356
/// - for a dev account "//Alice"
382
357
/// - with a password "//Alice///SECRET_PASSWORD"
383
- suri : String ,
358
+ pub ( crate ) suri : String ,
384
359
/// Whether to use your browser wallet to sign the extrinsic.
385
- use_wallet : bool ,
360
+ pub ( crate ) use_wallet : bool ,
386
361
/// Whether to automatically sign and submit the extrinsic without prompting for confirmation.
387
- skip_confirm : bool ,
362
+ pub ( crate ) skip_confirm : bool ,
388
363
/// Whether to dispatch the function call with `Root` origin.
389
- sudo : bool ,
364
+ pub ( crate ) sudo : bool ,
390
365
}
391
366
392
367
impl Call {
393
368
// Prepares the extrinsic.
394
- fn prepare_extrinsic (
369
+ pub ( crate ) fn prepare_extrinsic (
395
370
& self ,
396
371
client : & OnlineClient < SubstrateConfig > ,
397
372
cli : & mut impl Cli ,
@@ -473,32 +448,6 @@ impl Call {
473
448
}
474
449
}
475
450
476
- // Sign and submit an extrinsic using wallet integration.
477
- async fn submit_extrinsic_with_wallet (
478
- client : & OnlineClient < SubstrateConfig > ,
479
- url : & Url ,
480
- call_data : Vec < u8 > ,
481
- cli : & mut impl Cli ,
482
- ) -> Result < ( ) > {
483
- let maybe_payload = request_signature ( call_data, url. to_string ( ) ) . await ?;
484
- if let Some ( payload) = maybe_payload {
485
- cli. success ( "Signed payload received." ) ?;
486
- let spinner = cliclack:: spinner ( ) ;
487
- spinner. start (
488
- "Submitting the extrinsic and then waiting for finalization, please be patient..." ,
489
- ) ;
490
-
491
- let result = submit_signed_extrinsic ( client. clone ( ) , payload)
492
- . await
493
- . map_err ( |err| anyhow ! ( "{}" , format!( "{err:?}" ) ) ) ?;
494
-
495
- spinner. stop ( format ! ( "Extrinsic submitted with hash: {:?}" , result) ) ;
496
- } else {
497
- display_message ( "No signed payload received." , false , cli) ?;
498
- }
499
- Ok ( ( ) )
500
- }
501
-
502
451
// Displays a message to the user, with formatting based on the success status.
503
452
fn display_message ( message : & str , success : bool , cli : & mut impl Cli ) -> Result < ( ) > {
504
453
if success {
@@ -670,33 +619,20 @@ fn parse_function_name(name: &str) -> Result<String, String> {
670
619
mod tests {
671
620
use super :: * ;
672
621
use crate :: { cli:: MockCli , common:: wallet:: USE_WALLET_PROMPT } ;
622
+ use pop_parachains:: { parse_chain_metadata, set_up_client} ;
673
623
use tempfile:: tempdir;
674
624
use url:: Url ;
675
625
676
626
const BOB_SURI : & str = "//Bob" ;
677
627
const POP_NETWORK_TESTNET_URL : & str = "wss://rpc1.paseo.popnetwork.xyz" ;
678
628
const POLKADOT_NETWORK_URL : & str = "wss://polkadot-rpc.publicnode.com" ;
679
629
680
- #[ tokio:: test]
681
- async fn configure_chain_works ( ) -> Result < ( ) > {
682
- let call_config =
683
- CallChainCommand { suri : Some ( DEFAULT_URI . to_string ( ) ) , ..Default :: default ( ) } ;
684
- let mut cli = MockCli :: new ( ) . expect_intro ( "Call a chain" ) . expect_input (
685
- "Which chain would you like to interact with?" ,
686
- POP_NETWORK_TESTNET_URL . into ( ) ,
687
- ) ;
688
- let chain = call_config. configure_chain ( & mut cli) . await ?;
689
- assert_eq ! ( chain. url, Url :: parse( POP_NETWORK_TESTNET_URL ) ?) ;
690
- cli. verify ( )
691
- }
692
-
693
630
#[ tokio:: test]
694
631
async fn guide_user_to_call_chain_works ( ) -> Result < ( ) > {
695
632
let mut call_config =
696
633
CallChainCommand { pallet : Some ( "System" . to_string ( ) ) , ..Default :: default ( ) } ;
697
634
698
635
let mut cli = MockCli :: new ( )
699
- . expect_intro ( "Call a chain" )
700
636
. expect_input ( "Which chain would you like to interact with?" , POP_NETWORK_TESTNET_URL . into ( ) )
701
637
. expect_select (
702
638
"Select the function to call:" ,
@@ -724,7 +660,13 @@ mod tests {
724
660
. expect_confirm ( "Would you like to dispatch this function call with `Root` origin?" , true )
725
661
. expect_confirm ( USE_WALLET_PROMPT , true ) ;
726
662
727
- let chain = call_config. configure_chain ( & mut cli) . await ?;
663
+ let chain = chain:: configure (
664
+ "Which chain would you like to interact with?" ,
665
+ POP_NETWORK_TESTNET_URL ,
666
+ & None ,
667
+ & mut cli,
668
+ )
669
+ . await ?;
728
670
assert_eq ! ( chain. url, Url :: parse( POP_NETWORK_TESTNET_URL ) ?) ;
729
671
730
672
let call_chain = call_config. configure_call ( & chain, & mut cli) ?;
@@ -742,11 +684,17 @@ mod tests {
742
684
async fn guide_user_to_configure_predefined_action_works ( ) -> Result < ( ) > {
743
685
let mut call_config = CallChainCommand :: default ( ) ;
744
686
745
- let mut cli = MockCli :: new ( ) . expect_intro ( "Call a chain" ) . expect_input (
687
+ let mut cli = MockCli :: new ( ) . expect_input (
746
688
"Which chain would you like to interact with?" ,
747
689
POLKADOT_NETWORK_URL . into ( ) ,
748
690
) ;
749
- let chain = call_config. configure_chain ( & mut cli) . await ?;
691
+ let chain = chain:: configure (
692
+ "Which chain would you like to interact with?" ,
693
+ POP_NETWORK_TESTNET_URL ,
694
+ & None ,
695
+ & mut cli,
696
+ )
697
+ . await ?;
750
698
assert_eq ! ( chain. url, Url :: parse( POLKADOT_NETWORK_URL ) ?) ;
751
699
cli. verify ( ) ?;
752
700
@@ -896,20 +844,30 @@ mod tests {
896
844
sudo : true ,
897
845
} ;
898
846
let mut cli = MockCli :: new ( )
899
- . expect_intro ( "Call a chain" )
900
847
. expect_warning ( "NOTE: sudo is not supported by the chain. Ignoring `--sudo` flag." ) ;
901
- let chain = call_config. configure_chain ( & mut cli) . await ?;
848
+ let chain = chain:: configure (
849
+ "Which chain would you like to interact with?" ,
850
+ POP_NETWORK_TESTNET_URL ,
851
+ & Some ( Url :: parse ( POLKADOT_NETWORK_URL ) ?) ,
852
+ & mut cli,
853
+ )
854
+ . await ?;
902
855
call_config. configure_sudo ( & chain, & mut cli) ?;
903
856
assert ! ( !call_config. sudo) ;
904
857
cli. verify ( ) ?;
905
858
906
859
// Test when sudo pallet exist.
907
- cli = MockCli :: new ( ) . expect_intro ( "Call a chain" ) . expect_confirm (
860
+ cli = MockCli :: new ( ) . expect_confirm (
908
861
"Would you like to dispatch this function call with `Root` origin?" ,
909
862
true ,
910
863
) ;
911
- call_config. url = Some ( Url :: parse ( POP_NETWORK_TESTNET_URL ) ?) ;
912
- let chain = call_config. configure_chain ( & mut cli) . await ?;
864
+ let chain = chain:: configure (
865
+ "Which chain would you like to interact with?" ,
866
+ POP_NETWORK_TESTNET_URL ,
867
+ & Some ( Url :: parse ( POP_NETWORK_TESTNET_URL ) ?) ,
868
+ & mut cli,
869
+ )
870
+ . await ?;
913
871
call_config. configure_sudo ( & chain, & mut cli) ?;
914
872
assert ! ( call_config. sudo) ;
915
873
cli. verify ( )
0 commit comments