Skip to content

Commit 7fc0ae9

Browse files
feat: Add close validator vault (#71)
* feat: Add close validator vault * chore: Refactor
1 parent 0090ebc commit 7fc0ae9

File tree

7 files changed

+165
-0
lines changed

7 files changed

+165
-0
lines changed

src/discriminator.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ pub enum DlpDiscriminator {
3131
ProtocolClaimFees = 12,
3232
/// See [crate::processor::process_commit_state_from_buffer] for docs.
3333
CommitStateFromBuffer = 13,
34+
/// See [crate::processor::process_close_validator_fees_vault] for docs.
35+
CloseValidatorFeesVault = 14,
3436
}
3537

3638
impl DlpDiscriminator {
@@ -57,6 +59,7 @@ impl TryFrom<[u8; 8]> for DlpDiscriminator {
5759
0xb => Ok(DlpDiscriminator::CloseEphemeralBalance),
5860
0xc => Ok(DlpDiscriminator::ProtocolClaimFees),
5961
0xd => Ok(DlpDiscriminator::CommitStateFromBuffer),
62+
0xe => Ok(DlpDiscriminator::CloseValidatorFeesVault),
6063
_ => Err(ProgramError::InvalidInstructionData),
6164
}
6265
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use solana_program::instruction::Instruction;
2+
use solana_program::{instruction::AccountMeta, pubkey::Pubkey};
3+
4+
use crate::discriminator::DlpDiscriminator;
5+
use crate::pda::validator_fees_vault_pda_from_validator;
6+
7+
/// Close a validator fees vault PDA.
8+
/// See [crate::processor::process_close_validator_fees_vault] for docs.
9+
pub fn close_validator_fees_vault(
10+
payer: Pubkey,
11+
admin: Pubkey,
12+
validator_identity: Pubkey,
13+
) -> Instruction {
14+
let validator_fees_vault_pda = validator_fees_vault_pda_from_validator(&validator_identity);
15+
Instruction {
16+
program_id: crate::id(),
17+
accounts: vec![
18+
AccountMeta::new(payer, true),
19+
AccountMeta::new(admin, true),
20+
AccountMeta::new(validator_identity, false),
21+
AccountMeta::new(validator_fees_vault_pda, false),
22+
],
23+
data: DlpDiscriminator::CloseValidatorFeesVault.to_vec(),
24+
}
25+
}

src/instruction_builder/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
mod close_ephemeral_balance;
22
mod commit_state;
33

4+
mod close_validator_fees_vault;
45
mod commit_state_from_buffer;
56
mod delegate;
67
mod delegate_ephemeral_balance;
@@ -14,6 +15,7 @@ mod validator_claim_fees;
1415
mod whitelist_validator_for_program;
1516

1617
pub use close_ephemeral_balance::*;
18+
pub use close_validator_fees_vault::*;
1719
pub use commit_state::*;
1820
pub use commit_state_from_buffer::*;
1921
pub use delegate::*;

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ pub fn process_instruction(
9090
discriminator::DlpDiscriminator::ProtocolClaimFees => {
9191
processor::process_protocol_claim_fees(program_id, accounts, data)?
9292
}
93+
discriminator::DlpDiscriminator::CloseValidatorFeesVault => {
94+
processor::process_close_validator_fees_vault(program_id, accounts, data)?
95+
}
9396
}
9497
Ok(())
9598
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use solana_program::msg;
2+
use solana_program::program_error::ProgramError;
3+
use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};
4+
5+
use crate::consts::ADMIN_PUBKEY;
6+
use crate::error::DlpError::Unauthorized;
7+
use crate::processor::utils::loaders::{load_initialized_pda, load_signer};
8+
use crate::processor::utils::pda::close_pda;
9+
use crate::validator_fees_vault_seeds_from_validator;
10+
11+
/// Process the close of the validator fees vault
12+
///
13+
/// Accounts:
14+
///
15+
/// 0; `[signer]` payer
16+
/// 1; `[signer]` admin that controls the vault
17+
/// 2; `[]` validator_identity
18+
/// 3; `[]` validator_fees_vault_pda
19+
///
20+
/// Requirements:
21+
///
22+
/// - validator admin need to be signer since the existence of the validator fees vault
23+
/// is used as proof later that the validator is whitelisted
24+
/// - validator fees vault is closed
25+
///
26+
/// 1. Close the validator fees vault PDA
27+
pub fn process_close_validator_fees_vault(
28+
_program_id: &Pubkey,
29+
accounts: &[AccountInfo],
30+
_data: &[u8],
31+
) -> ProgramResult {
32+
// Load Accounts
33+
let [payer, admin, validator_identity, validator_fees_vault] = accounts else {
34+
return Err(ProgramError::NotEnoughAccountKeys);
35+
};
36+
37+
// Check if the payer and admin are signers
38+
load_signer(payer, "payer")?;
39+
load_signer(admin, "admin")?;
40+
41+
// Check if the admin is the correct one
42+
if !admin.key.eq(&ADMIN_PUBKEY) {
43+
msg!(
44+
"Expected admin pubkey: {} but got {}",
45+
ADMIN_PUBKEY,
46+
admin.key
47+
);
48+
return Err(Unauthorized.into());
49+
}
50+
51+
load_initialized_pda(
52+
validator_fees_vault,
53+
validator_fees_vault_seeds_from_validator!(validator_identity.key),
54+
&crate::id(),
55+
true,
56+
"validator fees vault",
57+
)?;
58+
59+
// Close the fees vault PDA
60+
close_pda(validator_fees_vault, validator_identity)?;
61+
62+
Ok(())
63+
}

src/processor/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod close_ephemeral_balance;
2+
mod close_validator_fees_vault;
23
mod commit_state;
34
mod commit_state_from_buffer;
45
mod delegate;
@@ -14,6 +15,7 @@ mod validator_claim_fees;
1415
mod whitelist_validator_for_program;
1516

1617
pub use close_ephemeral_balance::*;
18+
pub use close_validator_fees_vault::*;
1719
pub use commit_state::*;
1820
pub use commit_state_from_buffer::*;
1921
pub use delegate::*;
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use crate::fixtures::TEST_AUTHORITY;
2+
use dlp::pda::validator_fees_vault_pda_from_validator;
3+
use solana_program::{hash::Hash, native_token::LAMPORTS_PER_SOL, system_program};
4+
use solana_program_test::{processor, BanksClient, ProgramTest};
5+
use solana_sdk::{
6+
account::Account,
7+
signature::{Keypair, Signer},
8+
transaction::Transaction,
9+
};
10+
11+
mod fixtures;
12+
13+
#[tokio::test]
14+
async fn test_close_validator_fees_vault() {
15+
// Setup
16+
let (banks, admin, validator, blockhash) = setup_program_test_env().await;
17+
18+
let validator_fees_vault_pda = validator_fees_vault_pda_from_validator(&validator.pubkey());
19+
20+
// Submit the close vault tx
21+
let ix = dlp::instruction_builder::close_validator_fees_vault(
22+
admin.pubkey(),
23+
admin.pubkey(),
24+
validator.pubkey(),
25+
);
26+
let tx = Transaction::new_signed_with_payer(&[ix], Some(&admin.pubkey()), &[&admin], blockhash);
27+
let res = banks.process_transaction(tx).await;
28+
assert!(res.is_ok());
29+
30+
// Assert the validator fees vault now has been closed
31+
let validator_fees_vault_account = banks.get_account(validator_fees_vault_pda).await.unwrap();
32+
assert!(validator_fees_vault_account.is_none());
33+
}
34+
35+
async fn setup_program_test_env() -> (BanksClient, Keypair, Keypair, Hash) {
36+
let mut program_test = ProgramTest::new("dlp", dlp::ID, processor!(dlp::process_instruction));
37+
program_test.prefer_bpf(true);
38+
39+
let admin_keypair = Keypair::from_bytes(&TEST_AUTHORITY).unwrap();
40+
let validator = Keypair::new();
41+
42+
program_test.add_account(
43+
admin_keypair.pubkey(),
44+
Account {
45+
lamports: LAMPORTS_PER_SOL,
46+
data: vec![],
47+
owner: system_program::id(),
48+
executable: false,
49+
rent_epoch: 0,
50+
},
51+
);
52+
53+
// Setup the validator fees vault
54+
program_test.add_account(
55+
validator_fees_vault_pda_from_validator(&validator.pubkey()),
56+
Account {
57+
lamports: LAMPORTS_PER_SOL,
58+
data: vec![],
59+
owner: dlp::id(),
60+
executable: false,
61+
rent_epoch: 0,
62+
},
63+
);
64+
65+
let (banks, _, blockhash) = program_test.start().await;
66+
(banks, admin_keypair, validator, blockhash)
67+
}

0 commit comments

Comments
 (0)