sol_cerberus/instructions/
assign_role.rs

1use crate::instructions::allowed::{allowed, AllowedRule};
2use crate::metadata_program;
3use crate::state::app::{App, Seed};
4use crate::state::role::*;
5use crate::state::rule::{Namespaces, Rule};
6use crate::utils::{roles::address_or_wildcard, rules::*, utc_now};
7use crate::Errors::InvalidRole;
8use anchor_lang::prelude::*;
9use anchor_spl::{metadata::MetadataAccount, token::TokenAccount};
10
11// SPACE SIZE:
12// + 8 discriminator
13// + 32 app_id (Pubkey)
14// + 1 + 32 address Option<Pubkey>
15// + 4 + 16 role (string)
16// + 1 + 1 address_type
17// + 1 + 8 expires_at Option<i64>
18// + 1 bump
19// total = 8 + 32 + 1 + 32 + 4 + 16 + 1 + 1 +  1 + 8 + 1 = 105
20#[derive(Accounts)]
21#[instruction(assign_role_data:AssignRoleData)]
22pub struct AssignRole<'info> {
23    #[account(mut)]
24    pub signer: Signer<'info>,
25    #[account(
26        init,
27        payer = signer,
28        space = 105,
29        seeds = [assign_role_data.role.as_ref(), address_or_wildcard(&assign_role_data.address), sol_cerberus_app.id.key().as_ref()],
30        constraint = valid_rule(&assign_role_data.role, true)  @ InvalidRole,
31        bump
32    )]
33    pub role: Account<'info, Role>,
34    #[account(
35        seeds = [b"app".as_ref(), sol_cerberus_app.id.key().as_ref()],
36        bump = sol_cerberus_app.bump,
37    )]
38    pub sol_cerberus_app: Box<Account<'info, App>>,
39    #[account(
40        seeds = [sol_cerberus_role.role.as_ref(),  address_or_wildcard(&sol_cerberus_role.address), sol_cerberus_role.app_id.key().as_ref()],
41        bump = sol_cerberus_role.bump
42    )]
43    pub sol_cerberus_role: Option<Box<Account<'info, Role>>>,
44    #[account(
45        seeds = [sol_cerberus_rule.namespace.to_le_bytes().as_ref(), sol_cerberus_rule.role.as_ref(), sol_cerberus_rule.resource.as_ref(), sol_cerberus_rule.permission.as_ref(), sol_cerberus_rule.app_id.key().as_ref()],
46        bump = sol_cerberus_rule.bump,
47    )]
48    pub sol_cerberus_rule: Option<Box<Account<'info, Rule>>>,
49    #[account()]
50    pub sol_cerberus_token: Option<Box<Account<'info, TokenAccount>>>,
51    #[account(
52        seeds = [b"metadata", metadata_program::ID.as_ref(), sol_cerberus_metadata.mint.key().as_ref()],
53        seeds::program = metadata_program::ID,
54        bump,
55    )]
56    pub sol_cerberus_metadata: Option<Box<Account<'info, MetadataAccount>>>,
57    #[account(
58        init_if_needed,
59        payer = signer,
60        space = 9, // Account discriminator + initialized
61        seeds = [b"seed".as_ref(), signer.key.as_ref()],
62        bump
63    )]
64    pub sol_cerberus_seed: Option<Account<'info, Seed>>,
65    pub system_program: Program<'info, System>,
66}
67
68pub fn assign_role(ctx: Context<AssignRole>, assign_role_data: AssignRoleData) -> Result<()> {
69    allowed(
70        &ctx.accounts.signer,
71        &ctx.accounts.sol_cerberus_app,
72        &ctx.accounts.sol_cerberus_role,
73        &ctx.accounts.sol_cerberus_rule,
74        &ctx.accounts.sol_cerberus_token,
75        &ctx.accounts.sol_cerberus_metadata,
76        &mut ctx.accounts.sol_cerberus_seed,
77        &ctx.accounts.system_program,
78        AllowedRule {
79            app_id: ctx.accounts.sol_cerberus_app.id.key(),
80            namespace: Namespaces::AssignRole as u8,
81            resource: assign_role_data.address_type.to_string(),
82            permission: assign_role_data.role.clone(),
83        },
84    )?;
85
86    let role = &mut ctx.accounts.role;
87    role.bump = ctx.bumps.role;
88    role.app_id = ctx.accounts.sol_cerberus_app.id;
89    role.address = assign_role_data.address;
90    role.role = assign_role_data.role;
91    role.address_type = assign_role_data.address_type;
92    role.expires_at = assign_role_data.expires_at;
93    emit!(RolesChanged {
94        time: utc_now(),
95        app_id: ctx.accounts.sol_cerberus_app.id,
96    });
97    Ok(())
98}