Lição 065: Padrões de Controle de Acesso
No mundo dos contratos inteligentes, garantir que apenas usuários autorizados possam realizar ações específicas é fundamental. Padrões de controle de acesso são essenciais para estabelecer permissões e restringir o acesso a funções sensíveis. Esta lição explorará vários padrões comuns de controle de acesso em Solidity.
1. Controle de Acesso Básico com onlyOwner
Uma das formas mais simples de controle de acesso é restringir o acesso a determinadas funções ao proprietário do contrato. Isso pode ser realizado utilizando o padrão Ownable
.
Exemplo:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
contract ControleAcessoBasico is Ownable {
string public mensagemSecreta;
function definirMensagemSecreta(string memory _mensagem) public onlyOwner {
mensagemSecreta = _mensagem;
}
function visualizarMensagemSecreta() public view returns (string memory) {
return mensagemSecreta;
}
}
Neste exemplo:
- O contrato
ControleAcessoBasico
herda do contratoOwnable
da biblioteca OpenZeppelin. - A função
definirMensagemSecreta
só pode ser chamada pelo proprietário do contrato, enquanto qualquer pessoa pode chamarvisualizarMensagemSecreta
.
2. Múltiplos Proprietários com o Padrão Multisig
Utilizar múltiplos proprietários pode aumentar a segurança e a descentralização. O padrão de assinatura múltipla (multisig) permite que um grupo de contas controle um único contrato.
Exemplo:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MultiAssinatura {
address[] public proprietarios;
mapping(address => bool) public ehProprietario;
uint8 public necessários;
constructor(address[] memory _proprietarios, uint8 _necessários) {
require(_proprietarios.length > 0, "Deve ter proprietários");
require(_necessários > 0 && _necessários <= _proprietarios.length, "Número de proprietários necessários inválido");
for (uint8 i = 0; i < _proprietarios.length; i++) {
require(!ehProprietario[_proprietarios[i]], "Proprietário duplicado");
ehProprietario[_proprietarios[i]] = true;
}
proprietarios = _proprietarios;
necessários = _necessários;
}
modifier apenasProprietarios() {
require(ehProprietario[msg.sender], "Não é um proprietário");
_;
}
}
Neste exemplo, o contrato MultiAssinatura
permite que vários proprietários sejam designados. Funções podem ser adicionadas que requerem um determinado número de proprietários para aprovar ações.
3. Controle de Acesso Baseado em Funções
Para aplicações mais complexas, um padrão de controle de acesso baseado em funções (RBAC) pode ser usado. Isso permite permissões diferentes para diferentes funções.
Exemplo:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/AccessControl.sol";
contract ControleAcessoPorFuncoes is AccessControl {
bytes32 public constant ROLE_ADMIN = keccak256("ROLE_ADMIN");
bytes32 public constant ROLE_MINTER = keccak256("ROLE_MINTER");
constructor() {
_setupRole(ROLE_ADMIN, msg.sender);
_setupRole(ROLE_MINTER, msg.sender);
}
function mint(address to) public onlyRole(ROLE_MINTER) {
// Lógica de mintagem
}
function concederRoleMinter(address conta) public onlyRole(ROLE_ADMIN) {
grantRole(ROLE_MINTER, conta);
}
function revogarRoleMinter(address conta) public onlyRole(ROLE_ADMIN) {
revokeRole(ROLE_MINTER, conta);
}
}
No contrato ControleAcessoPorFuncoes
:
- Funções são definidas utilizando constantes
bytes32
. - O
ROLE_ADMIN
pode conceder ou revogar funções, enquanto oROLE_MINTER
pode criar novos tokens. - Este padrão é muito flexível e permite futuras melhorias nas funções.
4. Controle de Acesso Pausável
Em certas situações, pode ser necessário pausar a funcionalidade do contrato em emergências. O padrão Pausable
pode facilitar isso.
Exemplo:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract ControleAcessoPausavel is Pausable, Ownable {
function realizarAcao() public whenNotPaused {
// Lógica da ação que pode ser pausada
}
function pausar() public onlyOwner {
_pause();
}
function despausar() public onlyOwner {
_unpause();
}
}
No contrato ControleAcessoPausavel
:
- O contrato pode ser pausado ou despausado pelo proprietário.
- A função
realizarAcao
só pode ser executada quando o contrato não está pausado.
Conclusão
O controle de acesso é um aspecto fundamental da segurança em contratos inteligentes. Esta lição apresentou padrões essenciais de controle de acesso, incluindo propriedade básica, multisig, controle baseado em funções e contratos pausáveis. Ao implementar cuidadosamente esses padrões, os desenvolvedores podem melhorar significativamente a segurança e a funcionalidade de seus contratos inteligentes. Explore esses padrões e aplique-os judiciosamente para proteger seus projetos no espaço descentralizado.