Bootcamp — NFT Dinâmicos com Truffle e Chainlink Automation — Parte 1

Lucas Archangelo
11 min readMar 15, 2023

--

Fala pessoal, tudo bom? Nesse tutorial eu vou mostrar para vocês como criar um NFT Dinâmico utilizando a ferramenta Truffle e a solução Chainlink Automation.

O que é um NFT?

NFT é a sigla para "non-fungible token" (em português token não -fungível), NFTs são tokens digitais com características únicas, que estão armazenadas dentro de uma rede como a Ethereum por exemplo.
Esses tokens podem representar entre obras de artes, tickets para acesso exclusivo a algum conteúdo/evento ou até mesmo um personagem de um jogo de computador. Se você entrar em sites de venda de NFT (como a opensea), você vai perceber a variedade de NFTs que são criados na rede.

Qual a diferença de um NFT normal e um NFT dinâmico?

NFTs ganham vida à partir do momento que você determina os metadatas, que é um arquivo .json onde utilizando uma estrutura padrão para ele você determina características como nome, prazo de validade, idade, força inclusive você pode determinar uma imagem para ser apresentado. Dependendo da forma que você desenvolve seu NFT essa informação torna-se imutável, e uma vez criado ele nunca mais pode ser alterado em termos de características. NFTs dinâmicos te da a flexibilidade de mudar essas informações mesmo após ele ser criada na rede, sendo possível aumentar o level do seu personagem adicionar um novo atributo, mudar o status de um ticket como usado entre outros.

Para que serve a Chainlink Automation

Chainlink Automation é uma solução da Chainlink labs para realizar automatizações em seus processos com contratos inteligentes, utilizando essa solução você consegue definir triggers seja por tempo ou por lógica, para que uma ação seja executada. Por exemplo digamos que você queria premiar todos os seus usuários que estejam em uma pool stake do seu token todo mês, com essa solução você poderia definir essa regra e deixar executando sempre que a lógica ou tempo retornar verdadeiro.

Mãos a obra

Vou separar as atividades em 2 etapas:

  1. Configurar o ambiente, criar um contrato HelloWorld e deployar e verificar o contrato na rede de teste da polygon.
  2. Com todas as configurações realizadas, vamos criar a NFT dinamica e configurar a Chainlink Automation. Caso você ja tenha feito a primeira parte Clique Aqui.

Configurando o ambiente

Você vai precisar de algumas ferramentas no seu computador para que seja possível rodar esse projeto.

  1. Metamask — instale o plugin da metamask e crie uma seed para ela (guarda essa seed, pois vamos utilizar mais pra frente).
  2. Adicionar a rede Mumbai na sua carteira — após entrar no site, procure pelo botão "Add Mumbai Network" que fica na parte inferior do direito do site.
  3. Faucets na Mumbai — Após abrir esse site, copie o endereço da sua wallet pela metamask e jogue ele no campo Wallet Address, após fazer isso clique em submit.
  4. Nodejs — Instale a versão LTS 18.15.0 que é a versão compatível com o truffle.
  5. Truffle — execute o comando "npm install truffle -g" no prompt de comando do seu sistema operacional
  6. Ganache — execute o comando "npm install ganache -g" no prompt de comando do seu sistema operacional
  7. Git — Instale a ultima versão do GIT disponível para o seu sistema operacional

Criando o primeiro projeto com truffle

Com todo ambiente devidamente configurado, vamos começar a criar nosso projeto é só seguir os passos abaixo:

Crie uma pasta nova para o seu projeto, eu vou chamar a minha de helloWorld, abra o prompt de comando e entre na pasta que você acabou de criar.

Execute os comandos abaixo exatamente nessa sequência no seu prompt dentro da pasta que você acabou de criar.

truffle init
npm init -y
npm install @truffle/hdwallet-provider dotenv truffle-plugin-verify

Quando você rodar todos os comandos (alguns podem demorar um pouquinho), você vai ter uma estrutura de pastas como essa.

Daqui em diante, eu vou utilizar o meu IDE favorito, que é o VSCode, mas fiquem a vontade de utilizar o que você mais gostar, após abrir meu projeto no VSCODE ele ficou assim.

Eu estou utilizando 3 plugins no meu Vscode caso queira deixar igual:

  1. Javascript and Typescript Nightly
  2. Solidity de Juan Blanco
  3. vscode-icons

Vamos criar um contrato HelloWorld apenas para testar se tudo que precisamos está devidamente configurado.

Copie esse contrato dentro da pasta "contracts", com o nome HelloWorld.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract HelloWorld {

string public helloWorld;

constructor(string memory _helloWorld){
helloWorld = _helloWorld;
}

function getHelloWorld() public view returns (string memory _helloWorld) {
return helloWorld;
}

function setHelloWorld(string memory _helloWorld) public {
helloWorld = _helloWorld;
}
}

Copie esse script dentro da pasta "migrations" com o nome 1_hello_world.js

const HelloWorld = artifacts.require("HelloWorld");

module.exports = async function (deployer, _network, accounts) {
await deployer.deploy(HelloWorld, "Lucas Ramos Archangelo");
}

Atualize o seu arquivo truffle-config.js substituindo ele inteiro por esse aqui.

/**
* Use this file to configure your truffle project. It's seeded with some
* common settings for different networks and features like migrations,
* compilation, and testing. Uncomment the ones you need or modify
* them to suit your project as necessary.
*
* More information about configuration can be found at:
*
* https://trufflesuite.com/docs/truffle/reference/configuration
*
* To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider)
* to sign your transactions before they're sent to a remote public node. Infura accounts
* are available for free at: infura.io/register.
*
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
* phrase from a file you've .gitignored so it doesn't accidentally become public.
*
*/

require("dotenv").config();

const mnemonic = process.env["MNEMONIC"];
const POLYGONSCANAPIKEY = process.env["POLYGONSCANAPIKEY"];

const HDWalletProvider = require("@truffle/hdwallet-provider");

module.exports = {
/**
* Networks define how you connect to your ethereum client and let you set the
* defaults web3 uses to send transactions. If you don't specify one truffle
* will spin up a development blockchain for you on port 9545 when you
* run `develop` or `test`. You can ask a truffle command to use a specific
* network from the command line, e.g
*
* $ truffle test --network <network-name>
*/

// contracts_build_directory: "../Client/contracts",
plugins: ["truffle-plugin-verify"],
api_keys: {
polygonscan: POLYGONSCANAPIKEY,
},
networks: {
// Useful for testing. The `development` name is special - truffle uses it by default
// if it's defined here and no other network is specified at the command line.
// You should run a client (like ganache, geth, or parity) in a separate terminal
// tab if you use this network and you must also set the `host`, `port` and `network_id`
// options below to some value.
//
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 8545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
chain_id: "*",
},
//
// An additional network, but with some advanced options…
// advanced: {
// port: 8777, // Custom port
// network_id: 1342, // Custom network
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
// from: <address>, // Account to send transactions from (default: accounts[0])
// websocket: true // Enable EventEmitter interface for web3 (default: false)
// },
//
// Useful for deploying to a public network.
// Note: It's important to wrap the provider as a function to ensure truffle uses a new provider every time.
// goerli: {
// provider: () =>
// new HDWalletProvider(
// mnemonic,
// `https://goerli.infura.io/v3/${infuraProjectId}`
// ),
// network_id: 5, // Goerli's network id
// chain_id: 5, // Goerli's chain id
// gas: 5500000, // Gas limit used for deploys.
// confirmations: 2, // # of confirmations to wait between deployments. (default: 0)
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
// skipDryRun: true, // Skip dry run before migrations? (default: false for public nets)
// },
// testnet: {
// provider: () => new HDWalletProvider(mnemonic, `https://data-seed-prebsc-2-s3.binance.org:8545`),
// network_id: 97,
// confirmations: 1,
// timeoutBlocks: 20000,
// networkCheckTimeout: 9999999,
// skipDryRun: true
// },
mumbai: {
provider: () => new HDWalletProvider(mnemonic, `https://endpoints.omniatech.io/v1/matic/mumbai/public`),
network_id: 80001,
confirmations: 2,
timeoutBlocks: 200,
skipDryRun: true
},
matic: {
provider: () => new HDWalletProvider(mnemonic, `https://polygon-rpc.com`),
network_id: 137,
confirmations: 10,
timeoutBlocks: 200,
skipDryRun: true
},
// bsc: {
// provider: () => new HDWalletProvider(mnemonic, `https://bsc-dataseed1.binance.org`),
// network_id: 56,
// confirmations: 10,
// timeoutBlocks: 200,
// skipDryRun: true
// },
//
// Useful for private networks
// private: {
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
// network_id: 2111, // This network is yours, in the cloud.
// production: true // Treats this network as if it was a public net. (default: false)
// }
},

// Set default mocha options here, use special reporters, etc.
mocha: {
// timeout: 100000
},

// Configure your compilers
compilers: {
solc: {
version: "0.8.19", // Fetch exact version from solc-bin (default: truffle's version)
// docker: false, // Use "0.5.1" you've installed locally with docker (default: false)
settings: {
// See the solidity docs for advice about optimization and evmVersion
optimizer: {
enabled: false,
runs: 200
},
// evmVersion: "byzantium",
},
},
},

// Truffle DB is currently disabled by default; to enable it, change enabled:
// false to enabled: true. The default storage location can also be
// overridden by specifying the adapter settings, as shown in the commented code below.
//
// NOTE: It is not possible to migrate your contracts to truffle DB and you should
// make a backup of your artifacts to a safe location before enabling this feature.
//
// After you backed up your artifacts you can utilize db by running migrate as follows:
// $ truffle migrate --reset --compile-all
//
// db: {
// enabled: false,
// host: "127.0.0.1",
// adapter: {
// name: "sqlite",
// settings: {
// directory: ".db"
// }
// }
// }
};

Crie um arquivo chamado .env na pasta raiz do seu projeto. E copie esse conteúdo dentro do arquivo.
Na variável MNEMONIC coloque a seed que você criou na tarefa 1 da sessão de configurações, a POLYGONSCANAPIKEY vamos deixar assim por enquanto.

MNEMONIC="SEU SEED AQUI"
POLYGONSCANAPIKEY="SUA API KEY AQUI"

O meu arquivo ficou assim:

MNEMONIC="trim quote undo tornado zoo creek simple happy vast input breeze meat"
POLYGONSCANAPIKEY="SUA API KEY AQUI"

Ótimo já temos tudo que precisamos para buildar nosso contrato e realizar um deploy na nossa rede local. abra dois terminais (dentro do Vscode ou fora), certifique-se de que ele está na pasta raiz do seu projeto, então execute esses comandos:

No primeiro terminal execute o comando:

ganache

Após executar você vai ver uma tela parecida com essa:

a linha "RPC Listening on 127.0.0.1:8545" quer dizer que o seu servidor de blockchain está devidamente inicializado.

Após vizualizar essa informação no segundo terminal execute o comando:

truffle migrate

Veja como ficou os dois terminais após a execução dos dois comandos.

Perfeito seu contrato foi devidamente criado na sua rede de blockchain local e o endereço dele é o que aparece no campo "contract address", dessa forma temos um ambiente devidamente configurado para realizar um deploy na rede de teste e hoje vamos utilizar a (mumbai) que trata-se da rede de testes da polygon.

Várias configurações já foram devidamente realizadas nos passos anteriores para que seja possível o deploy na rede Mumbai, se você voltar no arquivo "truffle-config.js" e procurar pela palavra chave "mumbai", vai encontrar a configuração dessa rede conforme abaixo:

    mumbai: {
provider: () => new HDWalletProvider(mnemonic, `https://rpc-mumbai.maticvigil.com`),
network_id: 80001,
confirmations: 2,
timeoutBlocks: 200,
skipDryRun: true
},

Essa configuração está criando um provider com sua sua wallet configurada no arquivo .env que fizemos logo acima junto com a URL RPC da rede mumbai, nesse ponto podemos ter alguns problemas de comunicação com o link RPC, tente algumas vezes, caso não consiga execute esses passos:
Entre na Chainlist e tente pegar algum outro que esteja mais estável

Selecione a flag include Testnets, e pesquise por Mumbai

Clique na setinha pra baixo no card da mumbai, e procure por um link RPC com menor ping e de preferência com os dois flags positivos.

Copie o link na área determinada conforme abaixo, nesse caso eu peguei esse: "https://endpoints.omniatech.io/v1/matic/mumbai/public"

Sua configuração então ficará assim:

    mumbai: {
provider: () => new HDWalletProvider(mnemonic, `https://endpoints.omniatech.io/v1/matic/mumbai/public`),
network_id: 80001,
confirmations: 2,
timeoutBlocks: 200,
skipDryRun: true
},

ótimo, pare o seu servidor local, feche o terminal que ele estava aberto e no terminal que você rodou o comando truffle migrate execute o comando abaixo:

truffle migrate --network mumbai

Se receber no seu console algo parecido com isso, significa que o seu contrato está devidamente online na Mumbai!

Para validar, entre na mumbai.polygonscan e digite o número do contrato que foi apresentado nessa tela no campo "contract address", veja como fica o link após você pesquisar: "https://mumbai.polygonscan.com/address/0xAF7866372478b5cbeA8c420AF054352B91E320EC"

Muito legal, agora você tem um contrato seu na rede de testes da Polygon (Mumbai), mas podemos melhorar algumas coisas, é uma boa prática você verificar seus contratos, dando a possibilidade dos seus usuários entenderem o funcionamento dele a verificação de contrato nada mais é que tornar público o seu código fonte. Vamos fazer:

Primeiro precisamos criar uma conta no site polygonscan, clique em "Sign in" no canto superior direito e depois clique em "sign up", você vai cair na tela de cadastro, realize então o seu cadastro (você vai precisar confirmar seu e-mail). Com sua conta criada e confirmada se logue no sistema e clique na opção "API-KEYs".

Adicione então uma nova API-KEY clicando em add na tela.

De um nome para sua API-key e clique em continue.

Sua API Key vai aparecer assim que criar conforme abaixo:

Copie então essa API KEY e altere o arquivo .env da sua pasta raiz conforme abaixo:

MNEMONIC="trim quote undo tornado zoo creek simple happy vast input breeze meat"
POLYGONSCANAPIKEY="W3RXF7UPWGDPMPZX9X167PBHNM7U7PGXXD"

Repare que o valor da variável POLYGONSCANAPIKEY precisa ter o mesmo valor da API-KEY gerada no site da polygon.scan, feito isso execute o comando abaixo:

truffle run verify HelloWorld --network mumbai

Esse comando irá verificar o seu contrato deixando público o código fonte dele para quem entrar no endereço do seu contrato. Ao voltar no seu contrato repare que agora na aba "Contract" está um certo verde. E ao abrir você vai ver que o seu código está lá.

Para você que chegou até aqui, meus parabéns, agora você possui um contrato inicial publicado na rede de testes da Polygon e verificado utilizando as boas práticas de projetos na blockchain.

Vamos revisar o que aprendemos?

  1. Criar uma wallet na blockchain
  2. adicionar redes de teste no caso a mumbai
  3. coletar fauctes MATIC que é a moeda de teste da rede mumbai
  4. configurar o ambiente instalando node/truffle/ganache/git
  5. criar um contrato inicial Hello World
  6. iniciar um servidor ganache no computador local e realizar um deploy do contrato.
  7. realizar deploy na rede de teste da polygon (mumbai) e verificar o contrato.

Olha quanta coisa? muito bem.
na segunda parte com todas essas configurações feitas, vamos conseguir criar o nosso contrato NFT Dinâmico e configurar a Chainlink Automation para atualizar ele automaticamente. Clique aqui para ir para segunda parte.

--

--