diff --git a/clients/rust/marginfi-cli/src/entrypoint.rs b/clients/rust/marginfi-cli/src/entrypoint.rs index 7df6f2f06..c655ea43f 100644 --- a/clients/rust/marginfi-cli/src/entrypoint.rs +++ b/clients/rust/marginfi-cli/src/entrypoint.rs @@ -161,6 +161,36 @@ pub enum GroupCommand { #[clap(short = 't', long)] existing_token_lookup_tables: Vec, }, + InitFeeState { + #[clap(long)] + admin: Pubkey, + #[clap(long)] + fee_wallet: Pubkey, + #[clap(long)] + bank_init_flat_sol_fee: u32, + #[clap(long)] + program_fee_fixed: f64, + #[clap(long)] + program_fee_rate: f64, + }, + EditFeeState { + #[clap(long)] + fee_wallet: Pubkey, + #[clap(long)] + bank_init_flat_sol_fee: u32, + #[clap(long)] + program_fee_fixed: f64, + #[clap(long)] + program_fee_rate: f64, + }, + ConfigGroupFee { + #[clap(long)] + flag: u64, + }, + PropagateFee { + #[clap(long)] + marginfi_group: Pubkey, + }, } #[derive(Clone, Copy, Debug, Parser, ArgEnum)] @@ -309,6 +339,8 @@ pub enum BankCommand { }, CollectFees { bank: Pubkey, + #[clap(help = "The ATA for fee_state.global_fee_wallet and the bank's mint")] + fee_ata: Pubkey, }, WithdrawFees { bank: Pubkey, @@ -635,6 +667,36 @@ fn group(subcmd: GroupCommand, global_options: &GlobalOptions) -> Result<()> { &profile, existing_token_lookup_tables, ), + GroupCommand::InitFeeState { + admin, + fee_wallet, + bank_init_flat_sol_fee, + program_fee_fixed, + program_fee_rate, + } => processor::initialize_fee_state( + config, + admin, + fee_wallet, + bank_init_flat_sol_fee, + program_fee_fixed, + program_fee_rate, + ), + GroupCommand::EditFeeState { + fee_wallet, + bank_init_flat_sol_fee, + program_fee_fixed, + program_fee_rate, + } => processor::edit_fee_state( + config, + fee_wallet, + bank_init_flat_sol_fee, + program_fee_fixed, + program_fee_rate, + ), + GroupCommand::ConfigGroupFee { flag } => processor::config_group_fee(config, profile, flag), + GroupCommand::PropagateFee { marginfi_group } => { + processor::propagate_fee(config, marginfi_group) + } } } @@ -763,7 +825,9 @@ fn bank(subcmd: BankCommand, global_options: &GlobalOptions) -> Result<()> { BankCommand::SettleAllEmissions { bank } => { processor::emissions::claim_all_emissions_for_bank(&config, &profile, bank) } - BankCommand::CollectFees { bank } => processor::admin::process_collect_fees(config, bank), + BankCommand::CollectFees { bank, fee_ata } => { + processor::admin::process_collect_fees(config, bank, fee_ata) + } BankCommand::WithdrawFees { bank, amount, diff --git a/clients/rust/marginfi-cli/src/processor/admin.rs b/clients/rust/marginfi-cli/src/processor/admin.rs index 2c8f741dd..2552761ac 100644 --- a/clients/rust/marginfi-cli/src/processor/admin.rs +++ b/clients/rust/marginfi-cli/src/processor/admin.rs @@ -13,7 +13,7 @@ use solana_sdk::{ instruction::Instruction, message::Message, pubkey::Pubkey, transaction::Transaction, }; -pub fn process_collect_fees(config: Config, bank_pk: Pubkey) -> Result<()> { +pub fn process_collect_fees(config: Config, bank_pk: Pubkey, fee_ata: Pubkey) -> Result<()> { let bank = config.mfi_program.account::(bank_pk)?; let rpc_client = config.mfi_program.rpc(); @@ -33,7 +33,7 @@ pub fn process_collect_fees(config: Config, bank_pk: Pubkey) -> Result<()> { liquidity_vault: bank.liquidity_vault, insurance_vault: bank.insurance_vault, fee_state: find_fee_state_pda(&marginfi::id()).0, - fee_ata: find_fee_state_pda(&marginfi::id()).0, // TODO + fee_ata, } .to_account_metas(Some(true)), data: marginfi::instruction::LendingPoolCollectBankFees {}.data(), diff --git a/clients/rust/marginfi-cli/src/processor/mod.rs b/clients/rust/marginfi-cli/src/processor/mod.rs index bcfa6f28d..987b930cd 100644 --- a/clients/rust/marginfi-cli/src/processor/mod.rs +++ b/clients/rust/marginfi-cli/src/processor/mod.rs @@ -991,6 +991,170 @@ pub fn process_set_user_flag( Ok(()) } +pub fn initialize_fee_state( + config: Config, + admin: Pubkey, + fee_wallet: Pubkey, + bank_init_flat_sol_fee: u32, + program_fee_fixed: f64, + program_fee_rate: f64, +) -> Result<()> { + let program_fee_fixed: WrappedI80F48 = I80F48::from_num(program_fee_fixed).into(); + let program_fee_rate: WrappedI80F48 = I80F48::from_num(program_fee_rate).into(); + + let rpc_client = config.mfi_program.rpc(); + + let fee_state_pubkey = find_fee_state_pda(&config.program_id).0; + + let initialize_fee_state_ixs_builder = config.mfi_program.request(); + + let initialize_fee_state_ixs = initialize_fee_state_ixs_builder + .accounts(marginfi::accounts::InitFeeState { + payer: config.authority(), + fee_state: fee_state_pubkey, + rent: sysvar::rent::id(), + system_program: system_program::id(), + }) + .args(marginfi::instruction::InitGlobalFeeState { + admin, + fee_wallet, + bank_init_flat_sol_fee, + program_fee_fixed, + program_fee_rate, + }) + .instructions()?; + + let recent_blockhash = rpc_client.get_latest_blockhash().unwrap(); + let message = Message::new(&initialize_fee_state_ixs, Some(&config.authority())); + let mut transaction = Transaction::new_unsigned(message); + transaction.partial_sign(&config.get_signers(false), recent_blockhash); + + match process_transaction(&transaction, &rpc_client, config.get_tx_mode()) { + Ok(sig) => println!("Fee state initialized (sig: {})", sig), + Err(err) => { + println!("Error during fee state initialization:\n{:#?}", err); + return Err(anyhow!("Error during fee state initialization")); + } + }; + + Ok(()) +} + +pub fn edit_fee_state( + config: Config, + fee_wallet: Pubkey, + bank_init_flat_sol_fee: u32, + program_fee_fixed: f64, + program_fee_rate: f64, +) -> Result<()> { + let program_fee_fixed: WrappedI80F48 = I80F48::from_num(program_fee_fixed).into(); + let program_fee_rate: WrappedI80F48 = I80F48::from_num(program_fee_rate).into(); + + let rpc_client = config.mfi_program.rpc(); + + let fee_state_pubkey = find_fee_state_pda(&config.program_id).0; + + let edit_fee_state_ixs_builder = config.mfi_program.request(); + + let edit_fee_state_ixs = edit_fee_state_ixs_builder + .accounts(marginfi::accounts::EditFeeState { + global_fee_admin: config.authority(), + fee_state: fee_state_pubkey, + }) + .args(marginfi::instruction::EditGlobalFeeState { + fee_wallet, + bank_init_flat_sol_fee, + program_fee_fixed, + program_fee_rate, + }) + .instructions()?; + + let recent_blockhash = rpc_client.get_latest_blockhash().unwrap(); + let message = Message::new(&edit_fee_state_ixs, Some(&config.authority())); + let mut transaction = Transaction::new_unsigned(message); + transaction.partial_sign(&config.get_signers(false), recent_blockhash); + + match process_transaction(&transaction, &rpc_client, config.get_tx_mode()) { + Ok(sig) => println!("Fee state edited (sig: {})", sig), + Err(err) => { + println!("Error during fee state edit:\n{:#?}", err); + return Err(anyhow!("Error during fee state edit")); + } + }; + + Ok(()) +} + +pub fn config_group_fee(config: Config, profile: Profile, flag: u64) -> Result<()> { + let rpc_client = config.mfi_program.rpc(); + let marginfi_group_pubkey = profile.marginfi_group.ok_or_else(|| { + anyhow!( + "Marginfi group does not exist for profile [{}]", + profile.name + ) + })?; + + let fee_state_pubkey = find_fee_state_pda(&profile.program_id.unwrap()).0; + + let config_group_fee_ixs_builder = config.mfi_program.request(); + + let config_group_fee_ixs = config_group_fee_ixs_builder + .accounts(marginfi::accounts::ConfigGroupFee { + marginfi_group: marginfi_group_pubkey, + global_fee_admin: config.authority(), + fee_state: fee_state_pubkey, + }) + .args(marginfi::instruction::ConfigGroupFee { flag }) + .instructions()?; + + let recent_blockhash = rpc_client.get_latest_blockhash().unwrap(); + let message = Message::new(&config_group_fee_ixs, Some(&config.authority())); + let mut transaction = Transaction::new_unsigned(message); + transaction.partial_sign(&config.get_signers(false), recent_blockhash); + + match process_transaction(&transaction, &rpc_client, config.get_tx_mode()) { + Ok(sig) => println!("Config group fee updated (sig: {})", sig), + Err(err) => { + println!("Error during config group fee update:\n{:#?}", err); + return Err(anyhow!("Error during config group fee update")); + } + }; + + Ok(()) +} + +/// Note: doing this one group at a time is tedious, consider running the script instead. +pub fn propagate_fee(config: Config, marginfi_group: Pubkey) -> Result<()> { + let rpc_client = config.mfi_program.rpc(); + + let fee_state_pubkey = find_fee_state_pda(&config.program_id).0; + + let propagate_fee_ixs_builder = config.mfi_program.request(); + + let propagate_fee_ixs = propagate_fee_ixs_builder + .accounts(marginfi::accounts::PropagateFee { + fee_state: fee_state_pubkey, + marginfi_group, + }) + .args(marginfi::instruction::PropagateFeeState {}) + .instructions()?; + + let recent_blockhash = rpc_client.get_latest_blockhash().unwrap(); + let message = Message::new(&propagate_fee_ixs, None); + let mut transaction = Transaction::new_unsigned(message); + transaction.partial_sign(&config.get_signers(false), recent_blockhash); + + match process_transaction(&transaction, &rpc_client, config.get_tx_mode()) { + Ok(sig) => println!("Fee propagated (sig: {})", sig), + Err(err) => { + println!("Error during fee propagation:\n{:#?}", err); + return Err(anyhow!("Error during fee propagation")); + } + }; + + Ok(()) +} + // -------------------------------------------------------------------------------------------------------------------- // bank // --------------------------------------------------------------------------------------------------------------------