Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/args/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod call_handler;
mod commit_state;
mod delegate;
mod delegate_ephemeral_balance;
mod set_fees_receiver;
mod top_up_ephemeral_balance;
mod validator_claim_fees;
mod whitelist_validator_for_program;
Expand All @@ -10,6 +11,7 @@ pub use call_handler::*;
pub use commit_state::*;
pub use delegate::*;
pub use delegate_ephemeral_balance::*;
pub use set_fees_receiver::*;
pub use top_up_ephemeral_balance::*;
pub use validator_claim_fees::*;
pub use whitelist_validator_for_program::*;
7 changes: 7 additions & 0 deletions src/args/set_fees_receiver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::pubkey::Pubkey;

#[derive(BorshSerialize, BorshDeserialize)]
pub struct SetFeesReceiverArgs {
pub fees_receiver: Pubkey,
}
3 changes: 3 additions & 0 deletions src/discriminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ pub enum DlpDiscriminator {
CloseValidatorFeesVault = 14,
/// See [crate::processor::process_call_handler] for docs.
CallHandler = 15,
/// See [crate::processor::process_set_fees_receiver] for docs.
SetFeesReceiver = 16,
}

impl DlpDiscriminator {
Expand Down Expand Up @@ -63,6 +65,7 @@ impl TryFrom<[u8; 8]> for DlpDiscriminator {
0xd => Ok(DlpDiscriminator::CommitStateFromBuffer),
0xe => Ok(DlpDiscriminator::CloseValidatorFeesVault),
0xf => Ok(DlpDiscriminator::CallHandler),
0x10 => Ok(DlpDiscriminator::SetFeesReceiver),
_ => Err(ProgramError::InvalidInstructionData),
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/instruction_builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod finalize;
mod init_protocol_fees_vault;
mod init_validator_fees_vault;
mod protocol_claim_fees;
mod set_fees_receiver;
mod top_up_ephemeral_balance;
mod undelegate;
mod validator_claim_fees;
Expand All @@ -25,6 +26,7 @@ pub use finalize::*;
pub use init_protocol_fees_vault::*;
pub use init_validator_fees_vault::*;
pub use protocol_claim_fees::*;
pub use set_fees_receiver::*;
pub use top_up_ephemeral_balance::*;
pub use undelegate::*;
pub use validator_claim_fees::*;
Expand Down
14 changes: 7 additions & 7 deletions src/instruction_builder/protocol_claim_fees.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
use solana_program::instruction::Instruction;
use solana_program::{bpf_loader_upgradeable, instruction::AccountMeta, pubkey::Pubkey};
use solana_program::{instruction::AccountMeta, pubkey::Pubkey};

use crate::discriminator::DlpDiscriminator;
use crate::pda::fees_vault_pda;
use crate::pda::{fees_vault_pda, program_config_from_program_id};

/// Claim the accrued fees from the protocol fees vault.
/// See [crate::processor::process_protocol_claim_fees] for docs.
pub fn protocol_claim_fees(admin: Pubkey) -> Instruction {
pub fn protocol_claim_fees(fees_receiver: Pubkey, program: Pubkey) -> Instruction {
let fees_vault_pda = fees_vault_pda();
let delegation_program_data =
Pubkey::find_program_address(&[crate::ID.as_ref()], &bpf_loader_upgradeable::id()).0;
let program_config_pda = program_config_from_program_id(&program);
Instruction {
program_id: crate::id(),
accounts: vec![
AccountMeta::new(admin, true),
AccountMeta::new(fees_vault_pda, false),
AccountMeta::new_readonly(delegation_program_data, false),
AccountMeta::new(program_config_pda, false),
AccountMeta::new(fees_receiver, false),
AccountMeta::new_readonly(program, false),
],
data: DlpDiscriminator::ProtocolClaimFees.to_vec(),
}
Expand Down
32 changes: 32 additions & 0 deletions src/instruction_builder/set_fees_receiver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use borsh::to_vec;
use solana_program::instruction::Instruction;
use solana_program::{
bpf_loader_upgradeable, instruction::AccountMeta, pubkey::Pubkey, system_program,
};

use crate::args::SetFeesReceiverArgs;
use crate::discriminator::DlpDiscriminator;
use crate::pda::program_config_from_program_id;

/// Set the fees receiver.
/// See [crate::processor::process_set_fees_receiver] for docs.
pub fn set_fees_receiver(admin: Pubkey, fees_receiver: Pubkey, program: Pubkey) -> Instruction {
let program_config_pda = program_config_from_program_id(&program);
let delegation_program_data =
Pubkey::find_program_address(&[crate::ID.as_ref()], &bpf_loader_upgradeable::id()).0;
Instruction {
program_id: crate::id(),
accounts: vec![
AccountMeta::new(admin, true),
AccountMeta::new(program_config_pda, false),
AccountMeta::new_readonly(program, false),
AccountMeta::new_readonly(system_program::id(), false),
AccountMeta::new_readonly(delegation_program_data, false),
],
data: [
DlpDiscriminator::SetFeesReceiver.to_vec(),
to_vec(&SetFeesReceiverArgs { fees_receiver }).unwrap(),
]
.concat(),
}
}
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ pub fn process_instruction(
discriminator::DlpDiscriminator::CallHandler => {
process_call_handler(program_id, accounts, data)?
}
discriminator::DlpDiscriminator::SetFeesReceiver => {
processor::process_set_fees_receiver(program_id, accounts, data)?
}
}
Ok(())
}
2 changes: 2 additions & 0 deletions src/processor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod finalize;
mod init_protocol_fees_vault;
mod init_validator_fees_vault;
mod protocol_claim_fees;
mod set_fees_receiver;
mod top_up_ephemeral_balance;
mod undelegate;
mod utils;
Expand All @@ -26,6 +27,7 @@ pub use finalize::*;
pub use init_protocol_fees_vault::*;
pub use init_validator_fees_vault::*;
pub use protocol_claim_fees::*;
pub use set_fees_receiver::*;
pub use top_up_ephemeral_balance::*;
pub use undelegate::*;
pub use validator_claim_fees::*;
Expand Down
39 changes: 19 additions & 20 deletions src/processor/protocol_claim_fees.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use crate::error::DlpError::Unauthorized;
use crate::processor::utils::loaders::{
load_initialized_protocol_fees_vault, load_program_upgrade_authority, load_signer,
load_account, load_initialized_protocol_fees_vault, load_program_config,
};
use solana_program::msg;
use crate::state::ProgramConfig;
use solana_program::program_error::ProgramError;
use solana_program::rent::Rent;
use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};
Expand All @@ -11,15 +10,17 @@ use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubke
///
/// Accounts:
///
/// 1. `[signer]` admin account that can claim the fees
/// 2. `[writable]` protocol fees vault PDA
/// 1. `[writable]` protocol fees vault PDA
/// 2. `[]` program config PDA
/// 3. `[writable]` fees receiver PDA
/// 4. `[]` delegation program
///
/// Requirements:
///
/// - protocol fees vault is initialized
/// - protocol fees vault has enough lamports to claim fees and still be
/// rent exempt
/// - admin is the protocol fees vault admin
/// - fees receiver is the correct one
///
/// 1. Transfer lamports from protocol fees_vault PDA to the admin authority
pub fn process_protocol_claim_fees(
Expand All @@ -28,25 +29,23 @@ pub fn process_protocol_claim_fees(
_data: &[u8],
) -> ProgramResult {
// Load Accounts
let [admin, fees_vault, delegation_program_data] = accounts else {
let [fees_vault, program_config_account, fees_receiver, program] = accounts else {
return Err(ProgramError::NotEnoughAccountKeys);
};

// Check if the admin is signer
load_signer(admin, "admin")?;
load_initialized_protocol_fees_vault(fees_vault, true)?;
load_program_config(program_config_account, *program.key, true)?;

// Check if the admin is the correct one
let admin_pubkey =
load_program_upgrade_authority(&crate::ID, delegation_program_data)?.ok_or(Unauthorized)?;
if !admin.key.eq(&admin_pubkey) {
msg!(
"Expected admin pubkey: {} but got {}",
admin_pubkey,
admin.key
);
return Err(Unauthorized.into());
}
let program_config_data = program_config_account.try_borrow_data()?;
let program_config = ProgramConfig::try_from_bytes_with_discriminator(&program_config_data)?;

load_account(
fees_receiver,
program_config.fees_receiver,
true,
"fees receiver",
)?;

// Calculate the amount to transfer
let min_rent = Rent::default().minimum_balance(8);
Expand All @@ -61,7 +60,7 @@ pub fn process_protocol_claim_fees(
.checked_sub(amount)
.ok_or(ProgramError::InsufficientFunds)?;

**admin.try_borrow_mut_lamports()? = admin
**fees_receiver.try_borrow_mut_lamports()? = fees_receiver
.lamports()
.checked_add(amount)
.ok_or(ProgramError::ArithmeticOverflow)?;
Expand Down
92 changes: 92 additions & 0 deletions src/processor/set_fees_receiver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use crate::args::SetFeesReceiverArgs;
use crate::error::DlpError::Unauthorized;
use crate::processor::utils::loaders::{
load_program_config, load_program_upgrade_authority, load_signer,
};
use crate::processor::utils::pda::resize_pda;
use crate::state::ProgramConfig;
use borsh::BorshDeserialize;
use solana_program::msg;
use solana_program::program_error::ProgramError;
use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};

/// Process request to set the fees receiver
///
/// Accounts:
///
/// 1. `[signer, writable]` admin account that can set the fees receiver
/// 2. `[writable]` program config PDA
/// 3. `[]` program
/// 4. `[]` system program
///
/// Requirements:
///
/// - program config is initialized
/// - admin is the protocol config admin
///
/// 1. Set the fees receiver in the protocol config
pub fn process_set_fees_receiver(
_program_id: &Pubkey,
accounts: &[AccountInfo],
data: &[u8],
) -> ProgramResult {
// Load Accounts
let [admin, program_config_account, program, system_program, delegation_program_data] =
accounts
else {
return Err(ProgramError::NotEnoughAccountKeys);
};

// Check if the admin is signer
load_signer(admin, "admin")?;

// Check if the admin is the correct one
let admin_pubkey =
load_program_upgrade_authority(&crate::ID, delegation_program_data)?.ok_or(Unauthorized)?;
if !admin.key.eq(&admin_pubkey) {
msg!(
"Expected admin pubkey: {} but got {}",
admin_pubkey,
admin.key
);
return Err(Unauthorized.into());
}

// Check if the program config is initialized
if !load_program_config(program_config_account, *program.key, true)? {
return Err(ProgramError::UninitializedAccount);
}

// Migrate to the new account structure
let (mut program_config, migrated) = {
let program_config_data = program_config_account.try_borrow_data()?;
match ProgramConfig::try_from_bytes_with_discriminator(&program_config_data) {
Ok(program_config) => (program_config, false),
Err(_) => {
// Migrating the account
let mut data = program_config_data.to_vec();
data.extend(Pubkey::default().to_bytes());
let program_config = ProgramConfig::try_from_bytes_with_discriminator(&data)?;

(program_config, true)
}
}
};

if migrated {
resize_pda(
admin,
program_config_account,
system_program,
program_config.size_with_discriminator(),
)?;
}

let args = SetFeesReceiverArgs::try_from_slice(data)?;
program_config.fees_receiver = args.fees_receiver;

let mut program_config_data = program_config_account.try_borrow_mut_data()?;
program_config.to_bytes_with_discriminator(&mut program_config_data.as_mut())?;

Ok(())
}
5 changes: 4 additions & 1 deletion src/processor/whitelist_validator_for_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ pub fn process_whitelist_validator_for_program(
system_program,
authority,
)?;
ProgramConfig::default()
ProgramConfig {
approved_validators: Default::default(),
fees_receiver: *authority.key,
}
} else {
let program_config_data = program_config_account.try_borrow_data()?;
ProgramConfig::try_from_bytes_with_discriminator(&program_config_data)?
Expand Down
3 changes: 2 additions & 1 deletion src/state/program_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use super::discriminator::{AccountDiscriminator, AccountWithDiscriminator};
#[derive(BorshSerialize, BorshDeserialize, Default, Debug)]
pub struct ProgramConfig {
pub approved_validators: BTreeSet<Pubkey>,
pub fees_receiver: Pubkey,
}

impl AccountWithDiscriminator for ProgramConfig {
Expand All @@ -19,7 +20,7 @@ impl AccountWithDiscriminator for ProgramConfig {

impl ProgramConfig {
pub fn size_with_discriminator(&self) -> usize {
8 + 4 + 32 * self.approved_validators.len()
8 + 4 + 32 * self.approved_validators.len() + 32
}
}

Expand Down
3 changes: 2 additions & 1 deletion tests/fixtures/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,10 @@ pub fn get_commit_record_account_data(authority: Pubkey) -> Vec<u8> {
}

#[allow(dead_code)]
pub fn create_program_config_data(approved_validator: Pubkey) -> Vec<u8> {
pub fn create_program_config_data(approved_validator: Pubkey, fees_receiver: Pubkey) -> Vec<u8> {
let mut program_config = ProgramConfig {
approved_validators: Default::default(),
fees_receiver,
};
program_config
.approved_validators
Expand Down
Loading