1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//! # Inbox Instructions
//!
//! This module contains instructions related to managing the inbox.

use anchor_lang::prelude::*;
use crate::state::*;
use crate::constants::*;

/// Initializes a new inbox.
pub fn initialize(ctx: Context<InitializeInbox>) -> Result<()> {
    let inbox = &mut ctx.accounts.inbox;
    inbox.admin = *ctx.accounts.admin.key;
    // dev: these seem to not be needed, fields are 0-initialized by default
    // inbox.latest_free_slot = 0;
    // inbox.latest_whitelisted_slot = 0;

    msg!("Inbox initialized with admin: {:?}", inbox.admin);

    Ok(())
}

/// Changes the admin of the inbox.
pub fn change_admin(ctx: Context<ChangeAdmin>, new_admin: Pubkey) -> Result<()> {
    let inbox = &mut ctx.accounts.inbox;
    inbox.admin = new_admin;

    msg!("Inbox admin changed to: {:?}", inbox.admin);

    Ok(())
}

/// Withdraws surplus balance from the inbox.
pub fn withdraw_surplus_inbox_balance(ctx: Context<WithdrawSurplusInboxBalance>) -> Result<()> {
    let inbox = &ctx.accounts.inbox;
    let admin = &ctx.accounts.admin;

    let rent = Rent::get()?;
    let minimum_balance = rent.minimum_balance(inbox.to_account_info().data_len());
    let surplus = inbox.to_account_info().lamports().saturating_sub(minimum_balance);

    **inbox.to_account_info().try_borrow_mut_lamports()? -= surplus;
    **admin.to_account_info().try_borrow_mut_lamports()? += surplus;

    msg!("Surplus of {:?} lamports withdrawn from inbox", surplus);
    Ok(())
}

/// Accounts required for initializing an inbox.
#[derive(Accounts)]
pub struct InitializeInbox<'info> {
    #[account(
        init,
        seeds=[INBOX_SEED],
        bump,
        payer = admin,
        space = INBOX_SPACE
    )]
    pub inbox: Account<'info, Inbox>,
    #[account(mut)]
    pub admin: Signer<'info>,
    pub system_program: Program<'info, System>,
}

/// Accounts required for changing the admin of an inbox.
#[derive(Accounts)]
pub struct ChangeAdmin<'info> {
    #[account(mut, seeds=[INBOX_SEED], bump, has_one = admin)]
    pub inbox: Account<'info, Inbox>,
    pub admin: Signer<'info>,
}

/// Accounts required for withdrawing surplus balance from an inbox.
#[derive(Accounts)]
pub struct WithdrawSurplusInboxBalance<'info> {
    #[account(mut, has_one = admin)]
    pub inbox: Account<'info, Inbox>,
    #[account(mut)]
    pub admin: Signer<'info>,
}