@@ -19,6 +19,8 @@ use aligned_sdk::verification_layer::estimate_fee;
1919use aligned_sdk:: verification_layer:: get_chain_id;
2020use aligned_sdk:: verification_layer:: get_nonce_from_batcher;
2121use aligned_sdk:: verification_layer:: get_nonce_from_ethereum;
22+ use aligned_sdk:: verification_layer:: unlock_balance_in_aligned;
23+ use aligned_sdk:: verification_layer:: withdraw_balance_from_aligned;
2224use aligned_sdk:: verification_layer:: { deposit_to_aligned, get_balance_in_aligned} ;
2325use aligned_sdk:: verification_layer:: { get_vk_commitment, save_response, submit_multiple} ;
2426use clap:: Args ;
@@ -42,7 +44,9 @@ use crate::AlignedCommands::GetUserNonce;
4244use crate :: AlignedCommands :: GetUserNonceFromEthereum ;
4345use crate :: AlignedCommands :: GetVkCommitment ;
4446use crate :: AlignedCommands :: Submit ;
47+ use crate :: AlignedCommands :: UnlockFunds ;
4548use crate :: AlignedCommands :: VerifyProofOnchain ;
49+ use crate :: AlignedCommands :: WithdrawFunds ;
4650
4751#[ derive( Parser , Debug ) ]
4852#[ command( version, about, long_about = None ) ]
@@ -65,6 +69,10 @@ pub enum AlignedCommands {
6569 name = "deposit-to-batcher"
6670 ) ]
6771 DepositToBatcher ( DepositToBatcherArgs ) ,
72+ #[ clap( about = "Unlocks funds from the batcher" , name = "unlock-funds" ) ]
73+ UnlockFunds ( UnlockFundsArgs ) ,
74+ #[ clap( about = "Withdraw funds from the batcher" , name = "withdraw-funds" ) ]
75+ WithdrawFunds ( WithdrawFundsArgs ) ,
6876 #[ clap( about = "Get user balance from the batcher" , name = "get-user-balance" ) ]
6977 GetUserBalance ( GetUserBalanceArgs ) ,
7078 #[ clap(
@@ -208,6 +216,38 @@ pub struct DepositToBatcherArgs {
208216 amount : String ,
209217}
210218
219+ #[ derive( Parser , Debug ) ]
220+ #[ command( version, about, long_about = None ) ]
221+ pub struct UnlockFundsArgs {
222+ #[ command( flatten) ]
223+ private_key_type : PrivateKeyType ,
224+ #[ arg(
225+ name = "Ethereum RPC provider address" ,
226+ long = "rpc_url" ,
227+ default_value = "http://localhost:8545"
228+ ) ]
229+ eth_rpc_url : String ,
230+ #[ clap( flatten) ]
231+ network : NetworkArg ,
232+ }
233+
234+ #[ derive( Parser , Debug ) ]
235+ #[ command( version, about, long_about = None ) ]
236+ pub struct WithdrawFundsArgs {
237+ #[ command( flatten) ]
238+ private_key_type : PrivateKeyType ,
239+ #[ arg(
240+ name = "Ethereum RPC provider address" ,
241+ long = "rpc_url" ,
242+ default_value = "http://localhost:8545"
243+ ) ]
244+ eth_rpc_url : String ,
245+ #[ clap( flatten) ]
246+ network : NetworkArg ,
247+ #[ arg( name = "Amount to withdraw" , long = "amount" , required = true ) ]
248+ amount : String ,
249+ }
250+
211251#[ derive( Parser , Debug ) ]
212252#[ command( version, about, long_about = None ) ]
213253pub struct VerifyProofOnchainArgs {
@@ -752,6 +792,105 @@ async fn main() -> Result<(), AlignedError> {
752792 }
753793 }
754794 }
795+ UnlockFunds ( args) => {
796+ let eth_rpc_url = args. eth_rpc_url ;
797+ let eth_rpc_provider =
798+ Provider :: < Http > :: try_from ( eth_rpc_url. clone ( ) ) . map_err ( |e| {
799+ SubmitError :: EthereumProviderError ( format ! (
800+ "Error while connecting to Ethereum: {}" ,
801+ e
802+ ) )
803+ } ) ?;
804+
805+ let keystore_path = & args. private_key_type . keystore_path ;
806+ let private_key = & args. private_key_type . private_key ;
807+
808+ let mut wallet = if let Some ( keystore_path) = keystore_path {
809+ let password = rpassword:: prompt_password ( "Please enter your keystore password:" )
810+ . map_err ( |e| SubmitError :: GenericError ( e. to_string ( ) ) ) ?;
811+ Wallet :: decrypt_keystore ( keystore_path, password)
812+ . map_err ( |e| SubmitError :: GenericError ( e. to_string ( ) ) ) ?
813+ } else if let Some ( private_key) = private_key {
814+ private_key
815+ . parse :: < LocalWallet > ( )
816+ . map_err ( |e| SubmitError :: GenericError ( e. to_string ( ) ) ) ?
817+ } else {
818+ warn ! ( "Missing keystore or private key used for payment." ) ;
819+ return Ok ( ( ) ) ;
820+ } ;
821+
822+ let chain_id = get_chain_id ( eth_rpc_url. as_str ( ) ) . await ?;
823+ wallet = wallet. with_chain_id ( chain_id) ;
824+
825+ let client = SignerMiddleware :: new ( eth_rpc_provider, wallet) ;
826+
827+ match unlock_balance_in_aligned ( & client, args. network . into ( ) ) . await {
828+ Ok ( receipt) => {
829+ info ! (
830+ "Funds in batcher unlocked successfully. Receipt: 0x{:x}" ,
831+ receipt. transaction_hash
832+ ) ;
833+ }
834+ Err ( e) => {
835+ error ! ( "Transaction failed: {:?}" , e) ;
836+ }
837+ }
838+ }
839+ WithdrawFunds ( args) => {
840+ if !args. amount . ends_with ( "ether" ) {
841+ error ! ( "Amount should be in the format XX.XXether" ) ;
842+ return Ok ( ( ) ) ;
843+ }
844+
845+ let amount_ether = args. amount . replace ( "ether" , "" ) ;
846+
847+ let amount_wei = parse_ether ( & amount_ether) . map_err ( |e| {
848+ SubmitError :: EthereumProviderError ( format ! ( "Error while parsing amount: {}" , e) )
849+ } ) ?;
850+
851+ let eth_rpc_url = args. eth_rpc_url ;
852+ let eth_rpc_provider =
853+ Provider :: < Http > :: try_from ( eth_rpc_url. clone ( ) ) . map_err ( |e| {
854+ SubmitError :: EthereumProviderError ( format ! (
855+ "Error while connecting to Ethereum: {}" ,
856+ e
857+ ) )
858+ } ) ?;
859+
860+ let keystore_path = & args. private_key_type . keystore_path ;
861+ let private_key = & args. private_key_type . private_key ;
862+
863+ let mut wallet = if let Some ( keystore_path) = keystore_path {
864+ let password = rpassword:: prompt_password ( "Please enter your keystore password:" )
865+ . map_err ( |e| SubmitError :: GenericError ( e. to_string ( ) ) ) ?;
866+ Wallet :: decrypt_keystore ( keystore_path, password)
867+ . map_err ( |e| SubmitError :: GenericError ( e. to_string ( ) ) ) ?
868+ } else if let Some ( private_key) = private_key {
869+ private_key
870+ . parse :: < LocalWallet > ( )
871+ . map_err ( |e| SubmitError :: GenericError ( e. to_string ( ) ) ) ?
872+ } else {
873+ warn ! ( "Missing keystore or private key used for payment." ) ;
874+ return Ok ( ( ) ) ;
875+ } ;
876+
877+ let chain_id = get_chain_id ( eth_rpc_url. as_str ( ) ) . await ?;
878+ wallet = wallet. with_chain_id ( chain_id) ;
879+
880+ let client = SignerMiddleware :: new ( eth_rpc_provider, wallet) ;
881+
882+ match withdraw_balance_from_aligned ( & client, args. network . into ( ) , amount_wei) . await {
883+ Ok ( receipt) => {
884+ info ! (
885+ "Balance withdraw from batcher successfully. Receipt: 0x{:x}" ,
886+ receipt. transaction_hash
887+ ) ;
888+ }
889+ Err ( e) => {
890+ error ! ( "Transaction failed: {:?}" , e) ;
891+ }
892+ }
893+ }
755894 GetUserBalance ( get_user_balance_args) => {
756895 let user_address = H160 :: from_str ( & get_user_balance_args. user_address ) . unwrap ( ) ;
757896 match get_balance_in_aligned (
0 commit comments