@@ -51,6 +51,17 @@ pub enum SelectorsSubcommands {
5151 #[ clap( flatten) ]
5252 project_paths : ProjectPathsArgs ,
5353 } ,
54+
55+ /// List selectors from current workspace
56+ #[ clap( visible_alias = "ls" ) ]
57+ List {
58+ /// The name of the contract to list selectors for.
59+ #[ clap( help = "The name of the contract to list selectors for." ) ]
60+ contract : Option < String > ,
61+
62+ #[ clap( flatten) ]
63+ project_paths : ProjectPathsArgs ,
64+ } ,
5465}
5566
5667impl SelectorsSubcommands {
@@ -176,6 +187,95 @@ impl SelectorsSubcommands {
176187 println ! ( "{table}" ) ;
177188 }
178189 }
190+ SelectorsSubcommands :: List { contract, project_paths } => {
191+ println ! ( "Listing selectors for contracts in the project..." ) ;
192+ let build_args = CoreBuildArgs {
193+ project_paths : project_paths. clone ( ) ,
194+ compiler : CompilerArgs {
195+ extra_output : vec ! [ ContractOutputSelection :: Abi ] ,
196+ ..Default :: default ( )
197+ } ,
198+ ..Default :: default ( )
199+ } ;
200+
201+ // compile the project to get the artifacts/abis
202+ let project = build_args. project ( ) ?;
203+ let outcome = compile:: suppress_compile ( & project) ?;
204+ let artifacts = if let Some ( contract) = contract {
205+ let found_artifact = outcome. find_first ( & contract) ;
206+ let artifact = found_artifact
207+ . ok_or_else ( || {
208+ let candidates = outcome
209+ . artifacts ( )
210+ . map ( |( name, _, ) | name)
211+ . collect :: < Vec < _ > > ( ) ;
212+ let suggestion = if let Some ( suggestion) = foundry_cli:: utils:: did_you_mean ( & contract, candidates) . pop ( ) {
213+ format ! ( "\n Did you mean `{suggestion}`?" )
214+ } else {
215+ "" . to_string ( )
216+ } ;
217+ eyre:: eyre!(
218+ "Could not find artifact `{contract}` in the compiled artifacts{suggestion}" ,
219+ )
220+ } ) ?
221+ . clone ( ) ;
222+ vec ! [ ( contract, artifact) ]
223+ } else {
224+ outcome
225+ . into_artifacts_with_files ( )
226+ . filter ( |( file, _, _) | {
227+ let is_sources_path = file
228+ . starts_with ( & project. paths . sources . to_string_lossy ( ) . to_string ( ) ) ;
229+ let is_test = file. is_sol_test ( ) ;
230+
231+ is_sources_path && !is_test
232+ } )
233+ . map ( |( _, contract, artifact) | ( contract, artifact) )
234+ . collect ( )
235+ } ;
236+
237+ let mut artifacts = artifacts. into_iter ( ) . peekable ( ) ;
238+
239+ while let Some ( ( contract, artifact) ) = artifacts. next ( ) {
240+ let abi = artifact. abi . ok_or ( eyre:: eyre!( "Unable to fetch abi" ) ) ?;
241+ if abi. abi . functions . is_empty ( ) &&
242+ abi. abi . events . is_empty ( ) &&
243+ abi. abi . errors . is_empty ( )
244+ {
245+ continue
246+ }
247+
248+ println ! ( "{contract}" ) ;
249+
250+ let mut table = Table :: new ( ) ;
251+
252+ table. set_header ( vec ! [ "Type" , "Signature" , "Selector" ] ) ;
253+
254+ for func in abi. abi . functions ( ) {
255+ let sig = func. signature ( ) ;
256+ let selector = func. selector ( ) ;
257+ table. add_row ( vec ! [ "Function" , & sig, & hex:: encode_prefixed( selector) ] ) ;
258+ }
259+
260+ for event in abi. abi . events ( ) {
261+ let sig = event. signature ( ) ;
262+ let selector = event. selector ( ) ;
263+ table. add_row ( vec ! [ "Event" , & sig, & hex:: encode_prefixed( selector) ] ) ;
264+ }
265+
266+ for error in abi. abi . errors ( ) {
267+ let sig = error. signature ( ) ;
268+ let selector = error. selector ( ) ;
269+ table. add_row ( vec ! [ "Error" , & sig, & hex:: encode_prefixed( selector) ] ) ;
270+ }
271+
272+ println ! ( "{table}" ) ;
273+
274+ if artifacts. peek ( ) . is_some ( ) {
275+ println ! ( )
276+ }
277+ }
278+ }
179279 }
180280 Ok ( ( ) )
181281 }
0 commit comments