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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
use crate::constants::*;
use crate::errors::ErrorCodes;
use crate::instructions::{initialize_account::{ShadowDriveStorageAccount, StorageAccount, StorageAccountV2}, initialize_config::StorageConfig};
use anchor_lang::prelude::*;
use anchor_spl::token::Mint;
use std::convert::TryInto;

/// This is the function that handles the `request_delete_account` ix
pub fn handler(mut ctx: impl RequestDeleteAccount) -> Result<()> {
    // Cannot request to delete storage account if immutable
    require!(
        !ctx.check_immutable(),
        ErrorCodes::StorageAccountMarkedImmutable
    );

    // Cannot flag for deletion when already flagged for deletion
    require!(
        !ctx.check_delete_flag(),
        ErrorCodes::AlreadyMarkedForDeletion
    );

    msg!(
        "Requesting to delete StorageAccount account: {}",
        ctx.get_identifier()
    );
    ctx.mark_delete();

    Ok(())
}

#[derive(Accounts)]
/// This `RequestDeleteAccount` context is used in the instruction which allows users to
/// mark an account for future deletion (by an admin).
pub struct RequestDeleteAccountV1<'info> {
    /// This is the `StorageConfig` accounts that holds all of the admin, uploader keys.
    #[account(
        seeds = [
            "storage-config".as_bytes()
        ],
        bump,
    )]
    pub storage_config: Box<Account<'info, StorageConfig>>,

    /// Parent storage account.
    #[account(
        mut,
        seeds = [
            "storage-account".as_bytes(),
            &storage_account.owner_1.key().to_bytes(),
            &storage_account.account_counter_seed.to_le_bytes()
        ],
        bump,
    )]
    pub storage_account: Box<Account<'info, StorageAccount>>,

    /// File owner, user, fee-payer
    /// Requires mutability since owner/user is fee payer.
    #[account(mut, constraint=storage_account.is_owner(owner.key()))]
    pub owner: Signer<'info>,

    /// Token mint account
    #[account(address = shdw::ID)]
    pub token_mint: Account<'info, Mint>,

    /// System Program
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
/// This `RequestDeleteAccount` context is used in the instruction which allows users to
/// mark an account for future deletion (by an admin).
pub struct RequestDeleteAccountV2<'info> {
    /// This is the `StorageConfig` accounts that holds all of the admin, uploader keys.
    #[account(
        seeds = [
            "storage-config".as_bytes()
        ],
        bump,
    )]
    pub storage_config: Box<Account<'info, StorageConfig>>,

    /// Parent storage account.
    #[account(
        mut,
        seeds = [
            "storage-account".as_bytes(),
            &storage_account.owner_1.key().to_bytes(),
            &storage_account.account_counter_seed.to_le_bytes()
        ],
        bump,
    )]
    pub storage_account: Box<Account<'info, StorageAccountV2>>,

    /// File owner, user, fee-payer
    /// Requires mutability since owner/user is fee payer.
    #[account(mut, constraint=storage_account.is_owner(owner.key()))]
    pub owner: Signer<'info>,

    /// Token mint account
    #[account(address = shdw::ID)]
    pub token_mint: Account<'info, Mint>,

    /// System Program
    pub system_program: Program<'info, System>,
}

pub trait RequestDeleteAccount {
    fn check_immutable(&self) -> bool;
    fn check_delete_flag(&self) -> bool;
    fn get_identifier(&self) -> String;
    fn mark_delete(&mut self);
}

impl RequestDeleteAccount for Context<'_,'_,'_,'_, RequestDeleteAccountV1<'_>> {
    fn check_immutable(&self) -> bool {
        self.accounts.storage_account.check_immutable()
    }
    fn check_delete_flag(&self) -> bool {
        self.accounts.storage_account.to_be_deleted
    }
    fn get_identifier(&self) -> String {
        self.accounts.storage_account.get_identifier()
    }
    fn mark_delete(&mut self) {
        let storage_account = &mut self.accounts.storage_account;

        // Update deletion flag and record request time
        storage_account.to_be_deleted = true;
        storage_account.delete_request_epoch = Clock::get().unwrap().epoch.try_into().unwrap();
    }
}


impl RequestDeleteAccount for Context<'_,'_,'_,'_, RequestDeleteAccountV2<'_>> {
    fn check_immutable(&self) -> bool {
        self.accounts.storage_account.check_immutable()
    }
    fn check_delete_flag(&self) -> bool {
        self.accounts.storage_account.to_be_deleted
    }
    fn get_identifier(&self) -> String {
        self.accounts.storage_account.get_identifier()
    }
    fn mark_delete(&mut self) {
        let storage_account = &mut self.accounts.storage_account;

        // Update deletion flag and record request time
        storage_account.to_be_deleted = true;
        storage_account.delete_request_epoch = Clock::get().unwrap().epoch.try_into().unwrap();
    }
}