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
152
153
154
155
156
157
158
159
160
161
162
163
164
use {
    crate::state::*,
    anchor_lang::prelude::*,
    hpl_utils::{reallocate, Default},
    spl_account_compression::Noop,
};

#[derive(Accounts)]
pub struct CreateDelegateAuthority<'info> {
    /// The project account.
    #[account(mut)]
    pub project: Account<'info, Project>,

    /// The delegate authority PDA containing info about permissions
    #[account(
      init, payer = payer,
      space = DelegateAuthority::LEN,
      seeds = [b"delegate_authority".as_ref(), project.key().as_ref(), authority.key().as_ref(), delegate.key().as_ref()],
      bump
    )]
    pub delegate_authority: Account<'info, DelegateAuthority>,

    /// The wallet receiving delegate authority.
    /// CHECK: This is not dangerous
    pub delegate: AccountInfo<'info>,

    /// The authority of the project.
    pub authority: Signer<'info>,

    /// The wallet that pays for the rent.
    #[account(mut)]
    pub payer: Signer<'info>,

    /// NATIVE RENT SYSVAR
    pub rent_sysvar: Sysvar<'info, Rent>,

    /// The system program.
    pub system_program: Program<'info, System>,

    /// NO OP program
    pub log_wrapper: Program<'info, Noop>,

    /// NATIVE SYSVAR CLOCK
    pub clock: Sysvar<'info, Clock>,

    /// The vault that collects the fees.
    /// CHECK: This is not dangerous
    #[account(mut)]
    pub vault: AccountInfo<'info>,
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct CreateDelegateAuthorityArgs {
    pub delegations: Option<Vec<ServiceDelegation>>,
}

pub fn create_delegate_authority(
    ctx: Context<CreateDelegateAuthority>,
    args: CreateDelegateAuthorityArgs,
) -> Result<()> {
    let delegate_authority = &mut ctx.accounts.delegate_authority;
    delegate_authority.set_defaults();
    delegate_authority.bump = ctx.bumps["delegate_authority"];
    delegate_authority.project = ctx.accounts.project.key();
    delegate_authority.authority = ctx.accounts.delegate.key();

    if let Some(delegations) = args.delegations {
        if delegations.len() > 0 {
            reallocate(
                delegations.len() as isize * ServiceDelegation::LEN as isize,
                delegate_authority.to_account_info(),
                ctx.accounts.payer.to_account_info(),
                &ctx.accounts.rent_sysvar,
                &ctx.accounts.system_program,
            )?;
            delegate_authority.delegations = delegations;
        }
    }

    Event::new_delegate_authority(
        delegate_authority.key(),
        &delegate_authority,
        &ctx.accounts.clock,
    )
    .wrap(ctx.accounts.log_wrapper.to_account_info())?;

    Ok(())
}

#[derive(Accounts)]
pub struct ModifyDelegate<'info> {
    /// The project account.
    #[account(mut)]
    pub project: Account<'info, Project>,

    /// The delegate authority PDA containing info about permissions
    #[account(mut)]
    pub delegate_authority: Account<'info, DelegateAuthority>,

    /// The authority of the project.
    pub authority: Signer<'info>,

    /// The wallet that pays for the rent.
    #[account(mut)]
    pub payer: Signer<'info>,

    /// NATIVE RENT SYSVAR
    pub rent_sysvar: Sysvar<'info, Rent>,

    /// The system program.
    pub system_program: Program<'info, System>,

    /// NO OP program
    pub log_wrapper: Program<'info, Noop>,

    /// NATIVE SYSVAR CLOCK
    pub clock: Sysvar<'info, Clock>,

    /// The vault that collects the fees.
    /// CHECK: This is not dangerous because we don't read or write from this account
    #[account(mut)]
    pub vault: AccountInfo<'info>,
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct AddRemoveDelegationArgs {
    pub delegation: Option<ServiceDelegation>,
    pub index: Option<u8>,
}

pub fn add_remove_delegation(
    ctx: Context<ModifyDelegate>,
    args: AddRemoveDelegationArgs,
) -> Result<()> {
    let delegate_authority = &mut ctx.accounts.delegate_authority;
    if let Some(service) = args.delegation {
        delegate_authority.delegations.push(service);
        reallocate(
            ServiceDelegation::LEN as isize,
            delegate_authority.to_account_info(),
            ctx.accounts.payer.to_account_info(),
            &ctx.accounts.rent_sysvar,
            &ctx.accounts.system_program,
        )?;
    } else if let Some(index) = args.index {
        delegate_authority.delegations.remove(index as usize);
        reallocate(
            ServiceDelegation::LEN as isize * -1,
            delegate_authority.to_account_info(),
            ctx.accounts.payer.to_account_info(),
            &ctx.accounts.rent_sysvar,
            &ctx.accounts.system_program,
        )?;
    }

    Event::update_delegate_authority(
        delegate_authority.key(),
        &delegate_authority,
        &ctx.accounts.clock,
    )
    .wrap(ctx.accounts.log_wrapper.to_account_info())?;

    Ok(())
}