Introdução
Os NFTs tomaram o mercado de assalto e a indústria agora movimenta bilhões de dólares.
NFT não é um conceito novo. O conceito surgiu pela primeira vez em 2014 com o lançamento do Quantum. Um token não fungível foi criado naquela época.
Mais tarde, em 2020, o NFT se tornou um tema em voga, todos estavam falando sobre isso, e seu mercado cresceu em $250 milhões. Desde então, as vendas de NFTs dispararam.
Pré-requisitos
- Conhecimento prévio de Solidity é necessário.
- Conhecimento prévio de HTML, CSS e JavaScript é necessário.
- Conhecimento das especificações ERC-20, ERC-721.
- Conhecimento de como implantar contratos inteligentes via Remix.
Requisitos
- Remix IDE para escrever contrato inteligente.
- Conhecimento de HTML, CSS e JavaScript para codificar o front-end para que possamos interagir com o contrato inteligente para criar um NFT.
O que são NFTs?
Um token não fungível ou NFT é um registro permanente na blockchain, vinculado a um ativo digital ou físico. Por exemplo, se eu tiver uma imagem única e inserir sua localização dentro do token, essa peça é chamada de token não fungível.
Mas, primeiro, precisamos entender o que significa “fungível”.
Um bem “fungível” é substituível por um item similar com o mesmo valor; isso significa que todo item fungível tem a mesma utilidade e valor intrínseco. Um exemplo disso seria uma nota de $10 que pode ser usada para substituir qualquer outra nota de $10 - você pode trocar sua nota de $10 pela de seu amigo sem realmente fazer com que seu valor caia. No entanto, se você tiver uma nota de $10 assinada por alguma celebridade ou um número de série exclusivo como todos os oitos, pode valer até $1.000 ou mais. Por quê, então? Porque um mero autógrafo de uma celebridade pode tornar uma nota normal de $10 rara, especial e, portanto, não fungível.
O que são NFTs fracionados?
Como o nome sugere, um NFT fracionado é um NFT dividido em frações que podem ser vendidas individualmente. Cada fração representa a propriedade de um NFT, permitindo que várias pessoas possuam um único NFT.
O fracionamento reduz o limite para possuir um NFT, permitindo que mais pessoas possuam um único NFT coletivamente.
Os NFTs fracionados funcionam exatamente como ações de uma empresa ou propriedade compartilhada de uma propriedade.
Quando um NFT é fracionado, o NFT original é fechado em um cofre e um fornecimento limitado de tokens fungíveis representando frações da propriedade do NFT é emitido. Os compradores interessados podem investir nessas frações individuais do NFT e reivindicar a propriedade compartilhada.
Como fracionar um NFT?
Ambos, ERC-721 e ERC-1155 são usados para criar NFTs na Ethereum. No entanto, para criar tokens alternativos, a especificação ERC-20 é usada.
O processo de fracionamento requer a criação de tokens ERC-20 (fungíveis) a partir de tokens ERC-721 (não fungíveis). Aqueles que possuem este token ERC-20 possuem uma fração do NFT.
Agora vamos nos aprofundar e entender o processo para fracionar um NFT:
- Para fracionar um NFT, primeiro, ele deve ser protegido em um contrato inteligente que divide esse token ERC-721 ou ERC-1155 em várias partes menores, cada uma representando um token ERC-20 individual.
- Cada token ERC-20 representa a propriedade parcial do NFT. Depois que o proprietário do NFT o vende, os detentores dos tokens ERC-20 podem resgatar seus tokens por sua parte do dinheiro recebido com a venda.
- Desde a decisão sobre o número de tokens ERC-20 a serem criados até a fixação do preço de cada token, o proprietário do NFT toma todas as decisões importantes sobre o processo de fracionamento.
- Uma venda aberta é então organizada para as ações fracionárias a um preço fixo por um período definido ou até que sejam vendidas.
Chega de conversa. Vamos à codificação!
Vamos precisar de dois contratos inteligentes para realizar essa tarefa.
- Contrato inteligente NFT: este é um contrato inteligente NFT simples.
- Contrato inteligente NFT fracionado: este contrato inteligente fraciona o NFT e distribui o token ERC-20. Os usuários também podem comprar NFT deste NFT. Uma vez realizada uma venda, os detentores de ERC-20 (fração) podem resgatar seus tokens com ETH.
Acesse o assistente Open Zepplin e crie um token ERC-721.
Se parece com isso.
( [https://docs.openzeppelin.com/contracts/4.x/wizard]
Forneça o nome e o símbolo do seu contrato inteligente NFT. Certifique-se de selecionar Ownable no menu.
Abaixo está o código do contrato inteligente ERC-721.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyToken is ERC721, Ownable {
constructor() ERC721("MyToken", "MTK") {}
}
Você pode colá-lo no Remix IDE.
Agora, vou explicar linha por linha este contrato.
// SPDX-License-Identifier: MIT
A linha acima especifica a licença. No nosso caso, é uma licença MIT.
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
Acima, duas declarações de importação que estão importando o contrato inteligente ERC721 e o Ownable.
contract MyToken is ERC721, Ownable {
constructor() ERC721("MyToken", "MTK") {}
}
O nome do contrato é MyToken, que herda ERC721 e Ownable.
Temos um constructor, uma função especial que é executada quando um contrato inteligente é criado.
ERC721 está recebendo dois argumentos, nome do token e símbolo do token.
Depois que terminarmos de criar o contrato inteligente NFT, é hora de criar o contrato inteligente NFT fracionado.
Abaixo está o código.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/[email protected]/token/ERC20/ERC20.sol";
import "@openzeppelin/[email protected]/token/ERC721/IERC721.sol";
import "@openzeppelin/[email protected]/access/Ownable.sol";
import "@openzeppelin/[email protected]/token/ERC20/extensions/draft-ERC20Permit.sol";
import "@openzeppelin/[email protected]/token/ERC721/utils/ERC721Holder.sol";
contract FractionalizedNFT is ERC20, Ownable, ERC20Permit, ERC721Holder {
IERC721 public collection;
uint256 public tokenId;
bool public initialized = false;
bool public forSale = false;
uint256 public salePrice;
bool public canRedeem = false;
constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {}
function initialize(address _collection, uint256 _tokenId, uint256 _amount) external onlyOwner {
require(!initialized, "Já inicializado");
require(_amount > 0, "O montante precisa ser superior a 0");
collection = IERC721(_collection);
collection.safeTransferFrom(msg.sender, address(this), _tokenId);
tokenId = _tokenId;
initialized = true;
_mint(msg.sender, _amount);
}
function putForSale(uint256 price) external onlyOwner {
salePrice = price;
forSale = true;
}
function purchase() external payable {
require(forSale, "Não está à venda");
require(msg.value >= salePrice, "Não foi enviado CELO suficiente");
collection.transferFrom(address(this), msg.sender, tokenId);
forSale = false;
canRedeem = true;
}
function redeem(uint256 _amount) external {
require(canRedeem, "Resgate não disponível");
uint256 totalCelo = address(this).balance;
uint256 toRedeem = _amount * totalCelo / totalSupply();
_burn(msg.sender, _amount);
payable(msg.sender).transfer(toRedeem);
}
}
Vamos tentar entender o que esse contrato inteligente faz.
Aqui FractionalizedNFT herda ERC20, Ownable, ERC20Permit, ERC721Holder.
IERC721 public collection;
uint256 public tokenId;
bool public initialized = false;
bool public forSale = false;
uint256 public salePrice;
bool public canRedeem = false;
A variável collection do tipo IERC721, contém o endereço do contrato inteligente NFT que implantamos anteriormente. tokenId, do tipo uint256 contém o id do NFT.
initialized, forSale, canRedeem do tipo bool, são sinalizadores. O sinalizador initialized é usado para informar que o preço do NFT está definido, o endereço NFT é armazenado na variável da coleção, o tokenId é inicializado, o NFT é transferido do proprietário para o contrato inteligente e os tokens ERC-20 são cunhados para o proprietário do NFT. O sinalizador forSale é usado para informar que o NFT está à venda. O sinalizador canRedeem é usado para informar que o NFT foi vendido e os usuários podem resgatar seu token ERC-20. salePrice é o preço do NFT.
constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {}
Esta é a função executada quando o contrato inteligente é implantado. O ERC20 assume o nome e o símbolo do token como argumento, enquanto o ERC20Permit usa apenas o nome do token como argumento.
ERC20Permit é a especificação EIP que permite aos usuários aprovar transferências de token sem gastar taxas de gás.
function initialize(address _collection, uint256 _tokenId, uint256 _amount) external onlyOwner {
require(!initialized, "Já inicializado");
require(_amount > 0, "O montante precisa ser superior a 0");
collection = IERC721(_collection);
collection.safeTransferFrom(msg.sender, address(this), _tokenId);
tokenId = _tokenId;
initialized = true;
_mint(msg.sender, _amount);
}
A função initialize está usando address, _tokenId e _amount do NFT. O proprietário só pode invocar esta função.
Ela verifica se o contrato já foi inicializado. Caso contrário, ela verifica a outra condição, verificando se o valor enviado é maior que 0. Aqui, o valor se refere ao número total de tokens ERC-20 que serão cunhados.
A variável collection do tipo IERC721 é inicializada. Aqui, a variável de coleção contém o endereço de um NFT. A função safeTransferFrom transfere o NFT do proprietário para o contrato inteligente, ou seja, para si mesmo. A variável tokenId armazena o ID do token. O sinalizador initialized é marcado como verdadeiro (true). A função _mint gera tokens ERC-20 para o proprietário.
function putForSale(uint256 price) external onlyOwner {
salePrice = price;
forSale = true;
}
A função putForSale usa o preço como argumento. Ele define a variável salePrice do tipo uint256. É o preço de um NFT. Além disso, a função torna o sinalizador forSale verdadeiro.
function purchase() external payable {
require(forSale, "Não está à venda");
require(msg.value >= salePrice, "Não foi enviado CELO suficiente");
collection.transferFrom(address(this), msg.sender, tokenId);
forSale = false;
canRedeem = true;
}
A função purchase é uma função pagável, ou seja, você pode enviar CELO para esta função.
Primeiramente, ele verifica se o sinalizador forSale é verdadeiro e se o CELO enviado é maior ou igual ao preço de venda. Se ambas as condições forem atendidas, o NFT é transferido do contrato NFTFractionalized para o comprador que enviou o CELO.
O sinalizador forSale está definido como falso e agora as pessoas podem resgatar seus tokens ERC-20 com CELO. Este sinalizador é definido como verdadeiro.
function redeem(uint256 _amount) external {
require(canRedeem, "Resgate não disponível");
uint256 totalCelo = address(this).balance;
uint256 toRedeem = _amount * totalCelo / totalSupply();
_burn(msg.sender, _amount);
payable(msg.sender).transfer(toRedeem);
}
A função redeem considera o amount como um argumento. As pessoas podem enviar tokens ERC-20 parciais ou completos que estão segurando para esse NFT.
Primeiro, ele verifica se o sinalizador canRedeem está definido como verdadeiro. Em seguida, ele verifica o contrato inteligente CELO total que está segurando. Em seguida, calcula o valor de CELO que precisa ser resgatado. Ele queima o token ERC-20 enviado e transfere o CELO calculado para o chamador desta função.
Front-end
Uma vez que terminarmos de codificar nossos contratos inteligentes, vamos começar com nosso Front-end.
Para o front-end, usaremos as seguintes bibliotecas:
- create-react-app;
- Web3;
- @celo/contractkit.
O código do front-end já está pronto. Por favor, clone este repositório.
Criaremos uma única página para que qualquer pessoa possa adquirir o NFT, enviando o valor necessário de CELO.
Aqueles que possuem tokens ERC-20 de NFT fracionado podem resgatá-los de volta ao CELO.
Vamos começar com a parte de codificação.
Vamos editar a página App.jsOur UI e a lógica que vai nessa página.
Precisamos dar uma olhada em duas funções já definidas dentro de src/App.js
1. buyNFT()
export async function buyNFT() {
await window.celo.enable();
const web3 = new Web3(window.celo);
let kit = newKitFromWeb3(web3);
const accounts = await kit.web3.eth.getAccounts();
const user_address = accounts[0];
const contract = new kit.web3.eth.Contract(
FractionalizedNFTABI,
contractAddress
);
let result = await contract.methods.purchase().send({ from: user_address });
console.log(result);
}
Quando acionamos essa função dentro do nosso dApp, qualquer um poderá comprar o NFT pagando o preço.
2. redeemNFT()
export async function redeemNFT() {
let amount = document.getElementById("redeemNFTAmount").value;
console.log(amount);
await window.celo.enable();
const web3 = new Web3(window.celo);
let kit = newKitFromWeb3(web3);
const accounts = await kit.web3.eth.getAccounts();
const user_address = accounts[0];
const contract = new kit.web3.eth.Contract(
FractionalizedNFTABI,
contractAddress
);
let result = await contract.methods
.redeem(amount)
.send({ from: user_address });
console.log(result);
}
As pessoas poderão recuperar o CELO assim que enviarem seus tokens ERC-20 para o contrato. Na verdade, elas não precisam enviar os tokens. Elas só precisam executar a função, seus tokens serão queimados dentro do contrato.
O front-end final se parece com isso.
Quando você abrir esta página, o CeloExtensionWallet solicitará que você se conecte a este site.
Abaixo está um pequeno vídeo sobre como essa funcionalidade funciona.
Como não tenho CELO suficiente, não poderei comprar o NFT, mas se você tiver CELO suficiente, poderá comprá-lo.
Aqui está o link para a demonstração.
Espero que você tenha amado esse tutorial.
Obrigado
Sobre o Autor
- Aviraj Khare: Ex Gojek, no espaço Web3 desde 2016
Referências
Artigo escrito por Aviraj Khare e traduzido por Marcelo Panegali
Latest comments (0)