@@ -91,6 +91,9 @@ impl Command {
9191 command_withdraw ( config, command_config, matches, wallet_manager) . await
9292 }
9393 Command :: Display ( command_config) => command_display ( config, command_config) . await ,
94+ Command :: DepositSol ( command_config) => {
95+ command_deposit_sol ( config, command_config, matches, wallet_manager) . await
96+ }
9497 }
9598 }
9699}
@@ -822,6 +825,189 @@ async fn command_create_onramp(config: &Config, command_config: CreateOnRampCli)
822825 ) )
823826}
824827
828+ // deposit liquid sol
829+ async fn command_deposit_sol (
830+ config : & Config ,
831+ command_config : DepositSolCli ,
832+ matches : & ArgMatches ,
833+ wallet_manager : & mut Option < Rc < RemoteWalletManager > > ,
834+ ) -> CommandResult {
835+ let payer = config. fee_payer ( ) ?;
836+ let owner = config. default_signer ( ) ?;
837+
838+ let deposit_source = command_config
839+ . from
840+ . and_then ( |source| {
841+ signer_from_source ( matches, & source, "from" , wallet_manager)
842+ . ok ( )
843+ . map ( Arc :: from)
844+ } )
845+ . unwrap_or ( owner. clone ( ) ) ;
846+
847+ let deposit_amount = command_config. lamports ;
848+
849+ let pool_address = pool_address_from_args (
850+ command_config. pool_address ,
851+ command_config. vote_account_address ,
852+ ) ;
853+
854+ let pool_stake_address = find_pool_stake_address ( & spl_single_pool:: id ( ) , & pool_address) ;
855+ let onramp_address = find_pool_onramp_address ( & spl_single_pool:: id ( ) , & pool_address) ;
856+ let pool_mint_address = find_pool_mint_address ( & spl_single_pool:: id ( ) , & pool_address) ;
857+
858+ pool_is_initialized ( config, pool_address) . await ?;
859+
860+ let vote_account_address = get_vote_address_from_pool ( config, pool_address) . await ?;
861+
862+ if get_initialized_account ( config, onramp_address)
863+ . await ?
864+ . is_none ( )
865+ {
866+ return Err ( format ! (
867+ "Pool {} onramp {} does not exist" ,
868+ pool_address, onramp_address
869+ )
870+ . into ( ) ) ;
871+ }
872+
873+ let current_epoch = config. rpc_client . get_epoch_info ( ) . await ?. epoch ;
874+
875+ if let Some ( ( _, stake) ) = quarantine:: get_stake_info ( config, & pool_stake_address) . await ? {
876+ if stake. delegation . activation_epoch >= current_epoch {
877+ return Err ( format ! (
878+ "Pool {} stake {} is still activating; must be fully active" ,
879+ pool_address, pool_stake_address
880+ )
881+ . into ( ) ) ;
882+ }
883+
884+ if stake. delegation . deactivation_epoch < u64:: MAX {
885+ return Err ( format ! (
886+ "Pool {} stake {} is deactivating or deactivated" ,
887+ pool_address, pool_stake_address
888+ )
889+ . into ( ) ) ;
890+ }
891+ } else {
892+ // pool existence already validated and pool exists => stake exists
893+ unreachable ! ( ) ;
894+ } ;
895+
896+ {
897+ let deposit_source_balance = config
898+ . program_client
899+ . get_account ( deposit_source. pubkey ( ) )
900+ . await ?
901+ . map ( |account| account. lamports )
902+ . unwrap_or ( 0 ) ;
903+
904+ if deposit_source_balance < deposit_amount {
905+ return Err ( format ! (
906+ "Insufficient lamports in {} for deposit: has {}, needs {}" ,
907+ deposit_source. pubkey( ) ,
908+ deposit_source_balance,
909+ deposit_amount,
910+ )
911+ . into ( ) ) ;
912+ }
913+ }
914+
915+ println_display (
916+ config,
917+ format ! (
918+ "Depositing liquid sol from account {} into pool {}\n " ,
919+ deposit_source. pubkey( ) ,
920+ pool_address
921+ ) ,
922+ ) ;
923+
924+ let token = Token :: new (
925+ config. program_client . clone ( ) ,
926+ & spl_token:: id ( ) ,
927+ & pool_mint_address,
928+ None ,
929+ payer. clone ( ) ,
930+ ) ;
931+
932+ let mut instructions = vec ! [ ] ;
933+
934+ // use token account provided, or get/create the associated account for the client keypair
935+ let token_account_address = if let Some ( account) = command_config. token_account_address {
936+ account
937+ } else {
938+ let address = token. get_associated_token_address ( & owner. pubkey ( ) ) ;
939+ if get_initialized_account ( config, address) . await ?. is_none ( ) {
940+ instructions. push ( create_associated_token_account (
941+ & payer. pubkey ( ) ,
942+ & owner. pubkey ( ) ,
943+ & pool_mint_address,
944+ & spl_token:: id ( ) ,
945+ ) ) ;
946+ }
947+ address
948+ } ;
949+
950+ let previous_token_amount = match token. get_account_info ( & token_account_address) . await {
951+ Ok ( account) => account. base . amount ,
952+ Err ( _) => 0 ,
953+ } ;
954+
955+ // use escrow account for lamports to avoid exposing wallet signer to program
956+ let escrow_deposit_account = Keypair :: new ( ) ;
957+
958+ instructions. extend ( spl_single_pool:: instruction:: deposit_liquid (
959+ & spl_single_pool:: id ( ) ,
960+ & vote_account_address,
961+ & deposit_source. pubkey ( ) ,
962+ & escrow_deposit_account. pubkey ( ) ,
963+ & token_account_address,
964+ deposit_amount,
965+ ) ) ;
966+
967+ let mut signers = vec ! [ ] ;
968+ for signer in [
969+ payer. clone ( ) ,
970+ deposit_source,
971+ Arc :: new ( escrow_deposit_account) ,
972+ ] {
973+ if !signers. contains ( & signer) {
974+ signers. push ( signer) ;
975+ }
976+ }
977+
978+ let transaction = Transaction :: new_signed_with_payer (
979+ & instructions,
980+ Some ( & payer. pubkey ( ) ) ,
981+ & signers,
982+ config. program_client . get_latest_blockhash ( ) . await ?,
983+ ) ;
984+
985+ let signature = process_transaction ( config, transaction) . await ?;
986+
987+ let token_amount = if config. dry_run {
988+ None
989+ } else {
990+ Some (
991+ token
992+ . get_account_info ( & token_account_address)
993+ . await ?
994+ . base
995+ . amount
996+ - previous_token_amount,
997+ )
998+ } ;
999+
1000+ Ok ( format_output (
1001+ config,
1002+ "DepositSol" . to_string ( ) ,
1003+ DepositOutput {
1004+ pool_address,
1005+ token_amount,
1006+ signature,
1007+ } ,
1008+ ) )
1009+ }
1010+
8251011async fn get_initialized_account (
8261012 config : & Config ,
8271013 pubkey : Pubkey ,
0 commit comments