Há muita empolgação em torno dos NFTs, e com razão. Com algumas linhas de código Solidity, você pode criar um token que representa a propriedade de uma obra de arte única (Twin Flames 2). Você pode até mesmo codificar essa obra de arte dentro do próprio código (Art Blocks). Os NFTs podem ser usados para registrar seu próprio nome .eth ou sinalizar a adesão a uma comunidade (BAYC). O futuro é promissor para os NFTs, e a tecnologia possui um imenso potencial para a criação de valor. No entanto, se esse valor vai perdurar, depende da segurança do contrato subjacente.
Neste tutorial, vou mostrar como você pode criar e implantar um contrato NFT, sem precisar mexer em uma única linha de código Solidity ou JavaScript, usando o Assistente de Contratos (Contracts Wizard) do OpenZeppelin. Você poderá gerenciar seu token através de uma carteira multisig (multiassinatura), usando o OpenZeppelin Defender para criar tokens e pausar a funcionalidade do contrato em caso de emergência.
Ao final deste tutorial, você terá seu próprio contrato NFT implantado. Mais importante, você também terá alguma experiência valiosa com conceitos importantes na implantação e administração segura de contratos.
Crie Três Contas
Primeiro, vamos dar uma olhada na questão da propriedade do contrato. Um contrato NFT simples pode ser implantado com qualquer conta de propriedade externa (EOA, Externally Owned Account). Por exemplo, você pode usar sua conta da Metamask para implantar um contrato e, em seguida, sua conta terá propriedade sobre esse contrato. Desde que ninguém roube suas chaves privadas e você nunca perca o acesso a essa conta, você será o único proprietário desse contrato e poderá executar qualquer função de administração que você atribuir a ele. No entanto, não é seguro que uma única EOA atue como administradora do contrato.
Uma prática mais segura é ter seu contrato inteligente de propriedade de uma carteira multisig. Pense em uma multisig como uma carteira de uma equipe que consiste em mais de uma conta. Frequentemente, a propriedade de uma carteira multisig seria distribuída para três a cinco indivíduos diferentes usando carteiras de hardware em locais diferentes, mas neste caso, por simplicidade, você criará três contas Metamask e permanecerá o único proprietário de todas elas. Uma carteira multisig de três contas fornece uma camada adicional de segurança quando você especifica que duas das três contas em sua multisig devem aprovar uma transação específica.
Para uma multisig de três contas, você precisará ter três contas separadas. É fácil criar uma nova conta na Metamask clicando na imagem da sua conta e selecionando “Criar Conta”. Depois de fazer isso três vezes, você está pronto para prosseguir.
Observação importante de segurança: é uma boa prática durante o desenvolvimento usar uma carteira diferente e até mesmo um navegador diferente daquele que você normalmente usa para fazer transações na Ethereum. Mesmo que a Rinkeby seja uma rede diferente da rede principal (mainnet), sua chave privada da Rinkeby é a mesma que sua chave privada da rede principal. Se você vazar acidentalmente sua chave privada durante o desenvolvimento, provavelmente perderá todos os ativos de propriedade dessa carteira. Portanto, usar um navegador diferente e contas completamente diferentes é algo que vale a pena fazer.
Nota do tradutor: Após o “The Merge” da Ethereum, a rede de testes (testnet) Rinkeby foi descontinuada. Substitua por uma das redes de testes da Ethereum atualmente disponíveis, Goerli ou Sepolia.
Obtenha ETH da Rede de Testes
Custa gás para armazenar dados na blockchain. Você precisará pagar por isso em ETH. Felizmente, como você usará uma rede de testes, poderá usar o ETH da rede de testes, que pode ser obtido gratuitamente através de uma torneira (faucet).
Uma torneira é um contrato inteligente que envia uma quantidade predeterminada de ETH para qualquer contrato que o chame. Apenas uma de suas três contas precisará ser financiada com ETH. Depois de obter seu ETH de uma torneira, você está pronto para a próxima etapa.
Eu montei uma lista de torneiras Rinkeby aqui.
Crie uma Conta Multisig na Gnosis (Gnosis Safe) e Gerencie com o Defender
O OpenZeppelin Defender é uma plataforma de operações de segurança (SecOps) para desenvolvimento na Ethereum. Neste tutorial, você irá usá-lo para gerenciar sua conta multisig e executar funções de administração em seu contrato implantado.
Acesse defender.openzeppelin.com. Se você ainda não tiver uma conta, precisará se inscrever. A conta gratuita oferecerá muitas funcionalidades, que exploraremos mais em tutoriais futuros.
- Depois de fazer login, você verá algumas opções na barra de navegação à esquerda. Selecione “Admin” --> “Add Contract” (adicionar contrato) --> “Create Gnosis Safe” (criar Gnosis Safe).
- Na Metamask, selecione a rede Rinkeby.
- Clique em “Conectar Carteira” e selecione uma conta que possua ETH de teste que você obteve da torneira.
- Dê o nome que quiser à sua carteira multisig e selecione a rede Rinkeby.
- Em “Owners” (proprietários), você precisará adicionar o endereço de cada uma das suas três contas da Metamask. Para fazer isso, selecione uma conta na Metamask, copie o endereço, cole-o no Defender e selecione “Add Owner” (adicionar proprietário). Repita este passo para cada conta da Metamask.
- Defina o “Threshold” (limite mínimo de contas) para 2.
- Clique em “Create Gnosis Safe”.
- Cada conta conectada ao Defender precisará confirmar a transação.
Quando vir a mensagem "Transaction Confirmed" (Transação confirmada), você pode clicar em “Go to Safe” (ir para o Gnosis Safe) para ver os detalhes de sua carteira multisig. Mais tarde neste tutorial, você irá transferir a propriedade do seu contrato NFT para esta conta.
Observação importante de segurança: neste tutorial, a carteira multisig de três contas tem um threshold de 2, o que significa que 2 das três contas devem aprovar qualquer transação para que ela seja executada. Uma multisig de 2 de 3 é mais segura do que uma EOA. Definir um limite de 1 seria menos seguro do que uma EOA, pois se qualquer uma das contas fosse comprometida, uma transação poderia ser aprovada em nome da multisig.
Consulte o Assistente
O Assistente de Contratos do OpenZeppelin permite que você inicie o desenvolvimento rapidamente, fornecendo códigos Solidity pré-construídos a partir da versão mais recente dos contratos seguros do OpenZeppelin, com base nas seleções que você fizer. Você pode pegar esse código e exportá-lo para o Remix ou baixá-lo para trabalhar localmente.
Acesse wizard.openzeppelin.com para prosseguir.
Com esta ferramenta, você pode criar contratos de token fungíveis ERC20, NFTs ERC721, contratos multitoken ERC1155 e contratos de governança (Governor) para gerenciar uma DAO. Como você está criando um NFT, poderá selecionar ERC1155 ou ERC721. Para este tutorial, selecionaremos ERC721.
O Assistente de Contratos oferece várias opções importantes específicas para o padrão de contrato escolhido, para que você possa começar a funcionar simplesmente fazendo suas seleções desejadas no painel esquerdo.
Nas Configurações, dê ao seu token o nome e símbolo que desejar.
Você pode ignorar Base URI por enquanto, já que não usará seu token para apontar para nenhum metadado neste tutorial.
Sobre metadados: os metadados do token são um tópico em particular, então dedicaremos um tutorial futuro a esse aspecto do desenvolvimento de NFTs. Para este tutorial, o foco é na propriedade e administração seguras do contrato. Este é um bloco de construção muito importante para lidar responsavelmente com código imutável em uma blockchain pública descentralizada.
Em “Features” (recursos), selecione “Mintable” (cunhável), para que você possa criar novos tokens chamando uma função de cunhagem.
Agora, vamos considerar o controle de acesso ao token. As dicas do Assistente de Contratos são muito úteis para explicar a ideia principal aqui. Você precisa de alguma forma de controle de acesso para responder à pergunta muito importante de quem pode ser dono e chamar qual função. Ownable (de propriedade) é uma regra simples para controle de acesso.
Por padrão, o Controle de Acesso é definido como Ownable e o nosso contrato é definido para importar o Ownable.sol. Você notará no código que há um modificador onlyOwner em funções públicas, o que significa que apenas o endereço que criou o contrato pode chamá-las. O endereço do criador do contrato é armazenado como proprietário do contrato pelo construtor quando o contrato é criado e gravado na blockchain. Posteriormente, você atualizará a propriedade do contrato executando uma função para transferir a propriedade para sua conta multisig.
Além do modificador onlyOwner, tornar o contrato Ownable oferece outras funções que você pode usar, como renounceOwnership (renunciar propriedade) e transferOwnership (transferir propriedade). Essas funções podem ser chamadas pelo proprietário existente para mudar permanentemente qual conta o contrato considera como seu proprietário.
Por que um usuário iria querer renunciar à propriedade de um contrato? Dependendo do contrato, renunciar à propriedade pode ser feito como um sinal de boa fé de que o contrato não está em risco de ser manipulado por algum administrador intrometido. O contrato ainda existiria, os tokens ainda poderiam ser livremente transferidos e as variáveis de estado públicas ou externas do contrato ainda poderiam ser consultadas. Em resumo, quaisquer funções externas ou públicas não restritas pelo modificador onlyOwner poderiam ser chamadas.
Selecione IDs de incremento automático, para que cada vez que um token for cunhado com sucesso, o contrato mantenha o registro do número total de tokens cunhados. Você pode ver isso acontecendo com a importação do Counters.sol e com o código adicionado à função safeMint.
Em seguida, vamos olhar para a questão da pausabilidade. Selecionar “Pausable” adiciona as funções pause e unpause, bem como uma verificação que ocorre ao usar o modificador whenNotPaused na transferência de tokens. Por padrão, paused é definido como false. Pausar um contrato afeta a transferência de tokens porque a função adicionada, _beforeTokenTransfer, é executada quando alguém deseja transferir um token.
Por que considerar a implementação disso? Como mencionado, se algo catastrófico ocorrer, a pausa permite que você desative a funcionalidade de transferência de token até que o contrato seja despausado.
Claro, por uma questão de transparência, seria uma boa ideia alertar seus usuários sobre o problema, mas isso é outra questão.
Voltando um passo, a capacidade de pausar o contrato nos faz considerar o que realmente acontece durante a transferência de um token. Sua carteira digital não é como uma carteira física com dinheiro fiduciário. Quando você possui um NFT, esse NFT nunca é transferido para sua carteira. É mais preciso dizer que sua carteira contém sua chave privada e sua capacidade de assinar transações. A propriedade de um NFT acontece em virtude de sua chave pública ser armazenada no contrato inteligente ao qual o NFT pertence, em um mapeamento de endereço para ID de token.
Sinta-se à vontade para experimentar várias funcionalidades para ver o que é adicionado ou modificado no código fornecido pelo Assistente de Contratos.
Sobre a possibilidade de atualização: o Remix atualmente não funciona para implantar contratos atualizáveis. A possibilidade de atualização de contratos realmente amplia a visão das coisas, então, em um tutorial futuro, você criará um contrato atualizável, trabalhando localmente usando o VS Code e o Hardhat.
Você notará que há um espaço para um Contato de Segurança. É uma boa ideia incluir isso agora, pois você não poderá editar seu contrato depois que ele for implantado. No caso de você querer adicionar qualquer serviço de monitoramento ou alerta posteriormente, isso permitirá que seu contrato seja registrado com esse serviço depois que seu código for verificado.
Neste ponto, você deve dar um passo atrás e olhar para o que tem aqui. É seguro, é incrível e apenas exigiu um pouco de reflexão sobre quais recursos gostaríamos que seu contrato NFT tivesse.
Importe para o Remix
Quando estiver pronto, basta clicar em "Open in Remix", e tudo será importado para o Remix. O Remix é um IDE do Solidity genuíno, então, uma vez que seu código estiver importado aqui, você poderá adicionar coisas a ele ou alterá-lo. No entanto, como o Assistente deixou tudo organizado, deixe como está.
Faça a Compilação
Compilar o código torna possível implantá-lo na blockchain.
Na esquerda, certifique-se de que o compilador corresponda à versão do Solidity especificada por sua declaração pragma, ou seja, uma versão mais recente, e clique em "Compile contract-{alguns caracteres alfanuméricos}.sol".
O código será compilado e você verá algumas novas opções à esquerda. Abaixo, você verá um link para copiar a ABI e o bytecode. Não o usaremos aqui, mas se você estiver construindo um frontend para interagir com seu contrato inteligente, precisará da ABI do contrato, que é essencialmente uma API usada por uma biblioteca, como a ethers.js.
Faça a Implantação
Implantar nosso código envia uma transação para gravá-lo na blockchain.
Na barra de ferramentas do Remix, selecione “Deploy & Run Transactions” (Implante e Execute Transações).
Vamos considerar os diferentes ambientes por um momento. Se deixarmos como JavaScript VM, não custará nada para implantar, mas também não existirá fora do Remix. Essa opção é ótima para testes iniciais e experimentação, mas estamos prontos para implantar nosso código em uma rede de testes pública. Uma rede de testes pública é uma blockchain genuína com mineradores e taxas de gás, com uma diferença importante: o ETH da rede de testes não tem valor real no mundo real. Se você cometer um erro em uma rede de testes e precisar reimplantar o contrato, isso não o afetará financeiramente.
Nota do tradutor: Após o “The Merge”, as transações da Ethereum não são mais mineradas pelo protocolo de consenso de Prova de Trabalho (PoW, Proof-of-Work). As transações da Ethereum atualmente são validadas pelo protocolo de consenso de Prova de Participação (PoS, ou Proof-of-Stake).
Em primeiro lugar, verifique se está usando uma carteira Metamask usada apenas para desenvolvimento. Esta deve ser a mesma carteira que você preencheu com uns ETHs da Rinkeby anteriormente. Em sua carteira Metamask, verifique se você está na rede Rinkeby.
Em “Environment” (Ambiente), selecione “Injected Web3”. Ao fazer isso, a Metamask se conectará ao site.
Depois de conectado, você verá a chave pública da sua conta exibida em “Account”.
As coisas estão ficando animadas! Vamos aproveitar esta oportunidade para nos aprofundarmos no que está acontecendo nos bastidores quando se trata de declarações de importação em contratos. Embora tudo o que vemos inicialmente seja a linha adicional de código na parte superior, há mais coisas acontecendo aqui, e isso explica de onde vem a funcionalidade adicional.
Em “Contracts”, clique no menu suspenso. Na parte inferior, você verá seu contrato de token ERC721. Mas de onde vieram todos esses outros contratos? Eles são as importações especificadas na parte superior do contrato, juntamente com todas as suas dependências necessárias. Na prática, você pode considerar seu contrato como se ele estivesse incluindo cada um desses contratos primeiro, tudo em um longo megacontrato.
Você notará que Ownable aparece no topo da lista, mas queremos implantar nosso token, não apenas Ownable, portanto, certifique-se de selecionar o contrato do seu token. Quando você implantá-lo, todas as importações e dependências serão implantadas na mesma transação.
Ao selecionar “Deploy”, você será solicitado a confirmar a transação na Metamask e pagar pelo gás.
Na parte inferior da tela, o Remix informa que a transação está sendo minerada e quando ela é confirmada. Ele inclui detalhes como o bloco, o endereço de implantação, etc. Você pode selecionar "view on etherscan" (veja no etherscan) para ver todos os detalhes desta transação específica.
No Etherscan, o endereço "From" mostra o endereço que você acabou de usar para implantar o contrato. Selecionar esse endereço mostrará quaisquer transações anteriores feitas por esse endereço, indexadas pelo Etherscan.
O endereço "To" é o endereço do contrato implantado.
Você também pode visualizar o contrato voltando para o Remix, clicando no botão para copiar o endereço onde diz "Deployed Contracts" (Contratos Implantados) e inserindo-o na caixa de pesquisa do Rinkeby Etherscan.
Verificação do Contrato
Contratos verificados são aqueles que tornam seu código-fonte facilmente acessível para qualquer pessoa que os procure no Etherscan. Verificar um contrato também permite que os usuários executem quaisquer funções de leitura/escrita publicamente disponíveis diretamente do Etherscan. Embora a verificação do código-fonte não seja necessária, definitivamente é uma boa prática.
Para fazer isso no Remix, você precisará primeiro adicionar o plugin de verificação de contrato do Etherscan clicando no plugue localizado no canto inferior esquerdo. Procure pelo Etherscan e instale-o. Depois de instalado, selecione o plugin de verificação de contrato do Etherscan no painel de navegação à esquerda.
Você precisará de uma chave de API do Etherscan, que pode ser obtida acessando etherscan.io e criando uma conta. Depois de fazer login, você verá, em um menu suspenso sob o seu ID de usuário, um link para as chaves de API.
Depois de ter sua chave de API criada e copiada, volte para o Remix e cole-a. Em seguida, selecione seu contrato de token a partir do menu suspenso. (Você não precisa incluir quaisquer argumentos do construtor.) Cole o endereço do contrato implantado. Você pode encontrá-lo no Etherscan, no campo "To:" da transação anterior. Você também pode encontrá-lo no Remix na seção “Deploy” em “Deployed Contracts”.
Interagindo com o seu Contrato Verificado no Etherscan
Volte para o Etherscan e selecione “Contract”. Você verá o código-fonte completo do seu contrato junto com todos os contratos importados. Como seu contrato foi verificado, você também ganha a capacidade de ler e escrever no contrato. Selecionar “Read Contract” (Ler Contrato) mostra as funções que você pode chamar em seu contrato que não custam gás.
Selecionar “Write Transactions” (Gravar Transações) mostra as funções que exigem que você conecte sua carteira e pague pela transação, porque elas mudam o estado da blockchain.
O Etherscan fornece a contratos verificados esta interface muito minimalista para transacionar com contratos implantados e verificados. É minimalista, mas suficiente para executar as mesmas transações às quais você usaria o ethers.js ao desenvolver um aplicativo web completo.
Neste momento, consultar estas funções não nos dirá nada muito interessante. Não emitimos nenhum token. Vamos voltar para o Defender para essa parte.
Importando o Contrato no Defender
O Defender é uma ferramenta incrível para trabalhar com contratos implantados. Para começar o processo, precisamos importar o contrato para o Defender. "Importar um contrato" não faz nenhuma mudança no próprio contrato. Em vez disso, pense no Defender como uma ferramenta para chamar as funções de um contrato. Na verdade, é igualmente possível importar qualquer contrato verificado no Defender, independentemente de ser de sua propriedade ou não. Afinal, é uma blockchain pública!
Volte para o Defender e selecione “Admin”. Você verá a conta multisig criada anteriormente. Vamos usá-la em breve.
Selecione “Add Contract” → “Import a New Contract” no canto superior direito.
Você pode nomeá-lo como quiser. Por simplicidade, é uma boa ideia dar o mesmo nome que foi dado ao contrato implantado.
Selecione “Rinkeby” e cole o endereço do contrato implantado. Lembre-se: você pode encontrar o endereço do contrato através do Etherscan como o campo To: da transação mais recente de sua carteira ou no Remix em “Deployed Contracts”.
Como o contrato foi verificado, o Defender carrega automaticamente a ABI e detecta que seu contrato é Pausable, o que significa que você pode usar o Defender para pausar seu contrato se quiser.
Transferindo a Propriedade para a Multisig
Atualmente, o contrato do NFT tem o endereço da carteira que você usou para implantá-lo como seu proprietário atual.
A propriedade da carteira multisig é mais segura, então vamos transferir a propriedade para a multisig criada anteriormente. Para fazer isso, selecione “New Proposal” (Nova Proposta) e depois “Admin Action” (Ação de Administrador).
Aqui, no lado direito da tela, você pode ver o estado atual do contrato. Ele não está pausado, o proprietário é o endereço da sua carteira e o totalSupply é zero, pois ainda não cunhamos nenhum token.
Clique no menu suspenso “Function” e selecione transferOwnership. Em “newOwner”, selecione o nome que você deu à carteira multisig.
Abaixo disso, você verá “Execution Strategy” (Estratégia de Execução). O que é isso, você pergunta? O Defender está simplesmente perguntando como você gostaria que essa transação acontecesse.
Se o seu contrato fosse de propriedade de um contrato de governança, como em uma DAO, você selecionaria “Governor”, para que as transações fossem executadas se passassem em uma votação. Normalmente, isso seria feito em conjunto com um timelock (bloqueio de tempo), que aplica um atraso pré-definido na execução da transação. Para isso, você selecionaria “Timelock”.
Não estamos usando um timelock ou um governor, então nossa estratégia de execução é bem simples.
Em geral, se você alguma vez se deparar com algo que te deixou confuso, pesquise a documentação, e a resposta provavelmente estará lá. No Defender, você encontrará um link para isso na parte inferior esquerda.
Selecione “EOA” para contas de propriedade externa. Verifique se a mesma carteira usada para implantar o contrato está atualmente conectada ao Defender e configurada para a rede Rinkeby. Como essa conta é a proprietária do contrato, temos a capacidade de executar essa função onlyOwner. Após a transferência de propriedade, somente a conta multisig poderá executar esses tipos de funções.
Abaixo do título da proposta, dê uma descrição amigável para deixar claro o que você pretende realizar aqui. "Transferir a propriedade para a multisig" seria suficiente.
Selecione “Create admin action” e você verá que esta transação (com o título amigável que você acabou de fornecer) está pendente de aprovação.
Esta tela é um pouco como visualizar seu carrinho de compras antes de realmente fazer uma compra. Isso é bom, já que transferir a propriedade é uma decisão significativa.
Selecione “Approve and Execute”. Você terá que assinar (e pagar) a transação na Metamask, e então ela será executada. No futuro, ao executar transações para este contrato, você ainda precisará usar a Metamask, mas o processo será um pouco diferente, já que o contrato agora é de propriedade de uma multisig.
Faça a Cunhagem de um Token
Para cunhar um token usando o Defender, você executará outra ação de administrador.
Selecione “Admin” → {Seu contrato NFT}.
Em Proposals, você verá a transação de transferência de propriedade que acabou de ser executada.
Selecione “New Proposal” → “Admin action”.
Em “Function”, selecione safeMint. Você cunhará um token para o proprietário anterior do contrato para agradecer por implantar o contrato.
Para a estratégia de execução, selecione “Multisig” junto com a conta multisig gerenciada pelo Defender, que é o proprietário atual.
O Defender nos mostra que sua multisig tem três endereços e que você precisa de pelo menos dois para aprovar a transação para que ele passe.
Descreva a proposta como sua primeira cunhagem e selecione “Create admin action”.
Na próxima tela, revise a ação do administrador e selecione “Approve”.
Para realmente fazer essa transação multiassinatura acontecer, você precisará assinar a transação com duas das três contas pertencentes à multisig. Contas pertencentes a uma determinada multisig podem ser carteiras em qualquer lugar do mundo. Acontece que aqui você está gerenciando todas elas em um só lugar.
Na Metamask, mude para uma conta na multisig, selecione “Aprovar”, assine, mude para a segunda conta, assine e selecione “Approve and Execute”. (Uma vez que a transação tenha sido assinada por dois, ela pode ser executada por qualquer pessoa, incluindo a conta que acabou de assinar.)
Você cunhou com sucesso seu primeiro token. Para ver isso na blockchain, selecione o endereço do contrato e cole-o no Etherscan da Rinkeby (ou simplesmente passe o mouse sobre o endereço do contrato e selecione “View in Block Explorer” (Veja no Explorador de Blocos)).
Em “Transactions”, observe a transferência de propriedade.
Em "Internal Txns" você verá a transação de cunhagem dos tokens. Selecionando a transação principal, você será direcionado para os detalhes da transação, onde poderá ver que “Tokens Transferred” (Token Transferido) foi o ID de token “zero” para o mesmo endereço que implantou o contrato.
Parabéns! Você conseguiu implantar um contrato ERC721, transferir a propriedade para uma multisig e criar um token para uma conta externa. A partir daqui, sinta-se à vontade para experimentar mais com o Defender. Veja o que acontece se você pausar sua função e tentar criar outro token.
Artigo original escrito por Stephen Lloyd Webber. Traduzido por Paulinho Giovannini.
Latest comments (0)