Skip to main content

sss_token/instructions/
allowlist_add.rs

1use anchor_lang::prelude::*;
2
3use crate::errors::SssError;
4use crate::events::AllowlistAdded;
5use crate::state::*;
6use crate::utils::require_role;
7
8#[derive(AnchorSerialize, AnchorDeserialize)]
9pub struct AllowlistAddParams {
10    pub reason: String,
11}
12
13#[derive(Accounts)]
14#[instruction(_params: AllowlistAddParams)]
15pub struct AllowlistAdd<'info> {
16    #[account(mut)]
17    pub authority: Signer<'info>,
18
19    #[account(
20        mut,
21        seeds = [StablecoinConfig::SEED_PREFIX, config.mint.as_ref()],
22        bump = config.bump,
23    )]
24    pub config: Account<'info, StablecoinConfig>,
25
26    #[account(
27        seeds = [RoleRegistry::SEED_PREFIX, config.key().as_ref()],
28        bump = role_registry.bump,
29        constraint = role_registry.config == config.key() @ SssError::InvalidAuthority,
30    )]
31    pub role_registry: Account<'info, RoleRegistry>,
32
33    #[account(
34        init_if_needed,
35        payer = authority,
36        space = AllowlistEntry::SPACE,
37        seeds = [AllowlistEntry::SEED_PREFIX, config.key().as_ref(), address_to_allowlist.key().as_ref()],
38        bump,
39        constraint = allowlist_entry.config == config.key() || allowlist_entry.config == Pubkey::default() @ SssError::InvalidAuthority,
40    )]
41    pub allowlist_entry: Account<'info, AllowlistEntry>,
42
43    /// CHECK: The address being allowlisted.
44    pub address_to_allowlist: UncheckedAccount<'info>,
45
46    pub system_program: Program<'info, System>,
47}
48
49pub fn handler(ctx: Context<AllowlistAdd>, params: AllowlistAddParams) -> Result<()> {
50    let config = &ctx.accounts.config;
51
52    require!(
53        config.enable_permanent_delegate,
54        SssError::BlacklistNotEnabled
55    );
56
57    require_role(
58        &ctx.accounts.role_registry,
59        &ctx.accounts.authority.key(),
60        Role::Blacklister,
61    )?;
62
63    require!(
64        params.reason.len() <= AllowlistEntry::MAX_REASON_LEN,
65        SssError::AllowlistReasonTooLong
66    );
67
68    let entry = &ctx.accounts.allowlist_entry;
69    require!(
70        entry.config == Pubkey::default(),
71        SssError::AllowlistEntryExists
72    );
73
74    let clock = Clock::get()?;
75
76    let entry = &mut ctx.accounts.allowlist_entry;
77    entry.bump = ctx.bumps.allowlist_entry;
78    entry.config = config.key();
79    entry.address = ctx.accounts.address_to_allowlist.key();
80    entry.added_by = ctx.accounts.authority.key();
81    entry.added_at = clock.unix_timestamp;
82    entry.reason = params.reason.clone();
83
84    emit!(AllowlistAdded {
85        config: config.key(),
86        address: ctx.accounts.address_to_allowlist.key(),
87        added_by: ctx.accounts.authority.key(),
88        reason: params.reason,
89        timestamp: clock.unix_timestamp,
90    });
91
92    let config = &mut ctx.accounts.config;
93    config.updated_at = clock.unix_timestamp;
94
95    Ok(())
96}