Popular tags

    How to use Access Control in Cairo language securely?


    5 months ago




    How to use Access Control in Cairo securely? What library can I use for implementing it?

      cairosecurityaccess control



    5 months ago

    1 answers


    Accepted answer

    The first rule in access control is the principle of least privilege which states that users should have the minimum necessary privileges required to do their job. This can often be difficult to implement in smart contracts, as it would require managing many different accounts, therefore it is common to see the privileged functions of a smart contract being protected by at least an owner role, which ideally is secured by a multi-signature wallet.

    With Cairo, we have two main libraries which can be used to implement access control (both provided to us by OpenZeppelin):

    It is important to ensure that the roles implemented fit the purpose of the protocol, and have the least possible amount of privileges. Furthermore, use of multi-signature wallets where appropriate is highly encouraged.

    For instance, if we were to implement a custom ERC20 contract, we could implement the following roles:

    • Owner or Admin - Owns the contract and can transfer ownership/assign roles to others as well as perform other management activity
    • Minter - Can mint new tokens
    • Pauser - Can pause the contract
    • Upgrader - Can upgrade the contract (in case of an upgradeable contract)

    As mentioned above, we have two options for this, either use Ownable or AccessControl. For impementing more roles, it makes more sense to use AccessControl, as otherwise we would have to make amendment to the Ownable library, which is not recommended.

    With AccessControl, we can set arbitrary roles, and have them verified in a similar fashion. In this case, we will set the admin role in the constructor of our contract, just after initializing the library. Now that we have an admin role, we can use it to set all other roles. Let's try and implement a minter role:

    @external func grantRole{ syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr }(role: felt, user: felt) { AccessControl.grant_role(role, user); return (); }

    And then protect our mint function to only allow the minter to call it, using a modifier which looks like the one below:

    func assert_only_role{ syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr }(role: felt) { alloc_locals let (caller) = get_caller_address(); let (authorized) = has_role(role, caller); with_attr error_message("AccessControl: caller is missing role {role}") { assert authorized = TRUE; } return (); }

    And this is our code with the new added check:

    @external func mint{ syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr }(to: felt, amount: Uint256) { let (caller) = get_caller_address(); AccessControl.assert_only_role(120299592115570, caller); ERC20._mint(to, amount); return (); }

    And this should fail if the caller does not have the minter role.



    5 months ago

    Your answer