WEB3DEV

Cover image for Protegendo contratos inteligentes Solidity com Roles & Pausable
Adriano P. Araujo
Adriano P. Araujo

Posted on

Protegendo contratos inteligentes Solidity com Roles & Pausable

Como já sabemos, tudo nas blockchains como Ethereum, Polygon, BNB Chain e várias outras, é público, observável e os contratos inteligentes são interativos para qualquer pessoa, independentemente de quem seja.

Isso nos leva à questão de:

  • **Como posso proteger meus contratos inteligentes se literalmente qualquer um pode interagir com ele?

  • Como posso impedir que atores maliciosos explorem meus contratos inteligentes?**

A solução é com Roles & Pausable.

Neste artigo, mostrarei como proteger seus contratos inteligentes com a Roles & Pausable no  OpenZeppelin Contracts. O OpenZeppelin Contracts é uma biblioteca para o desenvolvimento seguro de contratos inteligentes, possui implementação de padrões como o ERC-20 e o ERC-721, e o mais importante é que foi auditado por várias empresas de segurança.

Por que é tão importante ter um contrato inteligente e seguro?

Imaginemos que você tenha um contrato inteligente para uma coleção de NFTs que você planeja comercializar e vender para colecionadores. As imagens dessa coleção de NFTs permanecerão ocultas até mais tarde, para evitar que os colecionadores adivinhem quais NFTs têm maior valor em termos de sua raridade e outras características.

Você planeja revelar as imagens em um mês através do contrato inteligente da NFT, mas antes de poder fazer isso, alguém descobriu que seu contrato inteligente não é seguro e encontrou uma maneira de revelar suas NFTs, agora todos podem ver as imagens reais das NFTs, o que levou os colecionadores a comprar apenas as NFTs mais raras da sua coleção, enquanto os outros estão sentados lá, coletando poeira, perdendo valor.

Essa é apenas uma das muitas maneiras pelas quais as pessoas podem explorar um contrato inteligente não seguro.

Então, como podemos garantir um contrato inteligente?

Como mencionado anteriormente, usaremos a biblioteca OpenZeppelin Contracts com nosso contrato inteligente, então criemos um arquivo .sol.

( Você pode fazer isso com seu IDE preferido ou apenas usar Remix Online IDE que permite implantar contratos inteligentes também. )

Vamos criar nosso contrato inteligente com o Padrão ERC-1155. Comecemos com uma base para o contrato…


// SPDX-License-Identifier: MIT

pragma solidity ^0.8.15;



import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";

import "@openzeppelin/contracts/access/AccessControl.sol";

import "@openzeppelin/contracts/security/Pausable.sol";



contract AccessControlWithRoles is ERC1155, AccessControl, Pausable {

   constructor() ERC1155("default") {}

}

Enter fullscreen mode Exit fullscreen mode

Estamos importando o ERC1155, contratos AccessControl & Pausable da biblioteca OpenZeppelin.

  • ERC1155 vem com funções como transferências em lote e transferências seguras

  • AccessControl permite atribuir e revogar funções a endereços de carteira, o que lhes concede permissão para executar determinadas funções em um contrato inteligente.

  • Pausable permite desativar funções em um contrato inteligente quando o contrato é pausado.

Agora adicionemos mais algumas linhas ao nosso contrato inteligente…


...



contract AccessControlWithRoles is ERC1155, AccessControl, Pausable {

    bytes32 public constant SECOND_ADMIN_ROLE = keccak256("SECOND_ADMIN_ROLE");



    uint256 private defAdminCount = 0;

    uint256 private secAdminCount = 0;

    uint256 private mintsLeft = 1000;



    constructor(

        address _defAdmin, 

        address _secAdmin

    ) ERC1155("default") {

        _setupRole(DEFAULT_ADMIN_ROLE, _defAdmin);

        _setupRole(SECOND_ADMIN_ROLE, _secAdmin);

    }

}



Enter fullscreen mode Exit fullscreen mode

Por padrão, o AccessControl vem com um administrador padrão chamado DEFAULT_ADMIN_ROLE, se você precisar de mais de um administrador ou função, precisará usar keccak256 ( ) para criar um novo.

Adicionamos algumas variáveis privadas com a qual faremos algo mais tarde. Também estamos atribuindo funções de administrador aos dois endereços da carteira analisados em nosso construtor.

Adicionemos algumas funções de gravação abaixo do método construtor…




// Permite que o Administrador Padrão pause o contrato

function pause() public onlyRole(DEFAULT_ADMIN_ROLE) {

_pause();

}



// Permite que o Administrador Padrão despause o contrato

function unpause() public onlyRole(DEFAULT_ADMIN_ROLE) {

_unpause();

}



// Incrementa a contagem de defAdminCount

function incDefAdminCount() public {

require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Não autorizado: você não tem a função DEFAULT_ADMIN_ROLE");

defAdminCount++;

}



// Incrementa a contagem de secAdminCount

function incSecAdminCount() public {

require(hasRole(SECOND_ADMIN_ROLE, msg.sender), "Não autorizado: você não tem a função SECOND_ADMIN_ROLE");

secAdminCount++;

}



// Decrementa mintsLeft

function mintNft() public whenNotPaused {

require(mintsLeft > 0, "Erro: Não há mais NFTs para serem criados");

mintsLeft--;

}



Enter fullscreen mode Exit fullscreen mode
  • Pause( ) permite que endereços com DEFAULT_ADMIN_ROLE pausem o contrato

  • unpause( ) permite que endereços com DEFAULT_ADMIN_ROLE despausem o contrato

  • incDefAdminCount ( ) incrementa a contagem de defAdminCount somente se o endereço tiver o papel de DEFAULT_ADMIN_ROLE

  • incSecAdminCount ( ) incrementa a contagem de secAdminCount somente se o endereço tiver o papel de SECOND_ADMIN_ROLE

  • mintNft ( ) permite que qualquer endereço o chame, desde que o contrato não seja pausado e que ** mintsLeft** seja maior do que 0.

Agora adicionaremos algumas funções de leitura para podermos ler nossas variáveis…


// Retorna defAdminCount quando chamado

function getDefAdminCount() public view returns (uint256) {

return defAdminCount;

}



// Retorna secAdminCount quando chamado

function getSecAdminCount() public view returns (uint256) {

return secAdminCount;

}



// Retorna mintsLeft quando chamado

function getMintsLeft() public view returns (uint256) {

return mintsLeft;

}



// Sobrescrita necessária pelo Solidity

function supportsInterface(bytes4 interfaceId)

public

view

override(ERC1155, AccessControl)

returns (bool)

{

return super.supportsInterface(interfaceId);

}

}



Enter fullscreen mode Exit fullscreen mode
  • getDefAdminCount ( ) retorna defAdminCount

  • getSecAdminCount ( ) retorna secAdminCount

  • getMintsLeft ( ) retorna mintsLeft

  • supportsInterface() é uma função de sobrescrita para o erro "Derived contract must override function 'supportsInterface'" que ocorrerá devido ao contrato AccessControl.

E esse é o nosso contrato inteligente, simples, mas conciso o suficiente para mostrar o que podemos fazer com o AccessControl & Pausable.

Implante contrato com o Remix Online IDE

Hora de implantar nosso contrato inteligente em uma rede.

Para fins deste tutorial, implantaremos nosso contrato na Polygon Testnet, Mumbai. Se você precisar de alguns MATIC para testes, você pode obter alguns na Alchemy’s Mumbai Faucet.

Após criar um arquivo .sol no Remix, você precisa primeiro Incorporar o arquivo antes de poder implantá-lo.

Clique com o botão direito do mouse no arquivo Solidity e selecione “ Flatten ”.

Após incorporado, você pode implantá-lo.

Selecione “ Fornecedor injetado — MetaMask ” para conectar-se à sua carteira MetaMask. Cole os endereços da carteira nos campos e clique em “ transact ” para implantar.

Um pop-up do MetaMask aparecerá para pedir para você confirmar a implantação do seu contrato.

Após implantado, você poderá ver o endereço do seu contrato na guia Contratos implantados, copie o endereço para poder procurar seu contrato em Mumbai Polygonscan.

Verificar e publicar contrato

Antes de podermos ler nosso contrato inteligente na Polygonscan, precisamos primeiro verificar e publicar.

Clique em “ Verify and Publish ” para publicar seu contrato

Cole o código incorporado na caixa e verifique. Após uma verificação bem-sucedida, você deve ver um link para visualizar seu contrato, clique nele.

Em seguida, em “ Contract ”, clique em “Write Contract ”.

Clique em getDefAdminCount, getSecAdminCount & getMintsLeft para ver cada um de seus valores. Eles devem ser 0, 0 e 1000, respectivamente.

Contrato de gravação

Clique em “Write Contract ” e clique em “ Connect to Web3” para conectar-se à sua carteira para poder começar a chamar suas funções de contrato.

Clique em “ Write ” para chamar as funções. Se sua carteira tiver a função correta, as transações deverão ser bem-sucedidas.

Suas transações falharão se você não tiver a função correta.

Você deve observar as alterações de valor em “Read Contract” se suas transações foram bem-sucedidas.

Isso foi para testarmos endereços com funções diferentes, agora vamos ver o que acontece quando nosso contrato é pausado.

Volte para “Write Contract"  e clique em “Write ” para a função mintNFT.

Como o contrato ainda não foi pausado, a transação deve ser um sucesso e & getMintsLeft deve decrementar por 1.

Agora pausemos o contrato executando a função pause em “Write Contract" e tente chamar a função mintNFT novamente.

As transações de  mintNFT devem falhar até que o endereço de administrador padrão desative o contrato novamente.

Pensamentos finais

Então aí está. É assim que você pode garantir melhor seus contratos inteligentes com a Roles & Pausable.

  • Com Roles, você pode ter certeza de que apenas pessoas com as permissões certas podem interagir com seus contratos inteligentes.

  • Com Pausable, você pode pausar seus contratos inteligentes a qualquer momento para impedir que as pessoas explorem mais uma brecha encontrada em seus contratos inteligentes.

A segurança sempre foi minha maior preocupação ao trabalhar com contratos inteligentes, espero que essas ideias o ajudem a escrever contratos inteligentes melhores no futuro.

Se você precisar do código-fonte, poderá encontrá-los aqui.

Obrigado pela leitura. Até a próxima vez! 👋


Este artigo foi escrito por   Erin Lim e traduzido por Adriano P. de Araujo. O original em inglês pode ser encontrado aqui.

Top comments (0)