gmsol_store/instructions/
roles.rs

1use anchor_lang::prelude::*;
2
3use crate::{states::Store, utils::internal};
4
5/// The accounts definition for [`check_admin`](crate::gmsol_store::check_admin)
6/// and [`check_role`](crate::gmsol_store::check_role).
7#[derive(Accounts)]
8pub struct CheckRole<'info> {
9    /// The address to check for the role.
10    pub authority: Signer<'info>,
11    /// The store account in which the role is defined.
12    pub store: AccountLoader<'info, Store>,
13}
14
15/// Verify that the `user` is an admin of the given `store`.
16pub(crate) fn check_admin(ctx: Context<CheckRole>) -> Result<bool> {
17    ctx.accounts
18        .store
19        .load()?
20        .has_admin_role(ctx.accounts.authority.key)
21}
22
23/// Verify that the `authority` has the given role in the given `store`.
24pub(crate) fn check_role(ctx: Context<CheckRole>, role: String) -> Result<bool> {
25    ctx.accounts
26        .store
27        .load()?
28        .has_role(ctx.accounts.authority.key, &role)
29}
30
31/// The accounts definition for [`has_admin`](crate::gmsol_store::has_admin)
32/// and [`has_role`](crate::gmsol_store::has_role).
33#[derive(Accounts)]
34pub struct HasRole<'info> {
35    /// The store account in which the role is defined.
36    pub store: AccountLoader<'info, Store>,
37}
38
39/// Verify that the `user` is an admin of the given `store` without signing.
40pub fn has_admin(ctx: Context<HasRole>, authority: Pubkey) -> Result<bool> {
41    ctx.accounts.store.load()?.has_admin_role(&authority)
42}
43
44/// Verify that the `authority` has the given role in the given `store` without signing.
45pub fn has_role(ctx: Context<HasRole>, authority: Pubkey, role: String) -> Result<bool> {
46    ctx.accounts.store.load()?.has_role(&authority, &role)
47}
48
49/// The accounts definition for [`enable_role`](crate::gmsol_store::enable_role).
50///
51/// *[See also the documentation for the instruction.](crate::gmsol_store::enable_role).*
52#[derive(Accounts)]
53pub struct EnableRole<'info> {
54    /// The caller of this instruction.
55    pub authority: Signer<'info>,
56    /// The store account for which the role is to be added/enabled.
57    #[account(mut)]
58    pub store: AccountLoader<'info, Store>,
59}
60
61/// Enable the given role in the data store.
62///
63/// # CHECK
64/// - This instruction can only be called by the `ADMIN`.
65pub(crate) fn unchecked_enable_role(ctx: Context<EnableRole>, role: String) -> Result<()> {
66    ctx.accounts.store.load_mut()?.enable_role(&role)
67}
68
69impl<'info> internal::Authentication<'info> for EnableRole<'info> {
70    fn authority(&self) -> &Signer<'info> {
71        &self.authority
72    }
73
74    fn store(&self) -> &AccountLoader<'info, Store> {
75        &self.store
76    }
77}
78
79/// The accounts definition for [`disable_role`](crate::gmsol_store::disable_role).
80///
81/// *[See also the documentation for the instruction.](crate::gmsol_store::disable_role).*
82#[derive(Accounts)]
83pub struct DisableRole<'info> {
84    /// The caller of this instruction.
85    pub authority: Signer<'info>,
86    /// The store account for which the role is to be disabled.
87    #[account(mut)]
88    pub store: AccountLoader<'info, Store>,
89}
90
91/// Disable the given role in the data store.
92///
93/// # CHECK
94/// - This instruction can only be called by the `ADMIN`.
95pub fn unchecked_disable_role(ctx: Context<DisableRole>, role: String) -> Result<()> {
96    ctx.accounts.store.load_mut()?.disable_role(&role)
97}
98
99impl<'info> internal::Authentication<'info> for DisableRole<'info> {
100    fn authority(&self) -> &Signer<'info> {
101        &self.authority
102    }
103
104    fn store(&self) -> &AccountLoader<'info, Store> {
105        &self.store
106    }
107}
108
109/// The accounts definition for [`grant_role`](crate::gmsol_store::grant_role).
110///
111/// *[See also the documentation for the instruction.](crate::gmsol_store::grant_role).*
112#[derive(Accounts)]
113pub struct GrantRole<'info> {
114    /// The caller of this instruction.
115    pub authority: Signer<'info>,
116    #[account(mut)]
117    /// The store account to which the new role is to be granted.
118    pub store: AccountLoader<'info, Store>,
119}
120
121/// Grant a role to the user.
122///
123/// # CHECK
124/// - This instruction can only be called by the `ADMIN`.
125pub(crate) fn unchecked_grant_role(
126    ctx: Context<GrantRole>,
127    user: Pubkey,
128    role: String,
129) -> Result<()> {
130    ctx.accounts.store.load_mut()?.grant(&user, &role)
131}
132
133impl<'info> internal::Authentication<'info> for GrantRole<'info> {
134    fn authority(&self) -> &Signer<'info> {
135        &self.authority
136    }
137
138    fn store(&self) -> &AccountLoader<'info, Store> {
139        &self.store
140    }
141}
142
143/// The accounts definition for [`revoke_role`](crate::gmsol_store::revoke_role).
144///
145/// *[See also the documentation for the instruction.](crate::gmsol_store::revoke_role).*
146#[derive(Accounts)]
147pub struct RevokeRole<'info> {
148    /// The caller of this instruction.
149    pub authority: Signer<'info>,
150    /// The store account from which the new role is to be revoked.
151    #[account(mut)]
152    pub store: AccountLoader<'info, Store>,
153}
154
155/// Revoke a role to the user.
156///
157/// # CHECK
158/// - This instruction can only be called by the `ADMIN`.
159pub(crate) fn unchecked_revoke_role(
160    ctx: Context<RevokeRole>,
161    user: Pubkey,
162    role: String,
163) -> Result<()> {
164    ctx.accounts.store.load_mut()?.revoke(&user, &role)
165}
166
167impl<'info> internal::Authentication<'info> for RevokeRole<'info> {
168    fn authority(&self) -> &Signer<'info> {
169        &self.authority
170    }
171
172    fn store(&self) -> &AccountLoader<'info, Store> {
173        &self.store
174    }
175}