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.
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
# 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
# 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
# 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.
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.
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,..."
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
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
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;
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>"
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);
}
})();
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"
},
// ...
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
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
}
]
}
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"
}
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();
})();
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" ,
} ,
// ...
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'
# }
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>"
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;
Arquivo: ./package.json
// ...
"scripts": {
"uploadFiles": "./node_modules/.bin/ts-node upload/arweaveFiles.ts",
"uploadFolder": "./node_modules/.bin/ts-node upload/arweaveFolder.ts",
},
// ...
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;
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"));
}
}
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;
});
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>"
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;
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
# 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
# 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..
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.
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
Copy Environment Variable File
# FROM: ./zkevm-erc1155
cp .env.example .env;
Update Environment Variables With Wallet Private Key
File: .env
WALLET_PRIVATE_KEY="<YOUR-WALLET-PRIVATE-KEY>"
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
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.
Oldest comments (0)