Access Control
This example shows how you can use the implementation of access-control to provide rights for usage of specific smart contract functions.
Step 1: Import default implementation
With default Cargo.toml
,
you need to import the access_control
module, enable the corresponding feature, and embed the module data structure
as described in that section.
The main trait is AccessControl
.
Step 2: Define constructor
Define constructor where you grant CALLER
role(or any another role) to the caller.
// You can manually set the number for the role.
// But better to use a hash of the variable name.
// It will generate a unique identifier of this role.
// And will reduce the chance to have overlapping roles.
const CALLER: RoleType = ink_lang::selector_id!("CALLER");
impl Contract {
#[ink(constructor)]
pub fn new() -> Self {
ink_lang::codegen::initialize_contract(|instance: &mut Self| {
let caller = instance.env().caller();
instance._init_with_admin(caller);
instance.grant_role(CALLER, caller).expect("Should grant CALLER role");
})
}
}
Step 3: Customize your contract
Customize it by adding access control logic. We will add a restricted_function
to Contract
implementation,
which will use the only_role
modifier with CALLER
parameter, which verifies that the caller has the CALLER
role.
#![cfg_attr(not(feature = "std"), no_std)]
#![feature(min_specialization)]
#[openbrush::contract]
pub mod my_access_control {
use ink_storage::traits::SpreadAllocate;
use openbrush::{
contracts::access_control::*,
modifiers,
traits::Storage,
};
#[ink(storage)]
#[derive(Default, SpreadAllocate, Storage)]
pub struct Contract {
#[storage_field]
access: access_control::Data,
}
// You can manually set the number for the role.
// But better to use a hash of the variable name.
// It will generate a unique identifier of this role.
// And will reduce the chance to have overlapping roles.
const CALLER: RoleType = ink_lang::selector_id!("CALLER");
impl AccessControl for Contract {}
impl Contract {
#[ink(constructor)]
pub fn new() -> Self {
ink_lang::codegen::initialize_contract(|instance: &mut Self| {
let caller = instance.env().caller();
instance._init_with_admin(caller);
instance.grant_role(CALLER, caller).expect("Should grant the role");
})
}
#[ink(message)]
#[modifiers(only_role(CALLER))]
pub fn restricted_function(&mut self) -> Result<(), AccessControlError> {
todo!()
}
}
}
You can check an example of the usage of Access Control.