Curso de OpenZeppelin

Curso de OpenZeppelin

Sebastián Leonardo Perez

Sebastián Leonardo Perez

Control de acceso basado en roles

3/19
Recursos

Aportes 5

Preguntas 1

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Por acá dejo un contrato donde pongo a prueba todo lo explicado en la clase y algunas cosas adicionales que entendí en la documentacion

También hice unos unit tests para probar los distintos casos de uso del contrato. Creo les puede interesar verlos tambien:

Pueden correr los unit tests con hardhat: npx hardhat test

Cuando el profe se refiere a la cuenta de admin por default del contrato (cuenta cero) es que el rol de admin se asigna a esta dirección:

0x0000000000000000000000000000000000000000000000000000000000000000

Me imagino que esta dirección es a la que se le asigna el rol de owner cuando renuncias a él (clase pasada Ownable.sol). Si desplegamos el contrato sin el constructor (sin la asignación inicial) va a quedar inutilizable.

Parece ser que la diferencia entre…

_grantRole()
_setupRole()

Es que _serutRole() no requere que quien llame a la función tenga el rol de admin, pero si es necesario con _grantRole()

Definir roles suena a centralizar actividades o cosas, no sé si por ahí exista algún ejemplo para poder ver cómo los aplican en la producción.

Por otro lado, es interesante ver cómo en solidity todo es estados y más estados, se juega mucho con reglas lógicas y hay que poner atención a lo que hacemos o podríamos dejar una puerta abierta que algún usuario malicioso podría explotar.

El contrato de Access Control

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControl.sol)

pragma solidity ^0.8.0;

import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";


abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;


    modifier onlyRole(bytes32 role) {
        _checkRole(role, _msgSender());
        _;
    }


    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }


    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }


    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(uint160(account), 20),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }


    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }


    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }


    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }


    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }


    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }


    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }


    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }


    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}