diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index 6c63f53eb..90e358838 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -132,18 +132,40 @@ and sets a 'minter' role: [,javascript] ---- -const MINTER_ROLE: felt252 = selector!('MINTER_ROLE'); +const MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); #[starknet::contract] mod MyContract { - use openzeppelin::access::accesscontrol::AccessControl::InternalImpl::assert_only_role; - use openzeppelin::access::accesscontrol::AccessControl; + use openzeppelin::access::accesscontrol::AccessControl as accesscontrol_component; + use openzeppelin::introspection::src5::SRC5 as src5_component; use openzeppelin::token::erc20::ERC20; use starknet::ContractAddress; use super::MINTER_ROLE; + component!(path: accesscontrol_component, storage: accesscontrol, event: AccessControlEvent); + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl AccessControlImpl = + accesscontrol_component::AccessControlImpl; + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + impl AccessControlInternalImpl = accesscontrol_component::InternalImpl; + #[storage] - struct Storage {} + struct Storage { + #[substorage(v0)] + accesscontrol: accesscontrol_component::Storage, + #[substorage(v0)] + src5: src5_component::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + AccessControlEvent: accesscontrol_component::Event, + SRC5Event: src5_component::Event + } #[constructor] fn constructor( @@ -160,22 +182,16 @@ mod MyContract { ERC20::InternalImpl::_mint(ref erc20_state, recipient, initial_supply); // AccessControl related initialization - let mut access_state = AccessControl::unsafe_new_contract_state(); - AccessControl::InternalImpl::initializer(ref access_state); - AccessControl::InternalImpl::_grant_role( - ref access_state, - MINTER_ROLE, - minter - ); + self.accesscontrol.initializer(); + self.accesscontrol._grant_role(MINTER_ROLE, minter); } - // This function can only be called by a minter + /// This function can only be called by a minter. #[external(v0)] fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { - let access_state = AccessControl::unsafe_new_contract_state(); - assert_only_role(@access_state, MINTER_ROLE); + self.accesscontrol.assert_only_role(MINTER_ROLE); - let mut erc20_state = AccessControl::unsafe_new_contract_state(); + let mut erc20_state = ERC20::unsafe_new_contract_state(); ERC20::InternalImpl::_mint(ref erc20_state, recipient, amount); } } @@ -192,19 +208,41 @@ Let's augment our ERC20 token example by also defining a 'burner' role, which le [,javascript] ---- -const MINTER_ROLE: felt252 = selector!('MINTER_ROLE'); -const BURNER_ROLE: felt252 = selector!('BURNER_ROLE'); +const MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); +const BURNER_ROLE: felt252 = selector!("BURNER_ROLE"); #[starknet::contract] mod MyContract { - use openzeppelin::access::accesscontrol::AccessControl::InternalImpl::assert_only_role; - use openzeppelin::access::accesscontrol::AccessControl; + use openzeppelin::access::accesscontrol::AccessControl as accesscontrol_component; + use openzeppelin::introspection::src5::SRC5 as src5_component; use openzeppelin::token::erc20::ERC20; use starknet::ContractAddress; use super::{MINTER_ROLE, BURNER_ROLE}; + component!(path: accesscontrol_component, storage: accesscontrol, event: AccessControlEvent); + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl AccessControlImpl = + accesscontrol_component::AccessControlImpl; + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + impl AccessControlInternalImpl = accesscontrol_component::InternalImpl; + #[storage] - struct Storage {} + struct Storage { + #[substorage(v0)] + accesscontrol: accesscontrol_component::Storage, + #[substorage(v0)] + src5: src5_component::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + AccessControlEvent: accesscontrol_component::Event, + SRC5Event: src5_component::Event + } #[constructor] fn constructor( @@ -222,38 +260,26 @@ mod MyContract { ERC20::InternalImpl::_mint(ref erc20_state, recipient, initial_supply); // AccessControl related initialization - let mut access_state = AccessControl::unsafe_new_contract_state(); - AccessControl::InternalImpl::initializer(ref access_state); - AccessControl::InternalImpl::_grant_role( - ref access_state, - MINTER_ROLE, - minter - ); - AccessControl::InternalImpl::_grant_role( - ref access_state, - BURNER_ROLE, - burner - ); + self.accesscontrol.initializer(); + self.accesscontrol._grant_role(MINTER_ROLE, minter); + self.accesscontrol._grant_role(BURNER_ROLE, burner); } - - // This function can only be called by a minter + /// This function can only be called by a minter. #[external(v0)] fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { - let access_state = AccessControl::unsafe_new_contract_state(); - assert_only_role(@access_state, MINTER_ROLE); + self.accesscontrol.assert_only_role(MINTER_ROLE); - let mut erc20_state = AccessControl::unsafe_new_contract_state(); + let mut erc20_state = ERC20::unsafe_new_contract_state(); ERC20::InternalImpl::_mint(ref erc20_state, recipient, amount); } - // This function can only be called by a burner + /// This function can only be called by a burner. #[external(v0)] fn burn(ref self: ContractState, account: ContractAddress, amount: u256) { - let access_state = AccessControl::unsafe_new_contract_state(); - assert_only_role(@access_state, BURNER_ROLE); + self.accesscontrol.assert_only_role(BURNER_ROLE); - let mut erc20_state = AccessControl::unsafe_new_contract_state(); + let mut erc20_state = ERC20::unsafe_new_contract_state(); ERC20::InternalImpl::_burn(ref erc20_state, account, amount); } } @@ -292,20 +318,29 @@ Let's take a look at the ERC20 token example, this time taking advantage of the [,javascript] ---- -const MINTER_ROLE: felt252 = selector!('MINTER_ROLE'); -const BURNER_ROLE: felt252 = selector!('BURNER_ROLE'); +const MINTER_ROLE: felt252 = selector!("MINTER_ROLE"); +const BURNER_ROLE: felt252 = selector!("BURNER_ROLE"); #[starknet::contract] mod MyContract { - use openzeppelin::access::accesscontrol::AccessControl::InternalImpl::assert_only_role; - use openzeppelin::access::accesscontrol::AccessControl; + use openzeppelin::access::accesscontrol::AccessControl as accesscontrol_component; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; + use openzeppelin::introspection::src5::SRC5 as src5_component; use openzeppelin::token::erc20::ERC20; use starknet::ContractAddress; use super::{MINTER_ROLE, BURNER_ROLE}; - #[storage] - struct Storage {} + component!(path: accesscontrol_component, storage: accesscontrol, event: AccessControlEvent); + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl AccessControlImpl = + accesscontrol_component::AccessControlImpl; + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + impl AccessControlInternalImpl = accesscontrol_component::InternalImpl; + + (...) #[constructor] fn constructor( @@ -322,49 +357,33 @@ mod MyContract { ERC20::InternalImpl::_mint(ref erc20_state, recipient, initial_supply); // AccessControl related initialization - let mut access_state = AccessControl::unsafe_new_contract_state(); - AccessControl::InternalImpl::initializer(ref access_state); - AccessControl::InternalImpl::_grant_role( - ref access_state, - DEFAULT_ADMIN_ROLE, - admin - ); + self.accesscontrol.initializer(); + self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, admin); } - // This function can only be called by a minter + /// This function can only be called by a minter. #[external(v0)] fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { - let access_state = AccessControl::unsafe_new_contract_state(); - assert_only_role(@access_state, MINTER_ROLE); + self.accesscontrol.assert_only_role(MINTER_ROLE); - let mut erc20_state = AccessControl::unsafe_new_contract_state(); + let mut erc20_state = ERC20::unsafe_new_contract_state(); ERC20::InternalImpl::_mint(ref erc20_state, recipient, amount); } - // This function can only be called by a burner + /// This function can only be called by a burner. #[external(v0)] fn burn(ref self: ContractState, account: ContractAddress, amount: u256) { - let access_state = AccessControl::unsafe_new_contract_state(); - assert_only_role(@access_state, BURNER_ROLE); + self.accesscontrol.assert_only_role(BURNER_ROLE); - let mut erc20_state = AccessControl::unsafe_new_contract_state(); + let mut erc20_state = ERC20::unsafe_new_contract_state(); ERC20::InternalImpl::_burn(ref erc20_state, account, amount); } - - // These function can only be called by the roles' admin - #[external(v0)] - fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControl::AccessControlImpl::grant_role(ref unsafe_state, role, account); - } - #[external(v0)] - fn revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControl::AccessControlImpl::revoke_role(ref unsafe_state, role, account); - } } ---- +TIP: The `grant_role` and `revoke_role` functions are automatically exposed as `external` functions +from the `AccessControlImpl` by leveraging the `#[abi(embed_v0)]` annotation. + Note that, unlike the previous examples, no accounts are granted the 'minter' or 'burner' roles. However, because those roles' admin role is the default admin role, and that role was granted to the 'admin', that same account can call `grant_role` to give minting or burning permission, and `revoke_role` to remove it. diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 71b017914..bea3fbd66 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -287,28 +287,24 @@ Emitted when `account` is revoked `role`. use openzeppelin::access::accesscontrol::AccessControl; ``` -Contract module that allows children to implement role-based access control mechanisms. +Component that allows contracts to implement role-based access control mechanisms. Roles are referred to by their `felt252` identifier: ```javascript -const MY_ROLE: felt252 = selector!('MY_ROLE'); +const MY_ROLE: felt252 = selector!("MY_ROLE"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {assert_only_role}[`assert_only_role`]: ```javascript -use openzeppelin::access::accesscontrol::AccessControl::InternalImpl::assert_only_role; -use openzeppelin::access::accesscontrol::AccessControl; -use openzeppelin::token::erc20::ERC20; +(...) #[external(v0)] -fn foo(ref self: ContractState, account: ContractAddress, amount: u256) { - let access_state = AccessControl::unsafe_new_contract_state(); - assert_only_role(@access_state, BURNER_ROLE); +fn foo(ref self: ContractState) { + self.accesscontrol.assert_only_role(MY_ROLE); - let mut erc20_state = ERC20::unsafe_new_contract_state(); - ERC20::InternalImpl::_burn(ref erc20_state, account, amount); + // Do something } ``` @@ -326,7 +322,7 @@ grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. [.contract-index] -.External Functions +.Embeddable Functions -- .AccessControlImpl @@ -340,16 +336,28 @@ accounts that have been granted it. * xref:#AccessControl-supports_interface[`++supports_interface(self, interface_id: felt252)++`] -- +[.contract-index] +.camelCase Support +-- +.AccessControlCamelImpl + +* xref:#AccessControl-hasRole[`++hasRole(self, role, account)++`] +* xref:#AccessControl-getRoleAdmin[`++getRoleAdmin(self, role)++`] +* xref:#AccessControl-grantRole[`++grantRole(self, role, account)++`] +* xref:#AccessControl-revokeRole[`++revokeRole(self, role, account)++`] +* xref:#AccessControl-renounceRole[`++renounceRole(self, role, account)++`] +-- + [.contract-index] .Internal Functions -- .InternalImpl * xref:#AccessControl-initializer[`++initializer(self)++`] +* xref:#AccessControl-assert_only_role[`++assert_only_role(self, role)++`] * xref:#AccessControl-_set_role_admin[`++_set_role_admin(self, role, admin_role)++`] * xref:#AccessControl-_grant_role[`++_grant_role(self, role, account)++`] * xref:#AccessControl-_revoke_role[`++_revoke_role(self, role, account)++`] -* xref:#AccessControl-assert_only_role[`++assert_only_role(self, role)++`] -- [.contract-index] @@ -361,8 +369,8 @@ accounts that have been granted it. * xref:#AccessControl-RoleRevoked[`++RoleRevoked(role, account, sender)++`] -- -[#AccessControl-External-Functions] -==== External Functions +[#AccessControl-Embeddable-Functions] +==== Embeddable Functions [.contract-item] [[AccessControl-has_role]] @@ -433,6 +441,39 @@ May emit a {RoleRevoked} event. See xref:api/introspection.adoc#ISRC5-supports_interface[ISRC5::supports_interface]. +[#AccessControl-camelCase-Support] +==== camelCase Support + +[.contract-item] +[[AccessControl-hasRole]] +==== `[.contract-item-name]#++hasRole++#++(self: @ContractState, role: felt252, account: ContractAddress) → bool++` [.item-kind]#external# + +See xref:AccessControl-has_role[has_role]. + +[.contract-item] +[[AccessControl-getRoleAdmin]] +==== `[.contract-item-name]#++getRoleAdmin++#++(self: @ContractState, role: felt252) → felt252++` [.item-kind]#external# + +See xref:AccessControl-get_role_admin[get_role_admin]. + +[.contract-item] +[[AccessControl-grantRole]] +==== `[.contract-item-name]#++grantRole++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#external# + +See xref:AccessControl-grant_role[grant_role]. + +[.contract-item] +[[AccessControl-revokeRole]] +==== `[.contract-item-name]#++revokeRole++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#external# + +See xref:AccessControl-revoke_role[revoke_role]. + +[.contract-item] +[[AccessControl-renounceRole]] +==== `[.contract-item-name]#++renounceRole++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#external# + +See xref:AccessControl-renounce_role[renounce_role]. + [#AccessControl-Internal-Functions] ==== Internal Functions @@ -442,6 +483,12 @@ See xref:api/introspection.adoc#ISRC5-supports_interface[ISRC5::supports_interfa Initializes the contract by registering the xref:#IAccessControl[IAccessControl] interface ID. +[.contract-item] +[[AccessControl-assert_only_role]] +==== `[.contract-item-name]#++assert_only_role++#++(self: @ContractState, role: felt252)++` [.item-kind]#internal# + +Panics if called by any account without the given `role`. + [.contract-item] [[AccessControl-_set_role_admin]] ==== `[.contract-item-name]#++_set_role_admin++#++(ref self: ContractState, role: felt252, admin_role: felt252)++` [.item-kind]#internal# @@ -470,12 +517,6 @@ Internal function without access restriction. May emit a {RoleRevoked} event. -[.contract-item] -[[AccessControl-assert_only_role]] -==== `[.contract-item-name]#++assert_only_role++#++(self: @ContractState, role: felt252)++` [.item-kind]#internal# - -Panics if called by any account without the given `role`. - [#AccessControl-Events] ==== Events diff --git a/src/access/accesscontrol/accesscontrol.cairo b/src/access/accesscontrol/accesscontrol.cairo index beb7fffc5..2c5ec554e 100644 --- a/src/access/accesscontrol/accesscontrol.cairo +++ b/src/access/accesscontrol/accesscontrol.cairo @@ -1,27 +1,22 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.7.0 (access/accesscontrol/accesscontrol.cairo) -#[starknet::contract] +/// # AccessControl Component +/// +/// The AccessControl component allows contracts to implement role-based access control mechanisms. +/// Roles are referred to by their `felt252` identifier. +#[starknet::component] mod AccessControl { use openzeppelin::access::accesscontrol::interface; - use openzeppelin::introspection::src5::SRC5 as src5_component; + use openzeppelin::introspection::src5::SRC5::InternalTrait as SRC5InternalTrait; + use openzeppelin::introspection::src5::SRC5; use starknet::ContractAddress; use starknet::get_caller_address; - component!(path: src5_component, storage: src5, event: SRC5Event); - - #[abi(embed_v0)] - impl SRC5Impl = src5_component::SRC5Impl; - #[abi(embed_v0)] - impl SRC5CamelImpl = src5_component::SRC5CamelImpl; - impl SRC5InternalImpl = src5_component::InternalImpl; - #[storage] struct Storage { AccessControl_role_admin: LegacyMap, AccessControl_role_member: LegacyMap<(felt252, ContractAddress), bool>, - #[substorage(v0)] - src5: src5_component::Storage } #[event] @@ -30,7 +25,6 @@ mod AccessControl { RoleGranted: RoleGranted, RoleRevoked: RoleRevoked, RoleAdminChanged: RoleAdminChanged, - SRC5Event: src5_component::Event } /// Emitted when `account` is granted `role`. @@ -72,92 +66,173 @@ mod AccessControl { const MISSING_ROLE: felt252 = 'Caller is missing role'; } - #[external(v0)] - impl AccessControlImpl of interface::IAccessControl { - fn has_role(self: @ContractState, role: felt252, account: ContractAddress) -> bool { + #[embeddable_as(AccessControlImpl)] + impl AccessControl< + TContractState, + +HasComponent, + +SRC5::HasComponent, + +Drop + > of interface::IAccessControl> { + /// Returns whether `account` has been granted `role`. + fn has_role( + self: @ComponentState, role: felt252, account: ContractAddress + ) -> bool { self.AccessControl_role_member.read((role, account)) } - fn get_role_admin(self: @ContractState, role: felt252) -> felt252 { + /// Returns the admin role that controls `role`. + fn get_role_admin(self: @ComponentState, role: felt252) -> felt252 { self.AccessControl_role_admin.read(role) } - fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { - let admin = AccessControlImpl::get_role_admin(@self, role); + /// Grants `role` to `account`. + /// + /// If `account` had not been already granted `role`, emits a `RoleGranted` event. + /// + /// Requirements: + /// + /// - the caller must have `role`'s admin role. + fn grant_role( + ref self: ComponentState, role: felt252, account: ContractAddress + ) { + let admin = self.get_role_admin(role); self.assert_only_role(admin); self._grant_role(role, account); } - fn revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { - let admin = AccessControlImpl::get_role_admin(@self, role); + /// Revokes `role` from `account`. + /// + /// If `account` had been granted `role`, emits a `RoleRevoked` event. + /// + /// Requirements: + /// + /// - the caller must have `role`'s admin role. + fn revoke_role( + ref self: ComponentState, role: felt252, account: ContractAddress + ) { + let admin = self.get_role_admin(role); self.assert_only_role(admin); self._revoke_role(role, account); } - fn renounce_role(ref self: ContractState, role: felt252, account: ContractAddress) { + /// Revokes `role` from the calling account. + /// + /// Roles are often managed via `grant_role` and `revoke_role`: this function's + /// purpose is to provide a mechanism for accounts to lose their privileges + /// if they are compromised (such as when a trusted device is misplaced). + /// + /// If the calling account had been revoked `role`, emits a `RoleRevoked` + /// event. + /// + /// Requirements: + /// + /// - the caller must be `account`. + fn renounce_role( + ref self: ComponentState, role: felt252, account: ContractAddress + ) { let caller: ContractAddress = get_caller_address(); assert(caller == account, Errors::INVALID_CALLER); self._revoke_role(role, account); } } - #[external(v0)] - impl AccessControlCamelImpl of interface::IAccessControlCamel { - fn hasRole(self: @ContractState, role: felt252, account: ContractAddress) -> bool { - AccessControlImpl::has_role(self, role, account) + /// Adds camelCase support for `IAccessControl`. + #[embeddable_as(AccessControlCamelImpl)] + impl AccessControlCamel< + TContractState, + +HasComponent, + +SRC5::HasComponent, + +Drop + > of interface::IAccessControlCamel> { + fn hasRole( + self: @ComponentState, role: felt252, account: ContractAddress + ) -> bool { + self.has_role(role, account) } - fn getRoleAdmin(self: @ContractState, role: felt252) -> felt252 { - AccessControlImpl::get_role_admin(self, role) + fn getRoleAdmin(self: @ComponentState, role: felt252) -> felt252 { + self.get_role_admin(role) } - fn grantRole(ref self: ContractState, role: felt252, account: ContractAddress) { - AccessControlImpl::grant_role(ref self, role, account); + fn grantRole( + ref self: ComponentState, role: felt252, account: ContractAddress + ) { + self.grant_role(role, account); } - fn revokeRole(ref self: ContractState, role: felt252, account: ContractAddress) { - AccessControlImpl::revoke_role(ref self, role, account); + fn revokeRole( + ref self: ComponentState, role: felt252, account: ContractAddress + ) { + self.revoke_role(role, account); } - fn renounceRole(ref self: ContractState, role: felt252, account: ContractAddress) { - AccessControlImpl::renounce_role(ref self, role, account); + fn renounceRole( + ref self: ComponentState, role: felt252, account: ContractAddress + ) { + self.renounce_role(role, account); } } - // - // Internal - // - #[generate_trait] - impl InternalImpl of InternalTrait { - fn initializer(ref self: ContractState) { - self.src5.register_interface(interface::IACCESSCONTROL_ID); + impl InternalImpl< + TContractState, + +HasComponent, + +SRC5::HasComponent, + +Drop + > of InternalTrait { + /// Initializes the contract by registering the IAccessControl interface Id. + fn initializer(ref self: ComponentState) { + let mut contract = self.get_contract_mut(); + let mut src5_component = SRC5::HasComponent::< + TContractState + >::get_component_mut(ref contract); + src5_component.register_interface(interface::IACCESSCONTROL_ID); } - fn assert_only_role(self: @ContractState, role: felt252) { + /// Validates that the caller has the given role. Otherwise it panics. + fn assert_only_role(self: @ComponentState, role: felt252) { let caller: ContractAddress = get_caller_address(); - let authorized: bool = AccessControlImpl::has_role(self, role, caller); + let authorized: bool = self.has_role(role, caller); assert(authorized, Errors::MISSING_ROLE); } - fn _grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { - if !AccessControlImpl::has_role(@self, role, account) { + /// Attempts to grant `role` to `account`. + /// + /// Internal function without access restriction. + /// + /// May emit a `RoleGranted` event. + fn _grant_role( + ref self: ComponentState, role: felt252, account: ContractAddress + ) { + if !self.has_role(role, account) { let caller: ContractAddress = get_caller_address(); self.AccessControl_role_member.write((role, account), true); self.emit(RoleGranted { role, account, sender: caller }); } } - fn _revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { - if AccessControlImpl::has_role(@self, role, account) { + /// Attempts to revoke `role` from `account`. + /// + /// Internal function without access restriction. + /// + /// May emit a `RoleRevoked` event. + fn _revoke_role( + ref self: ComponentState, role: felt252, account: ContractAddress + ) { + if self.has_role(role, account) { let caller: ContractAddress = get_caller_address(); self.AccessControl_role_member.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); + /// Sets `admin_role` as `role`'s admin role. + /// + /// Emits a `RoleAdminChanged` event. + fn _set_role_admin( + ref self: ComponentState, role: felt252, admin_role: felt252 + ) { + let previous_admin_role: felt252 = self.get_role_admin(role); self.AccessControl_role_admin.write(role, admin_role); self.emit(RoleAdminChanged { role, previous_admin_role, new_admin_role: admin_role }); } diff --git a/src/tests/access/test_accesscontrol.cairo b/src/tests/access/test_accesscontrol.cairo index d86dd4490..3e81628f0 100644 --- a/src/tests/access/test_accesscontrol.cairo +++ b/src/tests/access/test_accesscontrol.cairo @@ -1,31 +1,30 @@ -use openzeppelin::access::accesscontrol::AccessControl::AccessControlCamelImpl; -use openzeppelin::access::accesscontrol::AccessControl::AccessControlImpl; use openzeppelin::access::accesscontrol::AccessControl::InternalImpl; use openzeppelin::access::accesscontrol::AccessControl::RoleAdminChanged; use openzeppelin::access::accesscontrol::AccessControl::RoleGranted; use openzeppelin::access::accesscontrol::AccessControl::RoleRevoked; -use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; use openzeppelin::access::accesscontrol::interface::IACCESSCONTROL_ID; +use openzeppelin::access::accesscontrol::interface::{IAccessControl, IAccessControlCamel}; +use openzeppelin::introspection::interface::{ISRC5, ISRC5Camel}; +use openzeppelin::tests::mocks::accesscontrol_mocks::DualCaseAccessControlMock; use openzeppelin::tests::utils::constants::{ ADMIN, AUTHORIZED, OTHER, OTHER_ADMIN, ROLE, OTHER_ROLE, ZERO }; use openzeppelin::tests::utils; use starknet::ContractAddress; -use starknet::contract_address_const; use starknet::testing; // // Setup // -fn STATE() -> AccessControl::ContractState { - AccessControl::contract_state_for_testing() +fn STATE() -> DualCaseAccessControlMock::ContractState { + DualCaseAccessControlMock::contract_state_for_testing() } -fn setup() -> AccessControl::ContractState { +fn setup() -> DualCaseAccessControlMock::ContractState { let mut state = STATE(); - InternalImpl::_grant_role(ref state, DEFAULT_ADMIN_ROLE, ADMIN()); + state.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, ADMIN()); utils::drop_event(ZERO()); state } @@ -38,11 +37,8 @@ fn setup() -> AccessControl::ContractState { #[available_gas(2000000)] fn test_initializer() { let mut state = STATE(); - InternalImpl::initializer(ref state); - assert( - AccessControl::SRC5Impl::supports_interface(@state, IACCESSCONTROL_ID), - 'Should support own interface' - ); + state.accesscontrol.initializer(); + assert(state.src5.supports_interface(IACCESSCONTROL_ID), 'Should support own interface'); } // // supports_interface & supportsInterface @@ -52,22 +48,16 @@ fn test_initializer() { #[available_gas(2000000)] fn test_supports_interface() { let mut state = STATE(); - InternalImpl::initializer(ref state); - assert( - AccessControl::SRC5Impl::supports_interface(@state, IACCESSCONTROL_ID), - 'Should support own interface' - ); + state.accesscontrol.initializer(); + assert(state.src5.supports_interface(IACCESSCONTROL_ID), 'Should support own interface'); } #[test] #[available_gas(2000000)] fn test_supportsInterface() { let mut state = STATE(); - InternalImpl::initializer(ref state); - assert( - AccessControl::SRC5CamelImpl::supportsInterface(@state, IACCESSCONTROL_ID), - 'Should support own interface' - ); + state.accesscontrol.initializer(); + assert(state.src5.supportsInterface(IACCESSCONTROL_ID), 'Should support own interface'); } // @@ -78,18 +68,18 @@ fn test_supportsInterface() { #[available_gas(2000000)] fn test_has_role() { let mut state = setup(); - assert(!AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'should not have role'); - InternalImpl::_grant_role(ref state, ROLE, AUTHORIZED()); - assert(AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'should have role'); + assert(!state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'should not have role'); + state.accesscontrol._grant_role(ROLE, AUTHORIZED()); + assert(state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'should have role'); } #[test] #[available_gas(2000000)] fn test_hasRole() { let mut state = setup(); - assert(!AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'should not have role'); - InternalImpl::_grant_role(ref state, ROLE, AUTHORIZED()); - assert(AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'should have role'); + assert(!state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'should not have role'); + state.accesscontrol._grant_role(ROLE, AUTHORIZED()); + assert(state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'should have role'); } @@ -102,10 +92,10 @@ fn test_hasRole() { fn test_assert_only_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); testing::set_caller_address(AUTHORIZED()); - InternalImpl::assert_only_role(@state, ROLE); + state.accesscontrol.assert_only_role(ROLE); } #[test] @@ -114,7 +104,7 @@ fn test_assert_only_role() { fn test_assert_only_role_unauthorized() { let state = setup(); testing::set_caller_address(OTHER()); - InternalImpl::assert_only_role(@state, ROLE); + state.accesscontrol.assert_only_role(ROLE); } #[test] @@ -122,10 +112,10 @@ fn test_assert_only_role_unauthorized() { #[should_panic(expected: ('Caller is missing role',))] fn test_assert_only_role_unauthorized_when_authorized_for_another_role() { let mut state = setup(); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); testing::set_caller_address(AUTHORIZED()); - InternalImpl::assert_only_role(@state, OTHER_ROLE); + state.accesscontrol.assert_only_role(OTHER_ROLE); } // @@ -137,10 +127,10 @@ fn test_assert_only_role_unauthorized_when_authorized_for_another_role() { fn test_grant_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); assert_event_role_granted(ROLE, AUTHORIZED(), ADMIN()); - assert(AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should be granted'); + assert(state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'Role should be granted'); } #[test] @@ -148,10 +138,10 @@ fn test_grant_role() { fn test_grantRole() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); assert_event_role_granted(ROLE, AUTHORIZED(), ADMIN()); - assert(AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should be granted'); + assert(state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'Role should be granted'); } #[test] @@ -160,9 +150,9 @@ fn test_grant_role_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); - assert(AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should still be granted'); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); + assert(state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'Role should still be granted'); } #[test] @@ -171,11 +161,9 @@ fn test_grantRole_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); - assert( - AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should still be granted' - ); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); + assert(state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'Role should still be granted'); } #[test] @@ -184,7 +172,7 @@ fn test_grantRole_multiple_times_for_granted_role() { fn test_grant_role_unauthorized() { let mut state = setup(); testing::set_caller_address(AUTHORIZED()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); } #[test] @@ -193,7 +181,7 @@ fn test_grant_role_unauthorized() { fn test_grantRole_unauthorized() { let mut state = setup(); testing::set_caller_address(AUTHORIZED()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); } // @@ -205,7 +193,7 @@ fn test_grantRole_unauthorized() { fn test_revoke_role_for_role_not_granted() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.revoke_role(ROLE, AUTHORIZED()); } #[test] @@ -213,7 +201,7 @@ fn test_revoke_role_for_role_not_granted() { fn test_revokeRole_for_role_not_granted() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.revokeRole(ROLE, AUTHORIZED()); } #[test] @@ -222,13 +210,13 @@ fn test_revoke_role_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); utils::drop_event(ZERO()); - AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.revoke_role(ROLE, AUTHORIZED()); assert_event_role_revoked(ROLE, AUTHORIZED(), ADMIN()); - assert(!AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should be revoked'); + assert(!state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'Role should be revoked'); } #[test] @@ -237,13 +225,13 @@ fn test_revokeRole_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); utils::drop_event(ZERO()); - AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.revokeRole(ROLE, AUTHORIZED()); assert_event_role_revoked(ROLE, AUTHORIZED(), ADMIN()); - assert(!AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should be revoked'); + assert(!state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'Role should be revoked'); } #[test] @@ -252,12 +240,10 @@ fn test_revoke_role_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); - AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); - AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); - assert( - !AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should still be revoked' - ); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); + state.accesscontrol.revoke_role(ROLE, AUTHORIZED()); + state.accesscontrol.revoke_role(ROLE, AUTHORIZED()); + assert(!state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'Role should still be revoked'); } #[test] @@ -266,12 +252,10 @@ fn test_revokeRole_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); - AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); - AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); - assert( - !AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should still be revoked' - ); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); + state.accesscontrol.revokeRole(ROLE, AUTHORIZED()); + state.accesscontrol.revokeRole(ROLE, AUTHORIZED()); + assert(!state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'Role should still be revoked'); } #[test] @@ -280,7 +264,7 @@ fn test_revokeRole_multiple_times_for_granted_role() { fn test_revoke_role_unauthorized() { let mut state = setup(); testing::set_caller_address(OTHER()); - AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.revoke_role(ROLE, AUTHORIZED()); } #[test] @@ -289,7 +273,7 @@ fn test_revoke_role_unauthorized() { fn test_revokeRole_unauthorized() { let mut state = setup(); testing::set_caller_address(OTHER()); - AccessControlCamelImpl::revokeRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.revokeRole(ROLE, AUTHORIZED()); } // @@ -301,7 +285,7 @@ fn test_revokeRole_unauthorized() { fn test_renounce_role_for_role_not_granted() { let mut state = setup(); testing::set_caller_address(AUTHORIZED()); - AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.renounce_role(ROLE, AUTHORIZED()); } #[test] @@ -309,7 +293,7 @@ fn test_renounce_role_for_role_not_granted() { fn test_renounceRole_for_role_not_granted() { let mut state = setup(); testing::set_caller_address(AUTHORIZED()); - AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.renounceRole(ROLE, AUTHORIZED()); } #[test] @@ -318,14 +302,14 @@ fn test_renounce_role_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); utils::drop_event(ZERO()); testing::set_caller_address(AUTHORIZED()); - AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.renounce_role(ROLE, AUTHORIZED()); assert_event_role_revoked(ROLE, AUTHORIZED(), AUTHORIZED()); - assert(!AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should be renounced'); + assert(!state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'Role should be renounced'); } #[test] @@ -334,16 +318,14 @@ fn test_renounceRole_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); utils::drop_event(ZERO()); testing::set_caller_address(AUTHORIZED()); - AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.renounceRole(ROLE, AUTHORIZED()); assert_event_role_revoked(ROLE, AUTHORIZED(), AUTHORIZED()); - assert( - !AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), 'Role should be renounced' - ); + assert(!state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'Role should be renounced'); } #[test] @@ -351,14 +333,12 @@ fn test_renounceRole_for_granted_role() { fn test_renounce_role_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); testing::set_caller_address(AUTHORIZED()); - AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); - AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); - assert( - !AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'Role should still be renounced' - ); + state.accesscontrol.renounce_role(ROLE, AUTHORIZED()); + state.accesscontrol.renounce_role(ROLE, AUTHORIZED()); + assert(!state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'Role should still be renounced'); } #[test] @@ -366,15 +346,12 @@ fn test_renounce_role_multiple_times_for_granted_role() { fn test_renounceRole_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); testing::set_caller_address(AUTHORIZED()); - AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); - AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); - assert( - !AccessControlCamelImpl::hasRole(@state, ROLE, AUTHORIZED()), - 'Role should still be renounced' - ); + state.accesscontrol.renounceRole(ROLE, AUTHORIZED()); + state.accesscontrol.renounceRole(ROLE, AUTHORIZED()); + assert(!state.accesscontrol.hasRole(ROLE, AUTHORIZED()), 'Role should still be renounced'); } #[test] @@ -383,10 +360,10 @@ fn test_renounceRole_multiple_times_for_granted_role() { fn test_renounce_role_unauthorized() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); testing::set_caller_address(ZERO()); - AccessControlImpl::renounce_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.renounce_role(ROLE, AUTHORIZED()); } #[test] @@ -395,10 +372,10 @@ fn test_renounce_role_unauthorized() { fn test_renounceRole_unauthorized() { let mut state = setup(); testing::set_caller_address(ADMIN()); - AccessControlCamelImpl::grantRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grantRole(ROLE, AUTHORIZED()); // Admin is unauthorized caller - AccessControlCamelImpl::renounceRole(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.renounceRole(ROLE, AUTHORIZED()); } // @@ -410,15 +387,14 @@ fn test_renounceRole_unauthorized() { fn test__set_role_admin() { let mut state = setup(); assert( - AccessControlImpl::get_role_admin(@state, ROLE) == DEFAULT_ADMIN_ROLE, + state.accesscontrol.get_role_admin(ROLE) == DEFAULT_ADMIN_ROLE, 'ROLE admin default should be 0' ); - InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); + state.accesscontrol._set_role_admin(ROLE, OTHER_ROLE); assert_event_role_admin_changed(ROLE, DEFAULT_ADMIN_ROLE, OTHER_ROLE); assert( - AccessControlImpl::get_role_admin(@state, ROLE) == OTHER_ROLE, - 'ROLE admin should be OTHER_ROLE' + state.accesscontrol.get_role_admin(ROLE) == OTHER_ROLE, 'ROLE admin should be OTHER_ROLE' ); } @@ -426,31 +402,29 @@ fn test__set_role_admin() { #[available_gas(2000000)] fn test_new_admin_can_grant_roles() { let mut state = setup(); - InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); + state.accesscontrol._set_role_admin(ROLE, OTHER_ROLE); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, OTHER_ROLE, OTHER_ADMIN()); + state.accesscontrol.grant_role(OTHER_ROLE, OTHER_ADMIN()); testing::set_caller_address(OTHER_ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); - assert(AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'AUTHORIZED should have ROLE'); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); + assert(state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'AUTHORIZED should have ROLE'); } #[test] #[available_gas(2000000)] fn test_new_admin_can_revoke_roles() { let mut state = setup(); - InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); + state.accesscontrol._set_role_admin(ROLE, OTHER_ROLE); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, OTHER_ROLE, OTHER_ADMIN()); + state.accesscontrol.grant_role(OTHER_ROLE, OTHER_ADMIN()); testing::set_caller_address(OTHER_ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); - AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); - assert( - !AccessControlImpl::has_role(@state, ROLE, AUTHORIZED()), 'AUTHORIZED should not have ROLE' - ); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); + state.accesscontrol.revoke_role(ROLE, AUTHORIZED()); + assert(!state.accesscontrol.has_role(ROLE, AUTHORIZED()), 'AUTHORIZED should not have ROLE'); } #[test] @@ -458,9 +432,9 @@ fn test_new_admin_can_revoke_roles() { #[should_panic(expected: ('Caller is missing role',))] fn test_previous_admin_cannot_grant_roles() { let mut state = setup(); - InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); + state.accesscontrol._set_role_admin(ROLE, OTHER_ROLE); testing::set_caller_address(ADMIN()); - AccessControlImpl::grant_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.grant_role(ROLE, AUTHORIZED()); } #[test] @@ -468,9 +442,9 @@ fn test_previous_admin_cannot_grant_roles() { #[should_panic(expected: ('Caller is missing role',))] fn test_previous_admin_cannot_revoke_roles() { let mut state = setup(); - InternalImpl::_set_role_admin(ref state, ROLE, OTHER_ROLE); + state.accesscontrol._set_role_admin(ROLE, OTHER_ROLE); testing::set_caller_address(ADMIN()); - AccessControlImpl::revoke_role(ref state, ROLE, AUTHORIZED()); + state.accesscontrol.revoke_role(ROLE, AUTHORIZED()); } // @@ -482,7 +456,7 @@ fn test_previous_admin_cannot_revoke_roles() { fn test_other_role_admin_is_the_default_admin_role() { let state = setup(); assert( - AccessControlImpl::get_role_admin(@state, OTHER_ROLE) == DEFAULT_ADMIN_ROLE, + state.accesscontrol.get_role_admin(OTHER_ROLE) == DEFAULT_ADMIN_ROLE, 'Should be DEFAULT_ADMIN_ROLE' ); } @@ -492,7 +466,7 @@ fn test_other_role_admin_is_the_default_admin_role() { fn test_default_admin_role_is_its_own_admin() { let state = setup(); assert( - AccessControlImpl::get_role_admin(@state, DEFAULT_ADMIN_ROLE) == DEFAULT_ADMIN_ROLE, + state.accesscontrol.get_role_admin(DEFAULT_ADMIN_ROLE) == DEFAULT_ADMIN_ROLE, 'Should be DEFAULT_ADMIN_ROLE' ); } diff --git a/src/tests/access/test_dual_accesscontrol.cairo b/src/tests/access/test_dual_accesscontrol.cairo index 5a666a6db..5c61e4d36 100644 --- a/src/tests/access/test_dual_accesscontrol.cairo +++ b/src/tests/access/test_dual_accesscontrol.cairo @@ -6,11 +6,11 @@ use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatche use openzeppelin::access::accesscontrol::interface::IAccessControlCamelDispatcherTrait; use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcher; use openzeppelin::access::accesscontrol::interface::IAccessControlDispatcherTrait; -use openzeppelin::tests::mocks::accesscontrol_panic_mock::CamelAccessControlPanicMock; -use openzeppelin::tests::mocks::accesscontrol_panic_mock::SnakeAccessControlPanicMock; -use openzeppelin::tests::mocks::camel_accesscontrol_mock::CamelAccessControlMock; +use openzeppelin::tests::mocks::accesscontrol_mocks::{ + CamelAccessControlMock, SnakeAccessControlMock, CamelAccessControlPanicMock, + SnakeAccessControlPanicMock +}; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; -use openzeppelin::tests::mocks::snake_accesscontrol_mock::SnakeAccessControlMock; use openzeppelin::tests::utils::constants::{ADMIN, AUTHORIZED, ROLE}; use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend; diff --git a/src/tests/access/test_dual_ownable.cairo b/src/tests/access/test_dual_ownable.cairo index 1338c32b5..16588be16 100644 --- a/src/tests/access/test_dual_ownable.cairo +++ b/src/tests/access/test_dual_ownable.cairo @@ -4,10 +4,9 @@ use openzeppelin::access::ownable::interface::IOwnableCamelOnlyDispatcher; use openzeppelin::access::ownable::interface::IOwnableDispatcher; use openzeppelin::access::ownable::interface::IOwnableDispatcherTrait; use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; -use openzeppelin::tests::mocks::ownable_mocks::CamelOwnableMock; -use openzeppelin::tests::mocks::ownable_mocks::CamelOwnablePanicMock; -use openzeppelin::tests::mocks::ownable_mocks::SnakeOwnableMock; -use openzeppelin::tests::mocks::ownable_mocks::SnakeOwnablePanicMock; +use openzeppelin::tests::mocks::ownable_mocks::{ + CamelOwnableMock, CamelOwnablePanicMock, SnakeOwnableMock, SnakeOwnablePanicMock +}; use openzeppelin::tests::utils::constants::{OWNER, NEW_OWNER}; use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend; diff --git a/src/tests/mocks.cairo b/src/tests/mocks.cairo index e598542dd..fd4becb51 100644 --- a/src/tests/mocks.cairo +++ b/src/tests/mocks.cairo @@ -1,8 +1,7 @@ -mod accesscontrol_panic_mock; +mod accesscontrol_mocks; mod account_panic_mock; mod camel20_mock; mod camel721_mock; -mod camel_accesscontrol_mock; mod camel_account_mock; mod dual721_receiver_mocks; mod erc20_panic; @@ -16,7 +15,6 @@ mod reentrancy_attacker_mock; mod reentrancy_mock; mod snake20_mock; mod snake721_mock; -mod snake_accesscontrol_mock; mod snake_account_mock; mod src5_mocks; mod upgrades_v1; diff --git a/src/tests/mocks/accesscontrol_mocks.cairo b/src/tests/mocks/accesscontrol_mocks.cairo new file mode 100644 index 000000000..e187734ac --- /dev/null +++ b/src/tests/mocks/accesscontrol_mocks.cairo @@ -0,0 +1,209 @@ +#[starknet::contract] +mod DualCaseAccessControlMock { + use openzeppelin::access::accesscontrol::AccessControl as accesscontrol_component; + use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; + use openzeppelin::introspection::src5::SRC5 as src5_component; + use starknet::ContractAddress; + + component!(path: accesscontrol_component, storage: accesscontrol, event: AccessControlEvent); + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl AccessControlImpl = + accesscontrol_component::AccessControlImpl; + #[abi(embed_v0)] + impl AccessControlCamelImpl = + accesscontrol_component::AccessControlCamelImpl; + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + + impl AccessControlInternalImpl = accesscontrol_component::InternalImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + accesscontrol: accesscontrol_component::Storage, + #[substorage(v0)] + src5: src5_component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + AccessControlEvent: accesscontrol_component::Event, + SRC5Event: src5_component::Event + } + + #[constructor] + fn constructor(ref self: ContractState, admin: ContractAddress) { + self.accesscontrol.initializer(); + self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, admin); + } +} + +#[starknet::contract] +mod SnakeAccessControlMock { + use openzeppelin::access::accesscontrol::AccessControl as accesscontrol_component; + use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; + use openzeppelin::introspection::src5::SRC5 as src5_component; + use starknet::ContractAddress; + + component!(path: accesscontrol_component, storage: accesscontrol, event: AccessControlEvent); + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl AccessControlImpl = + accesscontrol_component::AccessControlImpl; + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + impl AccessControlInternalImpl = accesscontrol_component::InternalImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + accesscontrol: accesscontrol_component::Storage, + #[substorage(v0)] + src5: src5_component::Storage, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + AccessControlEvent: accesscontrol_component::Event, + SRC5Event: src5_component::Event + } + + #[constructor] + fn constructor(ref self: ContractState, admin: ContractAddress) { + self.accesscontrol.initializer(); + self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, admin); + } +} + +#[starknet::contract] +mod CamelAccessControlMock { + use openzeppelin::access::accesscontrol::AccessControl as accesscontrol_component; + use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; + use openzeppelin::introspection::src5::SRC5 as src5_component; + use starknet::ContractAddress; + + component!(path: accesscontrol_component, storage: accesscontrol, event: AccessControlEvent); + component!(path: src5_component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl AccessControlCamelImpl = + accesscontrol_component::AccessControlCamelImpl; + #[abi(embed_v0)] + impl SRC5Impl = src5_component::SRC5Impl; + + impl AccessControlInternalImpl = accesscontrol_component::InternalImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + accesscontrol: accesscontrol_component::Storage, + #[substorage(v0)] + src5: src5_component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + AccessControlEvent: accesscontrol_component::Event, + SRC5Event: src5_component::Event + } + + #[constructor] + fn constructor(ref self: ContractState, admin: ContractAddress) { + self.accesscontrol.initializer(); + self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, admin); + } +} + +// Although these modules are designed to panic, functions +// still need a valid return value. We chose: +// +// 3 for felt252 +// false for bool + +#[starknet::contract] +mod SnakeAccessControlPanicMock { + use starknet::ContractAddress; + + #[storage] + struct Storage {} + + #[external(v0)] + fn has_role(self: @ContractState, role: felt252, account: ContractAddress) -> bool { + panic_with_felt252('Some error'); + false + } + + #[external(v0)] + fn get_role_admin(self: @ContractState, role: felt252) -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[external(v0)] + fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external(v0)] + fn revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external(v0)] + fn renounce_role(ref self: ContractState, role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external(v0)] + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + panic_with_felt252('Some error'); + false + } +} + +#[starknet::contract] +mod CamelAccessControlPanicMock { + use starknet::ContractAddress; + + #[storage] + struct Storage {} + + #[external(v0)] + fn hasRole(self: @ContractState, role: felt252, account: ContractAddress) -> bool { + panic_with_felt252('Some error'); + false + } + + #[external(v0)] + fn getRoleAdmin(self: @ContractState, role: felt252) -> felt252 { + panic_with_felt252('Some error'); + 3 + } + + #[external(v0)] + fn grantRole(ref self: ContractState, role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external(v0)] + fn revokeRole(ref self: ContractState, role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external(v0)] + fn renounceRole(ref self: ContractState, role: felt252, account: ContractAddress) { + panic_with_felt252('Some error'); + } + + #[external(v0)] + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { + panic_with_felt252('Some error'); + false + } +} diff --git a/src/tests/mocks/accesscontrol_panic_mock.cairo b/src/tests/mocks/accesscontrol_panic_mock.cairo deleted file mode 100644 index 8ccfe80dc..000000000 --- a/src/tests/mocks/accesscontrol_panic_mock.cairo +++ /dev/null @@ -1,87 +0,0 @@ -// Although these modules are designed to panic, functions -// still need a valid return value. We chose: -// -// 3 for felt252 -// false for bool - -#[starknet::contract] -mod SnakeAccessControlPanicMock { - use starknet::ContractAddress; - - #[storage] - struct Storage {} - - #[external(v0)] - fn has_role(self: @ContractState, role: felt252, account: ContractAddress) -> bool { - panic_with_felt252('Some error'); - false - } - - #[external(v0)] - fn get_role_admin(self: @ContractState, role: felt252) -> felt252 { - panic_with_felt252('Some error'); - 3 - } - - #[external(v0)] - fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); - } - - #[external(v0)] - fn revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); - } - - #[external(v0)] - fn renounce_role(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); - } - - #[external(v0)] - fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - panic_with_felt252('Some error'); - false - } -} - -#[starknet::contract] -mod CamelAccessControlPanicMock { - use starknet::ContractAddress; - - #[storage] - struct Storage {} - - #[external(v0)] - fn hasRole(self: @ContractState, role: felt252, account: ContractAddress) -> bool { - panic_with_felt252('Some error'); - false - } - - #[external(v0)] - fn getRoleAdmin(self: @ContractState, role: felt252) -> felt252 { - panic_with_felt252('Some error'); - 3 - } - - #[external(v0)] - fn grantRole(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); - } - - #[external(v0)] - fn revokeRole(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); - } - - #[external(v0)] - fn renounceRole(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); - } - - #[external(v0)] - fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - panic_with_felt252('Some error'); - false - } -} diff --git a/src/tests/mocks/camel_accesscontrol_mock.cairo b/src/tests/mocks/camel_accesscontrol_mock.cairo deleted file mode 100644 index 09e2fbf92..000000000 --- a/src/tests/mocks/camel_accesscontrol_mock.cairo +++ /dev/null @@ -1,53 +0,0 @@ -#[starknet::contract] -mod CamelAccessControlMock { - use openzeppelin::access::accesscontrol::AccessControl::AccessControlCamelImpl; - use openzeppelin::access::accesscontrol::AccessControl; - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; - use starknet::ContractAddress; - - #[storage] - struct Storage {} - - #[constructor] - fn constructor(ref self: ContractState, admin: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControl::InternalImpl::initializer(ref unsafe_state); - AccessControl::InternalImpl::_grant_role(ref unsafe_state, DEFAULT_ADMIN_ROLE, admin); - } - - #[external(v0)] - fn hasRole(self: @ContractState, role: felt252, account: ContractAddress) -> bool { - let unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlCamelImpl::hasRole(@unsafe_state, role, account) - } - - #[external(v0)] - fn getRoleAdmin(self: @ContractState, role: felt252) -> felt252 { - let unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlCamelImpl::getRoleAdmin(@unsafe_state, role) - } - - #[external(v0)] - fn grantRole(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlCamelImpl::grantRole(ref unsafe_state, role, account); - } - - #[external(v0)] - fn revokeRole(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlCamelImpl::revokeRole(ref unsafe_state, role, account); - } - - #[external(v0)] - fn renounceRole(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlCamelImpl::renounceRole(ref unsafe_state, role, account); - } - - #[external(v0)] - fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - let unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControl::SRC5CamelImpl::supportsInterface(@unsafe_state, interfaceId) - } -} diff --git a/src/tests/mocks/snake_accesscontrol_mock.cairo b/src/tests/mocks/snake_accesscontrol_mock.cairo deleted file mode 100644 index 614b00627..000000000 --- a/src/tests/mocks/snake_accesscontrol_mock.cairo +++ /dev/null @@ -1,53 +0,0 @@ -#[starknet::contract] -mod SnakeAccessControlMock { - use openzeppelin::access::accesscontrol::AccessControl::AccessControlImpl; - use openzeppelin::access::accesscontrol::AccessControl; - use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; - use starknet::ContractAddress; - - #[storage] - struct Storage {} - - #[constructor] - fn constructor(ref self: ContractState, admin: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControl::InternalImpl::initializer(ref unsafe_state); - AccessControl::InternalImpl::_grant_role(ref unsafe_state, DEFAULT_ADMIN_ROLE, admin); - } - - #[external(v0)] - fn has_role(self: @ContractState, role: felt252, account: ContractAddress) -> bool { - let unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlImpl::has_role(@unsafe_state, role, account) - } - - #[external(v0)] - fn get_role_admin(self: @ContractState, role: felt252) -> felt252 { - let unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlImpl::get_role_admin(@unsafe_state, role) - } - - #[external(v0)] - fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlImpl::grant_role(ref unsafe_state, role, account); - } - - #[external(v0)] - fn revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlImpl::revoke_role(ref unsafe_state, role, account); - } - - #[external(v0)] - fn renounce_role(ref self: ContractState, role: felt252, account: ContractAddress) { - let mut unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControlImpl::renounce_role(ref unsafe_state, role, account); - } - - #[external(v0)] - fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - let unsafe_state = AccessControl::unsafe_new_contract_state(); - AccessControl::SRC5Impl::supports_interface(@unsafe_state, interface_id) - } -}