A equipe de edição da Bitaigen acredita que este artigo organiza sistematicamente todas as etapas necessárias para escrever, implantar e cunhar NFTs no ambiente Flow + IPFS. Desde a instalação das ferramentas até a implementação do contrato em Cadence, explicamos tudo passo a passo, facilitando a entrada rápida dos desenvolvedores. Os casos práticos que virão depois são ainda mais promissores, portanto recomendamos uma leitura atenta.
Tutorial de criação de contrato e mintagem de tokens NFT com Flow e IPFS
Na blockchain Flow, combinada com o IPFS, é possível escrever um contrato em Cadence, implantá‑lo em um simulador ou testnet, usar o Pinata para fazer upload dos ativos e obter o CID, e então cunhar o NFT vinculando os metadados ao token, completando todo o fluxo de criação e mintagem.
Configuração do ambiente
- Instalação do Flow CLI
- macOS
```bash
brew install flow-cli
```
- Linux
```bash
sh -ci "$(curl -fsSL https://storage.googleapis.com/flow-cli/install.sh)"
```
- Windows
```powershell
iex "& { $(irm 'https://storage.googleapis.com/flow-cli/install.ps1') }"
```
- Preparar o armazenamento de ativos no IPFS
- Crie uma conta gratuita no Pinata e obtenha a sua API Key. Na segunda parte deste tutorial usaremos a API do Pinata; aqui faremos o upload manual pelo site.
- Instalar Node.js e um editor de código
- Recomendamos o Visual Studio Code e a instalação da extensão de sintaxe Cadence, que oferece realce adequado para o código de contratos inteligentes.
- Criar diretório do projeto
```bash
mkdir pinata-party
cd pinata-party
flow project init
```
Depois da inicialização, o arquivo `flow.json` será criado e será configurado nos passos seguintes.
- Organizar a estrutura de pastas
```
pinata-party/
├─ cadence/
│ └─ contracts/
│ └─ PinataPartyContract.cdc
├─ transactions/
└─ scripts/
```
Todo o código relacionado ao Flow ficará na pasta `cadence/contracts`. Scripts de transação e de consulta serão armazenados, respectivamente, nas pastas `transactions` e `scripts`.
Configurando o *flow.json* para o simulador
Adicione o caminho do contrato ao arquivo `flow.json`:
```json
"contracts": {
"PinataPartyContract": "./cadence/contracts/PinataPartyContract.cdc"
},
"deployments": {
"emulator": {
"emulator-account": ["PinataPartyContract"]
}
}
```
Essa configuração indica ao Flow CLI que o contrato `PinataPartyContract` deve ser implantado no simulador local.
Escrita do contrato NFT
Estrutura central do contrato
```cadence
pub contract PinataPartyContract {
// Definição do recurso NFT
pub resource NFT {
pub let id: UInt64
init(initID: UInt64) {
self.id = initID
}
}
// Interface para quem recebe NFTs
pub resource interface NFTReceiver {
pub fun deposit(token: @NFT, metadata: {String: String})
pub fun getIDs(): [UInt64]
pub fun idExists(id: UInt64): Bool
pub fun getMetadata(id: UInt64): {String: String}
}
// Implementação da coleção de NFTs
pub resource Collection: NFTReceiver {
// Armazenamento dos NFTs
pub var ownedNFT: @{UInt64: NFT}
// Mapeamento dos metadados correspondentes
pub var metadataObjs: {UInt64: {String: String}}
init() {
self.ownedNFT <- {}
self.metadataObjs = {}
}
// Retira um NFT da coleção
pub fun withdraw(withdrawID: UInt64): @NFT {
let token <- self.ownedNFT.remove(key: withdrawID)!
return <-token
}
// Deposita um NFT e associa metadados
pub fun deposit(token: @NFT, metadata: {String: String}) {
self.ownedNFT[token.id] <-! token
self.metadataObjs[token.id] = metadata
}
pub fun idExists(id: UInt64): Bool {
return self.ownedNFT[id] != nil
}
pub fun getIDs(): [UInt64] {
return self.ownedNFT.keys
}
pub fun getMetadata(id: UInt64): {String: String} {
return self.metadataObjs[id]!
}
destroy() {
destroy self.ownedNFT
}
}
// Função fábrica que cria uma Collection vazia
pub fun createEmptyCollection(): @Collection {
return <-create Collection()
}
// Recurso responsável pela mintagem
pub resource NFTMinter {
pub var idCount: UInt64
init() {
self.idCount = 1
}
pub fun mintNFT(): @NFT {
let newNFT <- create NFT(initID: self.idCount)
self.idCount = self.idCount + 1
return <-newNFT
}
}
// Inicialização do contrato: cria a Collection, expõe a interface e salva o minter
init() {
// Cria e salva uma Collection vazia para quem implanta o contrato
self.account.save(<-self.createEmptyCollection(), to: /storage/NFTCollection)
// Expõe a Collection como a interface NFTReceiver
self.account.link<&Collection{NFTReceiver}>(/public/NFTReceiver, target: /storage/NFTCollection)
// Salva o recurso NFTMinter; apenas o criador do contrato tem acesso
self.account.save(<-create NFTMinter(), to: /storage/NFTMinter)
}
}
```
Pontos críticos
- O recurso NFT contém apenas o identificador exclusivo `id`.
- A interface NFTReceiver define quatro métodos que podem ser chamados externamente: `deposit`, `getIDs`, `idExists` e `getMetadata`.
- Collection implementa essa interface e ainda mantém o dicionário `metadataObjs` para armazenar os metadados de cada NFT.
- NFTMinter cuida do incremento de `idCount` e da criação de novos NFTs.
- O bloco `init()` cria automaticamente, na implantação, uma Collection vazia, expõe a interface pública e persiste o recurso minter.
Implantando o contrato
- Use o Flow Playground ou o simulador local.
- No simulador local, execute:
```bash
flow project start-emulator # inicia o simulador local
flow project deploy # implanta o contrato
```
O log de sucesso será semelhante a:
```
Deploying 1 contracts for accounts: emulator-account.PinataPartyContract -> 0xf8d6e0586b0a20c7
```
Mintagem de NFT (script de transação)
Criação do arquivo de transação
Dentro da pasta `transactions`, crie o arquivo `MintPinataParty.cdc` com o conteúdo abaixo:
```cadence
import PinataPartyContract from 0xf8d6e0586b0a20c7
transaction {
// Referências ao receiver e ao minter
let receiverRef: &{PinataPartyContract.NFTReceiver}
let minterRef: &PinataPartyContract.NFTMinter
prepare(acct: AuthAccount) {
// Obtém a capacidade pública de NFTReceiver
self.receiverRef = acct.getCapability<&{PinataPartyContract.NFTReceiver}>(/public/NFTReceiver)
.borrow()
?? panic("Could not borrow receiver reference")
// Obtém o recurso privado NFTMinter
self.minterRef = acct.borrow<&PinataPartyContract.NFTMinter>(from: /storage/NFTMinter)
?? panic("Could not borrow minter reference")
}
execute {
// Exemplo de metadados (substitua o CID do IPFS conforme necessário)
let metadata: {String: String} = {
"name": "The Big Swing",
"swing_velocity": "29",
"swing_angle": "45",
"rating": "5",
"uri": "ipfs://QmRZdc3mAMXpv6Akz9Ekp1y4vDSjazTx2dCQRkxVy1yUj6"
}
// Cunha o NFT e o deposita na Collection
let newNFT <- self.minterRef.mintNFT()
self.receiverRef.deposit(token: <-newNFT, metadata: metadata)
log("NFT minted and deposited")
}
}
```
Observações
- Substitua o endereço na linha `import` pelo endereço real onde o contrato foi implantado.
- O campo `uri` dentro de `metadata` usa o prefixo `ipfs://` apontando para o CID obtido no Pinata.
- O método `deposit` grava simultaneamente o NFT e seus metadados na Collection.
Gerar chave da conta e atualizar o *flow.json*
```bash
flow keys generate
```
Copie a `privateKey` e a `publicKey` retornadas para o bloco de contas do `flow.json`:
```json
"accounts": {
"emulator-account": {
"address": "0xf8d6e0586b0a20c7",
"privateKey": "SUA_CHAVE_PRIVADA",
"chain": "flow-emulator",
"sigAlgorithm": "ECDSA_P256",
"hashAlgorithm": "SHA3_256"
}
}
```
Dica de segurança: nunca publique sua chave privada em repositórios públicos. É recomendável adicionar o `flow.json` ao `.gitignore`.
Enviando a transação
```bash
flow transactions send --code ./transactions/MintPinataParty.cdc --signer emulator-account
```
Se tudo ocorrer bem, o comando retornará um ID de transação, confirmando que o NFT foi gravado na Collection da conta.
Consulta de metadados de NFT (script somente leitura)
Crie o script `CheckTokenMetadata.cdc` dentro da pasta `scripts`:
```cadence
import PinataPartyContract from 0xf8d6e0586b0a20c7
pub fun main(): {String: String} {
let nftOwner = getAccount(0xf8d6e0586b0a20c7)
let capability = nftOwner.getCapability<&{PinataPartyContract.NFTReceiver}>(/public/NFTReceiver)
let receiverRef = capability.borrow()
?? panic("Could not borrow the receiver reference")
return receiverRef.getMetadata(id: 1)
}
```
Execute o script:
```bash
flow scripts execute ./scripts/CheckTokenMetadata.cdc
```
A saída esperada será semelhante a:
```
{"name":"The Big Swing","swing_velocity":"29","swing_angle":"45","rating":"5","uri":"ipfs://QmRZdc3mAMXpv6Akz9Ekp1y4vDSjazTx2dCQRkxVy1yUj6"}
```
Com isso, concluímos todo o fluxo — criação, mintagem e consulta de NFTs usando Flow e IPFS.
---
Resumo
- Desenvolva contratos NFT compatíveis com o padrão Flow usando Cadence.
- Carregue arquivos de mídia no IPFS via Pinata e obtenha o CID.
- Insira o CID no campo `uri` dos metadados dentro do script de transação, vinculando o NFT on‑chain ao recurso off‑chain.
- O tutorial cobre quatro etapas essenciais: configuração do ambiente, desenvolvimento do contrato, implantação, mintagem e consulta, preparando o terreno para integrações front‑end ou marketplaces secundários.

---
*Esta tradução foi patrocinada pela Cell Network. Link do artigo original: https://medium.com/pinata/how-to-create-nfts-like-nba-top-shot-with-flow-and-ipfs-701296944bf*
Leitura Relacionada
- GameFi: Conceito, DeFi, NFT e Moedas de Alto Potencial
- GameFi, Metaverso e NFTs: Invista em Solana e Avalanche
- Guia completo para negociar NFTs na rede de teste do OpenSea
💡 Cadastre-se na Binance com o código B2345 para o desconto máximo em taxas. Veja guia completo Binance.