Skip to content

Commit ff2c875

Browse files
authored
[solana] Add close_vesting_balance instruction (#242)
* Add `close_vesting_balance` ix * Add rent_payer to `VestingBalance` for rent reclaim on close * Add total_vesting_balance == 0 constraint * Only set new `rent_payer` if not initialized already * Make rent_payer signer and remove unused mut * Remove unused `globalConfig * Add vesting test cases
1 parent 0e9cfeb commit ff2c875

File tree

7 files changed

+354
-166
lines changed

7 files changed

+354
-166
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use crate::context::{VESTING_BALANCE_SEED, VESTING_CONFIG_SEED};
2+
use crate::error::VestingError;
3+
use crate::state::{VestingBalance, VestingConfig};
4+
use anchor_lang::prelude::*;
5+
use anchor_spl::associated_token::AssociatedToken;
6+
use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};
7+
8+
#[derive(Accounts)]
9+
#[instruction()]
10+
pub struct CloseVestingBalance<'info> {
11+
#[account(mut)]
12+
/// CHECK: This account is the original rent_payer for the vesting_balance account
13+
rent_payer: Signer<'info>,
14+
mint: InterfaceAccount<'info, Mint>,
15+
#[account(
16+
seeds = [VESTING_CONFIG_SEED.as_bytes(), mint.key().as_ref(), config.seed.to_le_bytes().as_ref()],
17+
bump = config.bump
18+
)]
19+
config: Account<'info, VestingConfig>,
20+
#[account(
21+
mut,
22+
has_one = rent_payer,
23+
constraint = vesting_balance.total_vesting_balance == 0 @ VestingError::NotFullyVested,
24+
seeds = [VESTING_BALANCE_SEED.as_bytes(), config.key().as_ref(), vester_ta.owner.key().as_ref()],
25+
bump,
26+
close = rent_payer,
27+
)]
28+
vesting_balance: Account<'info, VestingBalance>,
29+
#[account(
30+
associated_token::mint = mint,
31+
associated_token::authority = vester_ta.owner,
32+
associated_token::token_program = token_program
33+
)]
34+
vester_ta: InterfaceAccount<'info, TokenAccount>,
35+
associated_token_program: Program<'info, AssociatedToken>,
36+
token_program: Interface<'info, TokenInterface>,
37+
system_program: Program<'info, System>,
38+
}
39+
40+
impl<'info> CloseVestingBalance<'info> {
41+
pub fn close_vesting_balance(&mut self) -> Result<()> {
42+
Ok(())
43+
}
44+
}

solana/programs/staking/src/contexts/create_vesting_balance.rs

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ impl<'info> CreateVestingBalance<'info> {
5353
stake_account_metadata: Pubkey::default(),
5454
total_vesting_balance: 0,
5555
bump,
56+
rent_payer: self.admin.key(),
5657
});
5758

5859
Ok(())

solana/programs/staking/src/contexts/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ pub use cancel_vesting::*;
1515

1616
pub mod withdraw_surplus;
1717
pub use withdraw_surplus::*;
18+
mod close_vesting_balance;
1819
mod create_vesting_balance;
1920

21+
pub use close_vesting_balance::*;
2022
pub use create_vesting_balance::*;
2123

2224
pub mod transfer_vesting;

solana/programs/staking/src/contexts/transfer_vesting.rs

+5
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,11 @@ impl<'info> crate::contexts::TransferVesting<'info> {
319319
.checked_add(self.vest.amount)
320320
.ok_or(VestingError::Overflow)?,
321321
bump: new_vesting_balance_bump,
322+
rent_payer: if self.new_vesting_balance.rent_payer == Pubkey::default() {
323+
self.vester.key()
324+
} else {
325+
self.new_vesting_balance.rent_payer
326+
},
322327
});
323328

324329
self.vesting_balance.total_vesting_balance = self

solana/programs/staking/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,11 @@ pub mod staking {
704704
.create_vesting_balance(ctx.bumps.vesting_balance)
705705
}
706706

707+
// Closes a vesting balance account
708+
pub fn close_vesting_balance(ctx: Context<CloseVestingBalance>) -> Result<()> {
709+
ctx.accounts.close_vesting_balance()
710+
}
711+
707712
// Finalize a Config, disabling any further creation or cancellation of Vesting accounts
708713
pub fn finalize_vesting_config(ctx: Context<Finalize>) -> Result<()> {
709714
ctx.accounts.finalize()

solana/programs/staking/src/state/vesting_balance.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub struct VestingBalance {
99
pub total_vesting_balance: u64,
1010
pub bump: u8,
1111
pub stake_account_metadata: Pubkey,
12+
pub rent_payer: Pubkey,
1213
}
1314

1415
impl VestingBalance {
@@ -21,6 +22,6 @@ pub mod tests {
2122

2223
#[test]
2324
fn check_size() {
24-
assert!(VestingBalance::LEN == 8 + 32 + 8 + 1 + 32); // 81
25+
assert!(VestingBalance::LEN == 8 + 32 + 8 + 1 + 32 + 32); // 113
2526
}
2627
}

0 commit comments

Comments
 (0)