@@ -3,7 +3,10 @@ use alloy_chains::Chain;
33use alloy_dyn_abi:: TypedData ;
44use alloy_primitives:: { hex, Address , PrimitiveSignature as Signature , B256 , U256 } ;
55use alloy_provider:: Provider ;
6- use alloy_signer:: Signer ;
6+ use alloy_signer:: {
7+ k256:: { elliptic_curve:: sec1:: ToEncodedPoint , SecretKey } ,
8+ Signer ,
9+ } ;
710use alloy_signer_local:: {
811 coins_bip39:: { English , Entropy , Mnemonic } ,
912 MnemonicBuilder , PrivateKeySigner ,
@@ -210,7 +213,16 @@ pub enum WalletSubcommands {
210213 #[ command( flatten) ]
211214 wallet : WalletOpts ,
212215 } ,
216+ /// Get the public key for the given private key.
217+ #[ command( visible_aliases = & [ "pubkey" ] ) ]
218+ PublicKey {
219+ /// If provided, the public key will be derived from the specified private key.
220+ #[ arg( long = "raw-private-key" , value_name = "PRIVATE_KEY" ) ]
221+ private_key_override : Option < String > ,
213222
223+ #[ command( flatten) ]
224+ wallet : WalletOpts ,
225+ } ,
214226 /// Decrypt a keystore file to get the private key
215227 #[ command( name = "decrypt-keystore" , visible_alias = "dk" ) ]
216228 DecryptKeystore {
@@ -398,6 +410,34 @@ impl WalletSubcommands {
398410 let addr = wallet. address ( ) ;
399411 sh_println ! ( "{}" , addr. to_checksum( None ) ) ?;
400412 }
413+ Self :: PublicKey { wallet, private_key_override } => {
414+ let wallet = private_key_override
415+ . map ( |pk| WalletOpts {
416+ raw : RawWalletOpts { private_key : Some ( pk) , ..Default :: default ( ) } ,
417+ ..Default :: default ( )
418+ } )
419+ . unwrap_or ( wallet)
420+ . signer ( )
421+ . await ?;
422+
423+ let private_key_bytes = match wallet {
424+ WalletSigner :: Local ( wallet) => wallet. credential ( ) . to_bytes ( ) ,
425+ _ => eyre:: bail!( "Only local wallets are supported by this command" ) ,
426+ } ;
427+
428+ let secret_key = SecretKey :: from_slice ( & private_key_bytes)
429+ . map_err ( |e| eyre:: eyre!( "Invalid private key: {}" , e) ) ?;
430+
431+ // Get the public key from the private key
432+ let public_key = secret_key. public_key ( ) ;
433+
434+ // Serialize it as uncompressed (65 bytes: 0x04 || X (32 bytes) || Y (32 bytes))
435+ let pubkey_bytes = public_key. to_encoded_point ( false ) ;
436+ // Strip the 1-byte prefix (0x04) to get 64 bytes for Ethereum use
437+ let ethereum_pubkey = & pubkey_bytes. as_bytes ( ) [ 1 ..] ;
438+
439+ sh_println ! ( "0x{}" , hex:: encode( ethereum_pubkey) ) ?;
440+ }
401441 Self :: Sign { message, data, from_file, no_hash, wallet } => {
402442 let wallet = wallet. signer ( ) . await ?;
403443 let sig = if data {
0 commit comments