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
use {
    crate::state::*,
    anchor_lang::prelude::*,
    hpl_utils::{reallocate, Default},
};

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

    /// The collection to add
    #[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 authority of the project.
    /// CHECK: This is not dangerous because we don't read or write from this account
    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>,

    /// 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 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;
        }
    }

    Ok(())
}

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

    /// The collection to add
    #[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>,

    /// 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,
        )?;
    }
    Ok(())
}