WEB3DEV

Cover image for O melhor passo a passo do contrato de NFT Mythic Card ERC1155 na zkEVM da Polygon
Isabela Curado Nehme
Isabela Curado Nehme

Posted on

O melhor passo a passo do contrato de NFT Mythic Card ERC1155 na zkEVM da Polygon

02 de abril de 2023

Usando o Midjourney e o ChatGPT - Como eu criei uma coleção de NFTs de Mythic Card (Carta mítica) na zkEVM (Máquina virtual de conhecimento zero da Ethereum) da Polygon

# Construa uma coleção NFT de Mythic Card ERC1155 na zkEVM da Polygon.

https://youtu.be/hqEYYREoTxs

O que é zkEVM da Polygon?

A zkEVM da Polygon é a rede mais recente lançada pela Polygon que ajuda a escalar transações da Ethereum, a um custo mais barato, e, ao mesmo tempo, alavancar a segurança da própria Ethereum.

O que isso significa para os criadores de NFT é que essa é uma maneira interessante de economizar nos custos das transações, na capacidade de fazer a ponte entre tokens de um lado para o outro (chegada da ponte de NFTs) e de tirar vantagens do ETH nativo para lidar com pagamentos por meio da ponte.

Mais barato, mais rápido e construído como você faria na Ethereum.

# https://polygon.technology/polygon-zkevm

O que é um contrato ERC1155

Um contrato ERC1155 é um token de NFT que leva o melhor do ERC20 e do ERC721 e permite que você gerencie vários tokens fungíveis ou não-fungíveis em um contrato.

Essa funcionalidade é ideal para jogos que querem integrar algum tipo de domínio ou componente de NFT para itens diferentes que podem ter múltiplos proprietários. Por exemplo, como ter 10 armas de espadas largas que possuem os mesmos atributos, mas pertencerão a pessoas diferentes.

Criando ativos de design para Mythic Cards (cartas míticas)

Este artigo mostrará como criei os gráficos de design com o Midjourney, os detalhes e a descrição com o ChatGPT e as animações das cartas. No verdadeiro estilo NFT, também mostro como fiz upload dos arquivos no Arweave para torná-los mais permanentes.

Se você quiser pular o aspecto de design e ir direto para o contrato, consulte a seção “Building An ERC1155 NFT Collection On Polygon zkEVM” (Construindo uma coleção de NFT ERC1155 na zkEVM da Polygon).

Prompts (Comandos) de design de cartas no Midjourney

Eu me inspirei muito no jogo Hearstone da Blizzard para projetar esses itens. Com o Midjourney, eu sabia que precisava de ambos os itens em si, do gráfico decorativo ao redor que os faria parecer consistentes e de um design padrão para o verso das cartas.

Prompts (Comandos) de itens no Midjourney

Eu tentei alguns prompts, mas o único que parecia funcionar melhor foi o seguinte:

// um machado sem personagens na foto e apenas o item em si, no estilo Heartstone da Blizzard

// OU

// um punhal de fogo roxo sem personagens na foto e apenas o item em si sem nenhum outro item, no estilo Heartstone da Blizzard
Enter fullscreen mode Exit fullscreen mode

# Gráfico de geração de espadas do Midjourney.

A espada, o machado e o crânio que consegui gerar não tiveram problemas, mas o Midjourney teve um problema com a palavra “Bow” (Arco) (até tentei arco e flecha) para um arco e flecha.

# Dificuldade do Midjourney em gerar um Arco e flecha.

Com a espada, o machado, o crânio e um item parecido com um coração, eu cheguei a esses quatro itens.

# Itens de Mythic Card gerados com o Midjourney.

Gerando decorações e verso da carta

Uma vez que eu tinha todos os quatro itens, fiz questão de pedir para gerar algumas formações rochosas aleatórias que eu sabia que poderia moldar para cobrir os itens. Também fiz um prompt de algumas portas de madeira bonitas para cobrir o verso das cartas.

// um fundo de pedra decorativo que ocupa toda a foto, sem nenhum personagem na foto, apenas o item em si, e sem nenhum outro item, no estilo Heartstone da Blizzard 
Enter fullscreen mode Exit fullscreen mode

# Midjourney gerando imagem de formação rochosa.
// um fundo de madeira decorativo sem nenhum personagem na foto e apenas o próprio item sem nenhum outro item, voltado para frente, no estilo Heartstone da Blizzard
Enter fullscreen mode Exit fullscreen mode

# Midjourney gerando imagem de porta de madeira para o verso da carta.

Editando imagens no Photoshop

As cartas não estavam completas, porque ainda precisava editá-las um pouco no Photoshop para aumentar a altura que procurava, criar a borda decorativa e adicionar alguns brilhos leves a eles.

# [GIF] Editando cartas com o Photoshop.

# Gráficos finais das cartas editadas no Photoshop.

Criando animação de carta em SVG (Scalable Vector Graphics - Gráficos vetoriais escaláveis)

Isso me levou um pouco mais de tempo para fazer porque existe essa propriedade css chamada backface-visibility, que infelizmente não funciona em SVGs.

A fim de obter a animação da carta que eu queria, precisava criar um retângulo giratório (depois transformado em uma imagem), que giraria até o ponto em que ficasse de lado, se tornasse completamente transparente e então aparecesse para completar o ciclo de rotação completo. Com dois desses retângulos, eu poderia imitar a backface-visibility e fazer parecer que a rotação estava se movendo suavemente para frente e para trás entre a frente e o verso da carta.

Iteração 1 da animação da carta - Rotação básica

Fazer com que um lado da carta gire no meio e se torne invisível quando girado de lado.

https://codesandbox.io/embed/card-animation-iteration-01-dofe95?fontsize=14&hidenavigation=1&theme=dark

Iteração 2 da animação da carta - Alternando

Fazer com que ambos os lados frente e verso da carta iterem para frente e para trás entre mostrar e ocultar seus respectivos lados.

https://codesandbox.io/embed/card-animation-iteration-02-v4zz5c?fontsize=14&hidenavigation=1&theme=dark

Iteração 3 da animação da carta - Gráficos de suporte

Aproveitando a possibilidade de usar codificação base64 para dados de imagem, podemos substituir as tags rect por tags image com um atributo href, começando com o seguinte:

<image href="data:image/jpeg;base64,..."
Enter fullscreen mode Exit fullscreen mode

Usando o base64.guru, podemos fazer upload de um arquivo e fazer com que ele gere a codificação base64 necessária para a imagem.

# https://base64.guru/converter/encode/image

https://codesandbox.io/embed/card-animation-iteration-03-2qeluq?fontsize=14&hidenavigation=1&theme=dark

Iteração 4 da animação da carta - Estilização

O último passo é aplicar as bordas arredondadas e dar a elas um fundo gradiente radial. Infelizmente, não há uma maneira fácil de arredondar o raio da borda com a tag image, então precisaremos usar uma retificação aplicada clipPath a ambas as tags image.

https://codesandbox.io/embed/suspicious-tom-kcnijt?fontsize=14&hidenavigation=1&theme=dark

Com a animação e o formato concluídos, posso salvar todos os itens como imagens de SVG separadas. Colocaremos todas as quatro imagens em uma pasta SVG.

# ./zkevm-erc1155
# svg
# ├── axe.svg
# ├── heart.svg
# ├── skull.svg
# └── sword.svg
Enter fullscreen mode Exit fullscreen mode

Fazendo upload de nossos gráficos e metadados para o Arweave Permaweb

Agora que temos as imagens, precisamos armazenar essas imagens em SVG em um local onde possamos referenciá-las mais tarde para o arquivo JSON de metadados que precisamos para o OpenSea e outros leitores de NFT fazerem o download e exibi-las corretamente.

OBSERVAÇÃO: Para estes próximos passos, no intuito de fazer o upload, precisaremos tanto de ETH real da Ethereum ou de MATIC da Polygon para fazer o upload para o Arweave.

Instalação e configuração de dependência

# FROM: ./zkevm-erc1155

npm init -y;
npm install dotenv @bundlr-network/client bignumber.js;
npm install -D @types/node ts-node typescript;
./node_modules/.bin/tsc --init;
mkdir upload; # Pasta de armazenamento de nossos scripts de upload de arquivo
touch .env;
Enter fullscreen mode Exit fullscreen mode

Em nosso arquivo .env, adicionaremos a chave privada da carteira que tem MATIC para pagar pelo upload.

Arquivo: ./.env

WALLET_PRIVATE_KEY="<YOUR-WALLET-PRIVATE-KEY>"
Enter fullscreen mode Exit fullscreen mode

Upload de arquivos para o Arweave

Em nossa nova pasta de upload, criaremos um uploader de arquivo que lerá os arquivos da pasta svg, estimará seu custo, financiará um nó Bundlr e fará o upload deles no Arweave.

Arquivo: ./upload/arweaveFiles.ts

// Importa
// ========================================================
import Bundlr from "@bundlr-network/client";
import fs from "fs";
import path from 'path';
import dotenv from 'dotenv';
import BigNumber from "bignumber.js";

// Configura
// ========================================================
dotenv.config();
const ARWEAVE_TX_URL = "https://arweave.net/";
const privateKey = process.env.WALLET_PRIVATE_KEY;
const bundlr = new Bundlr("http://node1.bundlr.network", "matic", privateKey); // OBSERVAÇÃO: Você precisa de matic na sua carteira para fazer upload

// Script Principal de Upload 
// ========================================================
(async () => {
   try {
       // Recupera o saldo atual
       console.group('Current Balance');
       const atomicBalance = await bundlr.getLoadedBalance();
       console.log({ atomicBalance });
       console.log({ atomicBalance: atomicBalance.toString() });
       const convertedBalance = bundlr.utils.unitConverter(atomicBalance);
       console.log({ convertedBalance });
       console.log({ convertedBalance: convertedBalance.toString() });
       console.groupEnd();

       // Obtém todos os arquivos
       console.group('Files');
       const folderPath = path.join(__dirname, '..', 'svg');
       const files = await fs.readdirSync(folderPath);
       console.log({ files });
       const svgFiles = files.filter(i => i.includes('.svg'));
       console.log({ svgFiles });
       console.groupEnd();

       // Obtém tamanho total do arquivo para todos os arquivos
       console.group('Funding Node');
       let size = 0;
       for (let i = 0; i < svgFiles.length; i++) {
           const fileToUpload = path.join(__dirname, '..', 'svg', svgFiles[i]);
           const fileSize = await fs.statSync(fileToUpload);
           size += fileSize.size;
       }
       console.log({ size });
       const price = await (await bundlr.getPrice(size)).toNumber() / 1000000000000000000;
       console.log({ price });

       // Financia se necessário
       if (price > parseFloat(convertedBalance.toString())) {
           console.log('Funding...');
           const fundAmountParsed = BigNumber(price as any).multipliedBy(bundlr.currencyConfig.base[1]);
           console.log({ fundAmountParsed: fundAmountParsed.toString() });
           await bundlr.fund(fundAmountParsed.toString());
           const convertedBalance = bundlr.utils.unitConverter(atomicBalance);
           console.log({ convertedBalance: convertedBalance.toString() });
       }
       console.groupEnd();

       console.group('Uploading...');
       for (let i = 0; i < svgFiles.length; i++) {
           const fileToUpload = path.join(__dirname, '..', 'svg', svgFiles[i]);
           const response = await bundlr.uploadFile(fileToUpload);
           console.log(`${ARWEAVE_TX_URL}${response.id}`);
       }
       console.groupEnd();
   } catch (e) {
       console.error("Error uploading file ", e);
   }
})();
Enter fullscreen mode Exit fullscreen mode

Tornaremos um pouco mais fácil para nós mesmos adicionarmos o comando upload ao nosso arquivo package.json.

Arquivo: ./package.json

// ...
 "scripts": {
   "uploadFiles": "./node_modules/.bin/ts-node upload/arweaveFiles.ts"
 },
// ...
Enter fullscreen mode Exit fullscreen mode

Se executarmos uploadFiles, devemos obter o seguinte:

# FROM ./zkevm-erc1155

npm run uploadFiles;

# Saída Esperada:
# Saldo Atual
#   { atomicBalance: BigNumber { s: 1, e: 15, c: [ 15, 71544535461003 ] } }
#   { atomicBalance: '1571544535461003' }
#   {
#     convertedBalance: BigNumber { s: 1, e: -3, c: [ 157154453546, 10030000000000 ] }
#   }
#   { convertedBalance: '0.001571544535461003' }
# Arquivos
#   { files: [ 'axe.svg', 'heart.svg', 'skull.svg', 'sword.svg' ] }
#   { svgFiles: [ 'axe.svg', 'heart.svg', 'skull.svg', 'sword.svg' ] }
# Nó de Financiamento
#   { size: 2550214 }
#   { price: 0.007514900904697801 }
#   Financimento...
#   { fundAmountParsed: '7514900904697801' }
#   { convertedBalance: '0.001571544535461003' }
# Fazendo Upload...
#   https://arweave.net/JtA8psYtbOP9i3QqxBAnkWVSVbNtL7-F_x-I3JMadE4
#   https://arweave.net/CcNM3Jaq5qAyfmAlUVPFqBEFz51ikZrGYw6cRsqQius
#   https://arweave.net/jFtwyxLxhzbzP94LYl0HcBuODwJsGT7JLdsWxWXhZK8
#   https://arweave.net/mXQ0uptvLKnMCc2LxqGxMwp6He2upfz_AeFV6MEgv8g
Enter fullscreen mode Exit fullscreen mode

OBSERVAÇÃO: Se o upload falhar, há uma grande chance de que o nó do Bundlr não tenha sido completamente financiado e que talvez seja necessário ajustar os fundos que precisam ser enviados para pagar pelo upload.

Se pegarmos um dos links do Arweave, podemos ver que nossa imagem foi carregada com sucesso.

# https://arweave.net/JtA8psYtbOP9i3QqxBAnkWVSVbNtL7-F_x-I3JMadE4

Criação de metadados de NFT

Agora que temos os URLs das imagens, precisamos criar metadados para cada item como um arquivo JSON separado que faz referência à imagem do Arweave. Também precisamos garantir que cada arquivo JSON seja armazenado com o ID do token (como um número inteiro) para o nome do arquivo (Ex: 1.json, 2.json, …).

Armazenaremos todos esses arquivos JSON em uma pasta chamada manifest e usaremos o ChatGPT para criar algumas descrições.

# Descrição do item no ChatGPT.

Faça isso para todos os itens e crie um arquivo JSON para cada um no seguinte formato JSON:

Arquivo: ./manifest/1.json

{
   "description": "The Blade of Souls is a legendary weapon steeped in mystery and lore. It is said to have been created by the gods themselves, imbued with the power to vanquish even the most malevolent of beings.",
   "image": "https://arweave.net/h3kkGN_QRfhYWbZlQb5N2bSaqj6HNB4_pGxLfsdhWuo",
   "name": "Blade Of Souls",
   "attributes": [
       {
           "trait_type": "Damage",
           "value": 12
       }
   ]
}
Enter fullscreen mode Exit fullscreen mode

Nessa mesma pasta, também adicionaremos um arquivo contract.json com os metadados do próprio contrato.

Arquivo: ./manifest/contract.json

{
   "name": "zkMythicCards",
   "description": "zkMythicCards is a mystical card game played by the gods themselves, where players use their elemental powers to summon creatures and cast spells to defeat their opponents and claim ultimate victory"
}
Enter fullscreen mode Exit fullscreen mode

Fazer upload da pasta para o Arweave

Com os arquivos JSON 1-4 criados e referenciando seus respectivos itens e descrições, agora podemos usar o Arweave para carregar a pasta para que ela faça referência a um número inteiro que podemos usar de nosso ID de token em nosso contrato ERC1155.

Em nossa pasta upload, criaremos um novo arquivo chamado uploadFolder.ts.

Arquivo: ./upload/arweaveFolder.ts

// Importa
// ========================================================
import Bundlr from "@bundlr-network/client";
import fs from "fs";
import path from 'path';
import dotenv from 'dotenv';

// Configura
// ========================================================
dotenv.config();
const ARWEAVE_TX_URL = "https://arweave.net/";
const privateKey = process.env.WALLET_PRIVATE_KEY;
const bundlr = new Bundlr("http://node1.bundlr.network", "matic", privateKey);

// Script Principal de Upload
// ========================================================
(async () => {
   console.group('Uploading folder...');
   try {
       const folderPath = path.join(__dirname, '..', 'manifest');
       const folder = fs.existsSync(folderPath);
       console.log({ folderExists: folder });
       if (!folder) {
           throw new Error('Folder doesn\'t exist');
       }
       const response = await bundlr.uploadFolder(folderPath, {
           indexFile: "", // arquivo de índice opcional (arquivo que o usuário carregará ao acessar ‘manifest’) 
           batchSize: 4, //número de itens para fazer upload de uma vez
           keepDeleted: false, // se deseja manter agora itens excluídos dos uploads anteriores
       }); //retorna o ID de ‘manifest’

       console.log({ response });
       console.log({ URL: `${ARWEAVE_TX_URL}${response?.id}`});
   } catch (e) {
       console.error("Error uploading file ", e);
   }
   console.groupEnd();
})();
Enter fullscreen mode Exit fullscreen mode

Vamos facilitar para nós mesmos novamente adicionando o comando de upload ao nosso arquivo package.json.

Arquivo: ./package.json

// ...
 "scripts" : {
   "uploadFiles" : "./node_modules/.bin/ts-node upload/arweaveFiles.ts" ,
   "uploadFolder" : "./node_modules/.bin/ts-node upload/arweaveFolder .ts" ,
 } ,
// ...
Enter fullscreen mode Exit fullscreen mode

Agora, se executarmos uploadFolder, devemos obter o seguinte resultado:

# FROM ./zkevm-erc1155

npm run uploadFolder;

# Saída esperada: 
# Fazendo upload da pasta...
#   { folderExists: true }
#   {
#     resposta: {
#       id: 'l9LANRyWrOOOgnaDrOG8QKBRbxTNf7mMeANw781y4bs',
#       timestamp: 1679943617898
#     }
#   }
#   {
#     URL: 'https://arweave.net/l9LANRyWrOOOgnaDrOG8QKBRbxTNf7mMeANw781y4bs'
#   }
Enter fullscreen mode Exit fullscreen mode

Usando o URL, cole-o no seu navegador e acrescente qualquer um dos números de 1 a 4 ou contrato como /1.json a ele.

# https://arweave.net/l9LANRyWrOOOgnaDrOG8QKBRbxTNf7mMeANw781y4bs/4.json

Com o URL vamos também adicioná-lo ao nosso arquivo .env da seguinte forma:

Arquivo: ./env

WALLET_PRIVATE_KEY="<YOUR-WALLET-PRIVATE-KEY>"
BASE_URL="<YOUR-UNIQUE-BASE-URL-FOR-HOLDING-JSON-FILES-WITH-SLASH-AT-THE-END>"
Enter fullscreen mode Exit fullscreen mode

Agora temos todos nossos ativos de design e arquivos prontos para criar o projeto NFT.

Construindo uma Coleção de NFT ERC1155 na kzEVM da Polygon

A próxima etapa é criar nosso contrato ERC1155 com o Hardhat, fazer algumas modificações personalizadas e configurá-lo para implantação da rede de teste da zkEVM.

Configurando o Hardhat com ERC1155

Como estamos usando o npx hardhat para criar a base do modelo, precisaremos remover o arquivo anterior package.json e adicionar estas dependências e algumas adicionais novamente.

# FROM: ./zkevm-erc1155

rm package.json;
rm tsconfig.json;
npx hardhat;

# Expeceted Output:
# ✔ What do you want to do? · Create a TypeScript project
# ✔ Hardhat project root: · /Users/username/path/to/zkevm-erc1155
# ✔ Do you want to add a .gitignore? (Y/n) · y
# ✔ Do you want to install this sample project's dependencies with npm (hardhat @nomicfoundation/hardhat-toolbox)? (Y/n) · y

npm install dotenv @bundlr-network/client bignumber.js @openzeppelin/contracts;
npm install -D @types/node ts-node typescript;
Enter fullscreen mode Exit fullscreen mode

Arquivo: ./package.json

// ...
 "scripts": {
   "uploadFiles": "./node_modules/.bin/ts-node upload/arweaveFiles.ts",
   "uploadFolder": "./node_modules/.bin/ts-node upload/arweaveFolder.ts",
 },
// ...
Enter fullscreen mode Exit fullscreen mode

Vamos renomear o arquivo do modelo Solidity gerado pelo Hardhat e remover a pasta de teste porque eles não se aplicam a esse novo contrato.

# FROM: ./zkevm-erc1155

mv contracts/Lock.sol contracts/ZkMythicCards.sol;
rm -rf test;
Enter fullscreen mode Exit fullscreen mode

Criando nosso contrato ERC1155

Agora que temos o que precisamos, criaremos nosso contrato com algumas funcionalidades adicionais para geração de números aleatórios (o VRF ainda não é compatível com a zkEVM) e obteremos o URI do contrato para os metadados do contrato.

Arquivo: ./contracts/ZkMythicCards.sol

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

// Importa
// ========================================================
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

// Contrato
// ========================================================
contract ZkMythicCards is ERC1155, Ownable, Pausable, ERC1155Burnable, ERC1155Supply {
   // Funcionalidade estendida
   using Strings for uint256;
   // Usado para rastrear um número aleatório gerado para selecionar um dos quatro itens
   uint256 public randomNumber;

   /**
    * Construtor principal definindo o baseURI
    * newuri - define o url base para onde estamos armazenando nossos arquivos JSON ‘manifest’
    */
   constructor(string memory newuri)
       ERC1155(newuri)
   {}

   /**
    * @dev Define um novo URI para todos os tipos de token, ao contar com o ID do tipo de token
    */
   function setURI(string memory newuri) public onlyOwner {
       _setURI(newuri);
   }

   /**
    * @dev Aciona o estado parado.
    */
   function pause() public onlyOwner {
       _pause();
   }

   /**
    * @dev Retorna ao estado normal.
    */
   function unpause() public onlyOwner {
       _unpause();
   }

   /**
    * @dev Cria um número aleatório baseado no número de loops a serem gerados
    * (Isto é antes do VRF ser compatível na zkEVM)
    */
   function generateRandomNumber(uint256 loopCount) public {
       for (uint256 i = 0; i < loopCount; i++) {
           uint256 blockValue = uint256(blockhash(block.number - i));
           randomNumber = uint256(keccak256(abi.encodePacked(blockValue, randomNumber, i)));
       }
   }

   /**
    * @dev Cria uma ‘amount`(quantidade) de tokens do token tipo `id` e os atribui a `msg.sender`.
    */
   function mint(uint256 amount)
       public
   {
       for (uint i = 0; i < amount; i++) {
           // generateRandomNumber cria um novo número toda vez logo antes de cunhar
           generateRandomNumber(i);
           // 4 é o número máximo e 1 é o número mínimo
           // _mint(to, tokenId, amount, data)
           _mint(msg.sender, randomNumber % 4 + 1, 1, "");
       }
   }

   /**
    * @dev Gancho (hook) chamado antes de qualquer transferência de token. Isso inclui a cunhagem
    * e a queima, bem como variantes em lote.
    */
   function _beforeTokenTransfer(address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
       internal
       whenNotPaused
       override(ERC1155, ERC1155Supply)
   {
       super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
   }

   /**
    * @dev Consulte {IERC1155MetadataURI-uri}.
    * Metadados exibidos para tokenID do NFT - Ex: 1.json
    */
   function uri(uint256 _tokenId) override public view returns (string memory) {
       if(!exists(_tokenId)) {
           revert("URI: nonexistent token");
       }
       return string(abi.encodePacked(super.uri(_tokenId), Strings.toString(_tokenId), ".json"));
   }

   /**
    * @dev Metadados em nível de contrato
    */
   function contractURI() public view returns (string memory) {
       return string(abi.encodePacked(super.uri(0), "contract.json"));
   }
}
Enter fullscreen mode Exit fullscreen mode

Implantando a coleção de cartas do ERC1155 para a rede de teste da zkEVM

Com o contrato pronto, modificaremos nosso arquivo deploy.ts.

Arquivo: ./scripts/deploy.ts

// Importa
// ========================================================
import { ethers } from "hardhat";
import dotenv from "dotenv";

// Configura
// ========================================================
dotenv.config();

// Importa
// ========================================================
async function main() {
 const Contract = await ethers.getContractFactory(`${process.env.CONTRACT_NAME}`);
 const contract = await Contract.deploy(`${process.env.BASE_URL}`);

 await contract.deployed();

 console.log(
   `${`${process.env.CONTRACT_NAME}`} deployed to ${contract.address}`
 );
}

// Recomendamos esse padrão para poder usar async/await em qualquer lugar
// e lidar adequadamente com erros.
main().catch((error) => {
 console.error(error);
 process.exitCode = 1;
});
Enter fullscreen mode Exit fullscreen mode

Atualizaremos nosso arquivo .env para refletir o CONTRACT_NAME, adicionaremos nosso RPC (Remote Procedure Call - chamada de procedimento remoto) da zkEVM e especificaremos quantos tipos de NFT existem.

Arquivo: ./env

CONTRACT_NAME="ZkMythicCards"
NUMBER_NFT_TYPES="4"
RPC_ZKEVM_URL="https://rpc.public.zkevm-test.net"
WALLET_PRIVATE_KEY="<YOUR-WALLET-PRIVATE-KEY>"
BASE_URL="<YOUR-UNIQUE-BASE-URL-FOR-HOLDING-JSON-FILES>"
Enter fullscreen mode Exit fullscreen mode

Com as novas variáveis de ambiente, modificaremos nosso hardhat.config.ts para ser compatível com as configurações do RPC.

Arquivo: hardhat.config.ts

// Importa
// ========================================================
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
import dotenv from "dotenv";

// Configura
// ========================================================
dotenv.config();

// Configura o Hardhat
// ========================================================
const config: HardhatUserConfig = {
 solidity: {
   version: "0.8.18",
   settings: {
     optimizer: {
       enabled: true,
       runs: 200,
     }
   }
 },
 networks: {
   zkevmTestnet: {
     url: `${process.env.RPC_ZKEVM_URL || ''}`,
     accounts: process.env.WALLET_PRIVATE_KEY
       ? [`0x${process.env.WALLET_PRIVATE_KEY}`]
       : [],
   }
 },
};

// Exporta
// ========================================================
export default config;
Enter fullscreen mode Exit fullscreen mode

Com tudo configurado, vamos implantar nosso contrato.

OBSERVAÇÃO: certifique-se de que você tem tokens na rede de teste da zkEVM. Você pode fazer uma ponte da Goerli para a zkEVM através de https://wallet.polygon.technology.

# FROM: ./zkevm-erc1155

npx hardhat run scripts/deploy.ts --network zkevmTestnet;

# Saída esperada: 
# 1 Arquivo Solidity compilado com sucesso
# ZkMythicCards implantado para 0x914B74867e49cd2a9cfb5928d14618B98Aa4FB13
Enter fullscreen mode Exit fullscreen mode

# Contrato implantado na rede de teste da zkEVM da Polygonscan - https://testnet-zkevm.polygonscan.com/address/0x914B74867e49cd2a9cfb5928d14618B98Aa4FB13

Verificação de contrato na rede de teste da zkEVM

OBSERVAÇÃO: infelizmente o Polygonscan está encontrando alguns problemas com a verificação e, por enquanto, usaremos o https://explorer.public.zkevm-test.net no lugar dele.

Criando uma entrada padrão JSON

Na pasta de artefatos compilados build-info, copie toda a seção de entrada e salve-a como um arquivo chamado verify.json.

# Copie a entrada JSON das informações de compilação.

# Crie um novo ./verify.json e cole-o nos detalhes de entrada dentro do arquivo JSON.

Verificando o contrato no explorador público (Public Explorer da rede de teste da zkEVM

Vá para o seu contrato implantado no seguinte URL, selecione o método de entrada padrão JSON para verificação e faça o upload do arquivo verify.json.

# https://explorer.public.zkevm-test.net/address/0xDeployedContractAddress
Enter fullscreen mode Exit fullscreen mode

# Explorador público da rede de teste da zkEVM - Verificar e publicar contrato.

# Explorador público da rede de teste da zkEVM - Selecionar JSON como entrada padrão.

# Explorador público da rede de teste da zkEVM - Configurar verificação.

# Explorador público da rede de teste da zkEVM - Verificação com sucesso.

Cunhando os NFTS do ERC1155 da zkEVM

Certificando-se de que nossa carteira está configurada para a rede de teste da zkEVM, conecte nossa carteira ao site, cunhe 5 NFTs e então leia um dos IDs de token para ver o resultado.

# Explorador público da rede de teste da zkEVM - Certifique-se de estar na rede de teste da zkEVM.

# Explorador público da rede de teste da zkEVM - Cunhe 5 NFTs e confirme.

# Explorador público da rede de teste da zkEVM - Cunhagem bem sucedida.

Uma vez que a cunhagem foi bem sucedida, vá para a seção “Read Contract” (ler contrato) e insira um dos quatro IDs de tokens na seção uri.

# Explorador público da rede de teste da zkEVM - Ler contrato e consultar o ID do token.

# Metadados do NFT no Arweave.

# Imagem do NFT no Arweave através dos metadados.

Embora o OpenSea ainda não seja compatível com a zkEVM, se implantarmos esse contrato na rede Mumbai da Polygon, veremos que os itens do NFT podem ter vários proprietários.

# O OpenSea demonstrando o ERC1155 com vários proprietários.

Repositório do GitHub de código completo

Se você quiser ver o repositório do código completo no GitHub, confira https://github.com/codingwithmanny/zkevm-erc1155..

GitHub logo codingwithmanny / zkevm-erc1155

How to deploy an ERC1155 Mythic Card Collection contract to zkEVM and arweave permaweb files

zkEVM ERC1155 NFT Contract - Zk Mythic Cards

This project demonstrates how to create an erc1155 contract with multiple game card items.

"zkEVM EC1155 Mythic Cards NFTs"


Requirements

  • NVM or Node v18.15.0
  • Wallet With Polygon Mainnet Matic (for the upload to arweave)
  • Wallet With zkEVM Testnet Tokens

Getting Start

This will walk you through the steps to setup, deploy, and mint the contract.

Install Dependencies

# FROM: ./zkevm-erc1155
npm install; # pnpm install
Enter fullscreen mode Exit fullscreen mode

Copy Environment Variable File

# FROM: ./zkevm-erc1155

cp .env.example .env;
Enter fullscreen mode Exit fullscreen mode

Update Environment Variables With Wallet Private Key

File: .env

WALLET_PRIVATE_KEY="<YOUR-WALLET-PRIVATE-KEY>"
Enter fullscreen mode Exit fullscreen mode

Upload Images To Arweave

NOTE: You will need actual matic to upload these files or just use the urls below

# FROM: ./zkevm-erc1155

npm run uploadFiles; # pnpm uploadFiles

# Expected Output:
# Uploading...
#   https://arweave.net/R5XqHv1UKWOazGJDX0iLe7GxqLByn3Zr5iYTCq-toko
#   https://arweave.net/QeV-FZNE4U-sDX659aQjHqnj1ocEHqGOlZm57k1mHxU
#   https://arweave.net/mnwuhiIbcne6swxK0Vm98OK-azPV-x3-_dGCsMSZbrw
#   https://arweave.net/h3kkGN_QRfhYWbZlQb5N2bSaqj6HNB4_pGxLfsdhWuo
Enter fullscreen mode Exit fullscreen mode

Modify Manifest JSON

Modify all four json files in the ./manifest folder with…

O que vem a seguir?

Alguns próximos passos poderiam ser incluir atributos adicionais para tornar este jogo de cartas totalmente funcional, onde as pessoas podem criar partidas a partir de contratos implantados.

Se você quiser aprender como implantar um Contrato ERC721 animado para a zkEVM, certifique-se de verificar esse artigo.

Se você obteve valor com isso, por gentileza, dê um pouco de amor e também me siga no twitter (onde sou bastante ativo) @codingwithmanny e instagram em @codingwithmanny .

Esse artigo foi escrito por manny e traduzido por Isabela Curado Nehme. Seu original pode ser lido aqui.

Top comments (0)