sol_cerberus/instructions/
add_rule.rs1use anchor_spl::{metadata::MetadataAccount, token::TokenAccount};
2use crate::instructions::allowed::{allowed, AllowedRule};
3use crate::utils::{valid_rules, utc_now, validate_ns_permission, roles::address_or_wildcard};
4use crate::state::role::Role;
5use anchor_lang::prelude::*;
6use crate::state::app::{App, Seed};
7use crate::state::rule::*;
8use crate::Errors;
9use crate::metadata_program;
10
11#[derive(Accounts)]
22#[instruction(rule_data:RuleData)]
23pub struct AddRule<'info> {
24 #[account(mut)]
25 pub signer: Signer<'info>,
26 #[account(
27 init,
28 payer = signer,
29 space = 111,
30 seeds = [rule_data.namespace.to_le_bytes().as_ref(), rule_data.role.as_ref(), rule_data.resource.as_ref(), rule_data.permission.as_ref(), sol_cerberus_app.id.key().as_ref()],
31 constraint = valid_rules(&rule_data.role, &rule_data.resource, &rule_data.permission) @ Errors::InvalidRule,
32 bump
33 )]
34 pub rule: Account<'info, Rule>,
35 #[account(
36 seeds = [b"app".as_ref(), sol_cerberus_app.id.key().as_ref()],
37 bump = sol_cerberus_app.bump,
38 )]
39 pub sol_cerberus_app: Box<Account<'info, App>>,
40 #[account(
41 seeds = [sol_cerberus_role.role.as_ref(), address_or_wildcard(&sol_cerberus_role.address), sol_cerberus_role.app_id.key().as_ref()],
42 bump = sol_cerberus_role.bump
43 )]
44 pub sol_cerberus_role: Option<Box<Account<'info, Role>>>,
45 #[account(
46 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()],
47 bump = sol_cerberus_rule.bump,
48 )]
49 pub sol_cerberus_rule: Option<Box<Account<'info, Rule>>>,
50 #[account(
51 seeds = [sol_cerberus_rule2.namespace.to_le_bytes().as_ref(), sol_cerberus_rule2.role.as_ref(), sol_cerberus_rule2.resource.as_ref(), sol_cerberus_rule2.permission.as_ref(), sol_cerberus_rule2.app_id.key().as_ref()],
52 bump = sol_cerberus_rule2.bump,
53 )]
54 pub sol_cerberus_rule2: Option<Box<Account<'info, Rule>>>,
55 #[account()]
56 pub sol_cerberus_token: Option<Box<Account<'info, TokenAccount>>>,
57 #[account(
58 seeds = [b"metadata", metadata_program::ID.as_ref(), sol_cerberus_metadata.mint.key().as_ref()],
59 seeds::program = metadata_program::ID,
60 bump,
61 )]
62 pub sol_cerberus_metadata: Option<Box<Account<'info, MetadataAccount>>>,
63 #[account(
64 init_if_needed,
65 payer = signer,
66 space = 9, seeds = [b"seed".as_ref(), signer.key.as_ref()],
68 bump
69 )]
70 pub sol_cerberus_seed: Option<Account<'info, Seed>>,
71 pub system_program: Program<'info, System>,
72}
73
74pub fn add_rule(
75 ctx: Context<AddRule>,
76 data:RuleData
77) -> Result<()> {
78 allowed(
80 &ctx.accounts.signer,
81 &ctx.accounts.sol_cerberus_app,
82 &ctx.accounts.sol_cerberus_role,
83 &ctx.accounts.sol_cerberus_rule,
84 &ctx.accounts.sol_cerberus_token,
85 &ctx.accounts.sol_cerberus_metadata,
86 &mut ctx.accounts.sol_cerberus_seed,
87 &ctx.accounts.system_program,
88 AllowedRule {
89 app_id: ctx.accounts.sol_cerberus_app.id.key(),
90 namespace: Namespaces::AddRuleNSRole as u8,
91 resource: data.namespace.to_string(),
92 permission: data.role.to_string(),
93 },
94 )?;
95 allowed(
97 &ctx.accounts.signer,
98 &ctx.accounts.sol_cerberus_app,
99 &ctx.accounts.sol_cerberus_role,
100 &ctx.accounts.sol_cerberus_rule2,
101 &ctx.accounts.sol_cerberus_token,
102 &ctx.accounts.sol_cerberus_metadata,
103 &mut ctx.accounts.sol_cerberus_seed,
104 &ctx.accounts.system_program,
105 AllowedRule {
106 app_id: ctx.accounts.sol_cerberus_app.id.key(),
107 namespace: Namespaces::AddRuleResourcePerm as u8,
108 resource: data.resource.to_string(),
109 permission: data.permission.to_string(),
110 },
111 )?;
112
113 if data.namespace >= Namespaces::AssignRole as u8 && data.namespace <= Namespaces::DeleteAssignRole as u8 {
115 if !matches!(data.resource.as_str(), "Wallet" | "Nft" | "Collection" | "*") {
116 return Err(error!(Errors::InvalidAddressType))
117 }
118 }
119
120 if data.namespace == Namespaces::AddRuleNSRole as u8 && data.namespace == Namespaces::DeleteRuleNSRole as u8 {
123 validate_ns_permission(&data.resource)?;
124 }
125
126 let rule = &mut ctx.accounts.rule;
128 rule.bump = ctx.bumps.rule;
129 rule.app_id = ctx.accounts.sol_cerberus_app.id;
130 rule.namespace = data.namespace;
131 rule.role = data.role;
132 rule.resource = data.resource;
133 rule.permission = data.permission;
134 rule.expires_at = data.expires_at;
135 emit!(RulesChanged {
136 time: utc_now(),
137 app_id: ctx.accounts.sol_cerberus_app.id,
138 });
139 Ok(())
140}