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") {}
}
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);
}
}
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--;
}
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);
}
}
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.
Oldest comments (0)