Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate access control to cairo2 #668

Merged
Merged
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
576331b
bump to cairo v2.0.2
andrew-fleming Jul 13, 2023
ad60a22
update Cargo
andrew-fleming Jul 13, 2023
4cbf81d
comment out mods
andrew-fleming Jul 13, 2023
2f024f0
update initializable syntax
andrew-fleming Jul 13, 2023
f3fca36
move security tests
andrew-fleming Jul 13, 2023
49aa0ef
update initializable tests
andrew-fleming Jul 13, 2023
7b81c8f
fix formatting
andrew-fleming Jul 13, 2023
0509970
remove SpanSerde
andrew-fleming Jul 15, 2023
e88feeb
update ownable syntax
andrew-fleming Jul 15, 2023
e332488
add ownable_camel impl
andrew-fleming Jul 15, 2023
d636e53
update syntax in ownable mocks
andrew-fleming Jul 15, 2023
b328476
update ownable tests
andrew-fleming Jul 15, 2023
e407eed
fix formatting
andrew-fleming Jul 15, 2023
638fc73
update cairo
andrew-fleming Jul 17, 2023
1c65b0b
update Cargo
andrew-fleming Jul 17, 2023
91d2083
simplify and clarify tests
andrew-fleming Jul 17, 2023
22f5d04
fix formatting
andrew-fleming Jul 17, 2023
b148079
Merge branch 'cairo2-initializable' into cairo2-ownable
andrew-fleming Jul 17, 2023
2ceea68
simplify internal fns
andrew-fleming Jul 18, 2023
8bf9996
add initializer
andrew-fleming Jul 18, 2023
6ab7e36
fix constructor, tidy up code
andrew-fleming Jul 18, 2023
3d76993
fix tests
andrew-fleming Jul 18, 2023
b77c775
Apply suggestions from code review
andrew-fleming Jul 18, 2023
1c9d5d3
fix tests
andrew-fleming Jul 18, 2023
a3815d7
fix conflicts
andrew-fleming Jul 18, 2023
9a16f64
fix conflicts
andrew-fleming Jul 18, 2023
277beaa
change StorageTrait to InternalTrait
andrew-fleming Jul 19, 2023
33e2069
fix conflicts
andrew-fleming Jul 19, 2023
6893191
update syntax
andrew-fleming Jul 20, 2023
e898b5c
update mocks
andrew-fleming Jul 20, 2023
d8979e0
start updating tests
andrew-fleming Jul 20, 2023
30dcc83
start refactor
andrew-fleming Jul 20, 2023
1fbf553
change impls to external fns
andrew-fleming Jul 20, 2023
0c9091f
use IOwnableCamelOnly
andrew-fleming Jul 20, 2023
655c40b
fix tests
andrew-fleming Jul 20, 2023
62d779c
remove unneeded mut
andrew-fleming Jul 20, 2023
6312004
remove unneeded mut
andrew-fleming Jul 20, 2023
874002a
fix conflicts
andrew-fleming Jul 20, 2023
2984e6d
fix mocks
andrew-fleming Jul 20, 2023
c658c1b
simplify events
andrew-fleming Jul 20, 2023
92375ac
change array syntax
andrew-fleming Jul 20, 2023
909eefb
update syntax in tests
andrew-fleming Jul 20, 2023
ec2cadc
fix formatting
andrew-fleming Jul 20, 2023
452b269
fix conflicts
andrew-fleming Jul 20, 2023
5958506
Apply suggestions from code review
andrew-fleming Jul 21, 2023
e9883be
add space between events
andrew-fleming Jul 21, 2023
6b2e75a
fix generic state
andrew-fleming Jul 21, 2023
73fc41c
add space between events
andrew-fleming Jul 21, 2023
f49c83c
fix formatting
andrew-fleming Jul 21, 2023
8b099f9
fix conflicts
andrew-fleming Jul 21, 2023
7d85df6
fix conflicts
andrew-fleming Jul 21, 2023
d158c8c
fix conflicts
andrew-fleming Jul 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/openzeppelin/access.cairo
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
//mod accesscontrol;
mod accesscontrol;
mod ownable;
246 changes: 100 additions & 146 deletions src/openzeppelin/access/accesscontrol/accesscontrol.cairo
Original file line number Diff line number Diff line change
@@ -1,211 +1,165 @@
#[contract]
#[starknet::contract]
mod AccessControl {
use openzeppelin::access::accesscontrol::interface;
use openzeppelin::introspection::src5;
use starknet::ContractAddress;
use starknet::get_caller_address;
use openzeppelin::access::accesscontrol::interface;
use openzeppelin::introspection::interface::ISRC5;
use openzeppelin::introspection::interface::ISRC5Camel;
use openzeppelin::introspection::src5::SRC5;

#[storage]
struct Storage {
role_admin: LegacyMap<felt252, felt252>,
role_members: LegacyMap<(felt252, ContractAddress), bool>,
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
RoleGranted: RoleGranted,
RoleRevoked: RoleRevoked,
RoleAdminChanged: RoleAdminChanged,
}

/// Emitted when `account` is granted `role`.
///
/// `sender` is the account that originated the contract call, an admin role
/// bearer (except if `_grant_role` is called during initialization from the constructor).
#[event]
fn RoleGranted(role: felt252, account: ContractAddress, sender: ContractAddress) {}
#[derive(Drop, starknet::Event)]
struct RoleGranted {
role: felt252,
account: ContractAddress,
sender: ContractAddress
}

/// Emitted when `account` is revoked `role`.
///
/// `sender` is the account that originated the contract call:
/// - If using `revoke_role`, it is the admin role bearer.
/// - If using `renounce_role`, it is the role bearer (i.e. `account`).
#[event]
fn RoleRevoked(role: felt252, account: ContractAddress, sender: ContractAddress) {}
#[derive(Drop, starknet::Event)]
struct RoleRevoked {
role: felt252,
account: ContractAddress,
sender: ContractAddress
}

/// Emitted when `new_admin_role` is set as `role`'s admin role, replacing `previous_admin_role`
///
/// `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
/// {RoleAdminChanged} not being emitted signaling this.
#[event]
fn RoleAdminChanged(role: felt252, previous_admin_role: felt252, new_admin_role: felt252) {}

impl ISRC5Impl of src5::ISRC5 {
fn supports_interface(interface_id: felt252) -> bool {
src5::SRC5::supports_interface(interface_id)
#[derive(Drop, starknet::Event)]
struct RoleAdminChanged {
role: felt252,
previous_admin_role: felt252,
new_admin_role: felt252
}

#[external(v0)]
impl SRC5Impl of ISRC5<ContractState> {
fn supports_interface(self: @ContractState, interface_id: felt252) -> bool {
let unsafe_state = SRC5::unsafe_new_contract_state();
SRC5::SRC5Impl::supports_interface(@unsafe_state, interface_id)
}
}

impl ISRC5CamelImpl of src5::ISRC5Camel {
fn supportsInterface(interfaceId: felt252) -> bool {
src5::SRC5::supportsInterface(interfaceId)
#[external(v0)]
impl SRC5CamelImpl of ISRC5Camel<ContractState> {
fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool {
let unsafe_state = SRC5::unsafe_new_contract_state();
SRC5::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId)
}
}

impl AccessControlImpl of interface::IAccessControl {
fn has_role(role: felt252, account: ContractAddress) -> bool {
role_members::read((role, account))
#[external(v0)]
impl AccessControlImpl of interface::IAccessControl<ContractState> {
fn has_role(self: @ContractState, role: felt252, account: ContractAddress) -> bool {
self.role_members.read((role, account))
}

fn get_role_admin(role: felt252) -> felt252 {
role_admin::read(role)
fn get_role_admin(self: @ContractState, role: felt252) -> felt252 {
self.role_admin.read(role)
}

fn grant_role(role: felt252, account: ContractAddress) {
let admin = get_role_admin(role);
assert_only_role(admin);
_grant_role(role, account);
fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) {
let admin = AccessControlImpl::get_role_admin(@self, role);
self.assert_only_role(admin);
self._grant_role(role, account);
}

fn revoke_role(role: felt252, account: ContractAddress) {
let admin: felt252 = get_role_admin(role);
assert_only_role(admin);
_revoke_role(role, account);
fn revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) {
let admin = AccessControlImpl::get_role_admin(@self, role);
self.assert_only_role(admin);
self._revoke_role(role, account);
}

fn renounce_role(role: felt252, account: ContractAddress) {
fn renounce_role(ref self: ContractState, role: felt252, account: ContractAddress) {
let caller: ContractAddress = get_caller_address();
assert(caller == account, 'Can only renounce role for self');
_revoke_role(role, account);
self._revoke_role(role, account);
}
}

impl AccessControlCamelImpl of interface::IAccessControlCamel {
fn hasRole(role: felt252, account: ContractAddress) -> bool {
AccessControlImpl::has_role(role, account)
#[external(v0)]
impl AccessControlCamelImpl of interface::IAccessControlCamel<ContractState> {
fn hasRole(self: @ContractState, role: felt252, account: ContractAddress) -> bool {
AccessControlImpl::has_role(self, role, account)
}

fn getRoleAdmin(role: felt252) -> felt252 {
AccessControlImpl::get_role_admin(role)
fn getRoleAdmin(self: @ContractState, role: felt252) -> felt252 {
AccessControlImpl::get_role_admin(self, role)
}

fn grantRole(role: felt252, account: ContractAddress) {
AccessControlImpl::grant_role(role, account);
fn grantRole(ref self: ContractState, role: felt252, account: ContractAddress) {
AccessControlImpl::grant_role(ref self, role, account);
}

fn revokeRole(role: felt252, account: ContractAddress) {
AccessControlImpl::revoke_role(role, account);
fn revokeRole(ref self: ContractState, role: felt252, account: ContractAddress) {
AccessControlImpl::revoke_role(ref self, role, account);
}

fn renounceRole(role: felt252, account: ContractAddress) {
AccessControlImpl::renounce_role(role, account);
fn renounceRole(ref self: ContractState, role: felt252, account: ContractAddress) {
AccessControlImpl::renounce_role(ref self, role, account);
}
}

//
// View
//

#[view]
fn supports_interface(interface_id: felt252) -> bool {
ISRC5Impl::supports_interface(interface_id)
}

#[view]
fn supportsInterface(interfaceId: felt252) -> bool {
ISRC5CamelImpl::supportsInterface(interfaceId)
}

#[view]
fn has_role(role: felt252, account: ContractAddress) -> bool {
AccessControlImpl::has_role(role, account)
}

#[view]
fn hasRole(role: felt252, account: ContractAddress) -> bool {
AccessControlCamelImpl::hasRole(role, account)
}

#[view]
fn get_role_admin(role: felt252) -> felt252 {
AccessControlImpl::get_role_admin(role)
}

#[view]
fn getRoleAdmin(role: felt252) -> felt252 {
AccessControlCamelImpl::getRoleAdmin(role)
}

//
// External
//

#[external]
fn grant_role(role: felt252, account: ContractAddress) {
AccessControlImpl::grant_role(role, account);
}

#[external]
fn grantRole(role: felt252, account: ContractAddress) {
AccessControlCamelImpl::grantRole(role, account);
}

#[external]
fn revoke_role(role: felt252, account: ContractAddress) {
AccessControlImpl::revoke_role(role, account);
}

#[external]
fn revokeRole(role: felt252, account: ContractAddress) {
AccessControlCamelImpl::revokeRole(role, account);
}

#[external]
fn renounce_role(role: felt252, account: ContractAddress) {
AccessControlImpl::renounce_role(role, account);
}

#[external]
fn renounceRole(role: felt252, account: ContractAddress) {
AccessControlCamelImpl::renounceRole(role, account);
}

//
// Internals
// Internal
//

#[internal]
fn initializer() {
src5::SRC5::register_interface(interface::IACCESSCONTROL_ID);
}

#[internal]
fn assert_only_role(role: felt252) {
let caller: ContractAddress = get_caller_address();
let authorized: bool = has_role(role, caller);
assert(authorized, 'Caller is missing role');
}

//
// WARNING
// The following internal methods are unprotected and should not be used
// outside of a contract's constructor.
//
#[generate_trait]
impl InternalImpl of InternalTrait {
fn initializer(ref self: ContractState) {
let mut unsafe_state = SRC5::unsafe_new_contract_state();
SRC5::InternalImpl::register_interface(ref unsafe_state, interface::IACCESSCONTROL_ID);
}

#[internal]
fn _grant_role(role: felt252, account: ContractAddress) {
if !has_role(role, account) {
fn assert_only_role(self: @ContractState, role: felt252) {
let caller: ContractAddress = get_caller_address();
role_members::write((role, account), true);
RoleGranted(role, account, caller);
let authorized: bool = AccessControlImpl::has_role(self, role, caller);
assert(authorized, 'Caller is missing role');
}
}

#[internal]
fn _revoke_role(role: felt252, account: ContractAddress) {
if has_role(role, account) {
let caller: ContractAddress = get_caller_address();
role_members::write((role, account), false);
RoleRevoked(role, account, caller);
fn _grant_role(ref self: ContractState, role: felt252, account: ContractAddress) {
if !AccessControlImpl::has_role(@self, role, account) {
let caller: ContractAddress = get_caller_address();
self.role_members.write((role, account), true);
self.emit(RoleGranted { role, account, sender: caller });
}
}
}

#[internal]
fn _set_role_admin(role: felt252, admin_role: felt252) {
let previous_admin_role: felt252 = get_role_admin(role);
role_admin::write(role, admin_role);
RoleAdminChanged(role, previous_admin_role, admin_role);
fn _revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) {
if AccessControlImpl::has_role(@self, role, account) {
let caller: ContractAddress = get_caller_address();
self.role_members.write((role, account), false);
self.emit(RoleRevoked { role, account, sender: caller });
}
}

fn _set_role_admin(ref self: ContractState, role: felt252, admin_role: felt252) {
let previous_admin_role: felt252 = AccessControlImpl::get_role_admin(@self, role);
self.role_admin.write(role, admin_role);
self.emit(RoleAdminChanged { role, previous_admin_role, new_admin_role: admin_role });
}
}
}
12 changes: 6 additions & 6 deletions src/openzeppelin/access/accesscontrol/dual_accesscontrol.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ trait DualCaseAccessControlTrait {

impl DualCaseAccessControlImpl of DualCaseAccessControlTrait {
fn has_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress) -> bool {
let mut args = ArrayTrait::new();
let mut args = array![];
args.append_serde(role);
args.append_serde(account);

Expand All @@ -35,7 +35,7 @@ impl DualCaseAccessControlImpl of DualCaseAccessControlTrait {
}

fn get_role_admin(self: @DualCaseAccessControl, role: felt252) -> felt252 {
let mut args = ArrayTrait::new();
let mut args = array![];
args.append_serde(role);

try_selector_with_fallback(
Expand All @@ -45,7 +45,7 @@ impl DualCaseAccessControlImpl of DualCaseAccessControlTrait {
}

fn grant_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress) {
let mut args = ArrayTrait::new();
let mut args = array![];
args.append_serde(role);
args.append_serde(account);

Expand All @@ -56,7 +56,7 @@ impl DualCaseAccessControlImpl of DualCaseAccessControlTrait {
}

fn revoke_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress) {
let mut args = ArrayTrait::new();
let mut args = array![];
args.append_serde(role);
args.append_serde(account);

Expand All @@ -67,7 +67,7 @@ impl DualCaseAccessControlImpl of DualCaseAccessControlTrait {
}

fn renounce_role(self: @DualCaseAccessControl, role: felt252, account: ContractAddress) {
let mut args = ArrayTrait::new();
let mut args = array![];
args.append_serde(role);
args.append_serde(account);

Expand All @@ -78,7 +78,7 @@ impl DualCaseAccessControlImpl of DualCaseAccessControlTrait {
}

fn supports_interface(self: @DualCaseAccessControl, interface_id: felt252) -> bool {
let mut args = ArrayTrait::new();
let mut args = array![];
args.append_serde(interface_id);

try_selector_with_fallback(
Expand Down
Loading