Em uma economia tokenizada, ingressos é um ótimo case de uso para negociação para redução de fraudes e permitir um mercado secundário global.
Os problema atual basicamente se consiste em uma pessoa que compra o ingresso e para vende-lo necessita de serviços intermediários que faz com que o comprador desconfie. Sem falar de alguns vendedores que vendem o mesmo ingresso para dezenas de pessoas.

Se agora tudo pode ser tokenizado, imagina que nosso ingresso se tornou um NFT e as regras de pagamentos são aplicadas diretamente na negociação do ativo e não via intermediários.

Então vamos usar o poder dos contratos inteligentes para evoluir a negociação dos ingressos.
Vamos criar um contrato para que usuários possam criar seus ingressos como NFTs e colocá-los a venda e receber o pagamento via USDC(Dólar tokenizado) e somente após o pagamento o ingresso é transferido.
Mas o que é Solidity?
Solidity é uma linguagem de programação para contratos inteligentes, muito usada em diversas plataformas de blockchain, sendo a mais conhecida o Ethereum.
O que eu preciso saber antes de começar?
Idealmente, você deve ter alguma familiaridade com programação e um entendimento básico de blockchain.
Como funciona o Contrato TicketsMarketplace?
O contrato TicketsMarketplace
serve como um exemplo de mercado de NFTs, ele foi construído com o padrão ERC1155 para tokens e se beneficia de vários contratos do OpenZeppelin, uma biblioteca cheia de contratos inteligentes seguros.
Algumas funções e propriedades que esse contrato tem:
Structs
No contrato, temos uma struct
chamada TokenData
:
Essa struct
é usada para armazenar informações sobre um token, como o proprietário do token, o preço do token, se o token está à venda e se o token foi aprovado.
Atributos
Temos também alguns atributos importantes no contrato. Por exemplo:IERC20 public coinToken;
Este é o token ERC20 que será usado para pagamentos no mercado. Por exemplo, poderia ser um token USDC.
Eventos
Os eventos são uma parte crucial dos contratos Ethereum, pois permitem que os contratos comuniquem que algo importante aconteceu. No nosso contrato, temos dois eventos:
event TokenListed(uint256 tokenId, uint256 price); event TokenSold(uint256 tokenId, uint256 price, address buyer);
O evento TokenListed
é emitido quando um token é listado para venda, e o evento TokenSold
é emitido quando um token é vendido.
Minting
A função mint
é responsável pela criação dos novos tokens. O termo “minting” é usado comumente em criptografia para se referir à criação de novas moedas ou tokens.
Listagem
Depois que um token é criado, o proprietário pode decidir vendê-lo. Isso é feito através da função listTokenForSale
.
Remoção da Listagem
Se o proprietário mudar de ideia e decidir não vender o token, ele pode usar a função removeTokenFromSale
.
Compra
Outra função crucial é a buyToken
, que permite que qualquer pessoa compre um token que esteja à venda.
Funções Adicionais
Temos algumas outras funções importantes no contrato, como safeTransferFrom
e getCoinTokenName
.
safeTransferFrom
: Essa função é uma parte crucial do padrão ERC1155. Ela permite a transferência segura de tokens entre contas. No nosso contrato, adicionamos uma verificação para garantir que apenas o proprietário do token ou um endereço aprovado possa transferir o token.getCoinTokenName
: Esta função retorna o nome do token ERC20 usado para pagamentos no mercado. Isso pode ser útil para informar aos usuários sobre qual token eles precisam ter para comprar tokens no mercado.
Exemplo prático
Aqui está um exemplo de como usar esse contrato:
- Deploy do Contrato: Primeiro, você precisa implantar o contrato na blockchain. Para isso, você precisará do endereço do token ERC20 que será usado para pagamentos (como o USDC).
- Criação de um Token: Com o contrato já implantado, você pode criar um novo token. É só chamar a função
mint
, indicar o endereço do proprietário, o ID do token, a quantidade de tokens a serem criados e quaisquer dados adicionais. - Listagem do Token para Venda: O dono de um token pode listá-lo para venda. É só chamar a função
listTokenForSale
, indicar o ID do token e o preço de venda. - Compra de um Token: Se alguém se interessar pelo token, pode adquiri-lo. Basta chamar a função
buyToken
, indicando o ID do token. Lembrando que é preciso ter saldo suficiente decoinToken
para pagar o preço listado.
Fonte completo
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
contract TicketsMarketplace is
ERC1155Burnable,
ERC1155Holder {
IERC20 public coinToken; // Token usado para pagamento em moeda fiat (e.g., USDC)
struct TokenData {
address owner;
uint256 price;
bool isForSale;
bool isApproved;
}
mapping(uint256 => TokenData) public tokenDetails;
mapping(uint256 => mapping(address => bool)) public tokenApprovals;
event TokenListed(uint256 tokenId, uint256 price);
event TokenSold(uint256 tokenId, uint256 price, address buyer);
constructor(address _coinTokenAddress) ERC1155("") {
coinToken = IERC20(_coinTokenAddress);
}
// Função de mint para criar novos tokens ERC1155 e atribuir propriedade a um endereço específico
function mint(address account, uint256 tokenId, uint256 amount, bytes memory data) external {
_mint(account, tokenId, amount, data);
}
// Permite ao proprietário listar um token para venda com pagamento em coinToken (e.g., USDC)
function listTokenForSale(uint256 tokenId, uint256 price) external {
require(!tokenDetails[tokenId].isForSale, "Token is already listed");
require(price > 0, "Price must be greater than zero");
require(balanceOf(msg.sender, tokenId) >= 1, "You must own the token to list for sale");
_setApprovalForAll(msg.sender, address(this), true);
tokenDetails[tokenId] = TokenData({
owner: msg.sender,
price: price,
isForSale: true,
isApproved: true
});
tokenApprovals[tokenId][address(this)] = true;
emit TokenListed(tokenId, price);
}
// Permite ao proprietário remover um token da venda
function removeTokenFromSale(uint256 tokenId) external {
require(tokenDetails[tokenId].isForSale, "Token is not listed");
require(_msgSender() == tokenDetails[tokenId].owner, "You must be the token owner to remove from sale");
delete tokenDetails[tokenId];
delete tokenApprovals[tokenId][address(this)];
_setApprovalForAll(msg.sender, address(this), false);
emit TokenListed(tokenId, 0);
}
// Permite ao proprietário remover a autorização do contrato do marketplace
function revokeMarketplaceTransfer(uint256 tokenId) external {
require(_msgSender() == tokenDetails[tokenId].owner, "You must be the token owner to revoke authorization");
delete tokenApprovals[tokenId][address(this)];
_setApprovalForAll(msg.sender, address(this), false);
}
// Permite a um comprador adquirir o token com pagamento em coinToken (e.g., USDC)
function buyToken(uint256 tokenId) external {
require(tokenDetails[tokenId].isForSale, "Token is not for sale");
uint256 price = tokenDetails[tokenId].price;
require(price > 0, "Invalid token price");
require(tokenApprovals[tokenId][address(this)], "Marketplace is not authorized to transfer the token");
address owner = tokenDetails[tokenId].owner;
delete tokenDetails[tokenId];
delete tokenApprovals[tokenId][address(this)];
// Verifica se o comprador possui a quantidade suficiente do token ERC20 para o pagamento
require(coinToken.balanceOf(msg.sender) >= price, "Insufficient balance to purchase");
// Realiza a transferência do token ERC20 para o contrato do marketplace
coinToken.transferFrom(msg.sender, owner, price);
// Realiza a transferência do token ERC1155 para o comprador
this.safeTransferFrom(owner, msg.sender, tokenId, 1, "");
emit TokenSold(tokenId, price, msg.sender);
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
require(
isApprovedForAll(from, address(this)),
"ERC1155: caller is not token owner or approved"
);
_safeTransferFrom(from, to, id, amount, data);
}
// EIP2981 standard Interface return. Adds to ERC721 and ERC165 Interface returns.
function supportsInterface(
bytes4 interfaceId
)
public
view
virtual
override(ERC1155, ERC1155Receiver)
returns (bool)
{
return
ERC1155.supportsInterface(interfaceId);
}
// Função para retornar o nome do ERC20 associado ao contrato
function getCoinTokenName() external view returns (string memory) {
return IERC20Metadata(address(coinToken)).name();
}
}
Como testar
- Vá para o Remix Ethereum: Primeiro, acesse o Remix Ethereum em: https://remix.ethereum.org/.
- Crie um novo arquivo de contrato Solidity: No canto esquerdo da interface do usuário, clique no segundo ícone de cima para baixo (ícone do arquivo) para abrir o gerenciador de arquivos. Em seguida, clique no ícone
+
para criar um novo arquivo. Nomeie-o comoTicketsMarketplace.sol
. - Copie o código do contrato: Cole o código do contrato
TicketsMarketplace
fornecido na caixa de texto do novo arquivo - Compile o contrato: No painel à esquerda, clique no ícone do compilador (o terceiro ícone de cima para baixo) e clique em
Compile TicketsMarketplace.sol
. Se o código não apresentar nenhum erro, ele será compilado com sucesso - Implante o contrato: No painel à esquerda, clique no ícone
Deploy & Run Transactions
(o quarto ícone de cima para baixo). Selecione o ambiente adequado (por exemplo,JavaScript VM
). No campoContract
, selecioneTicketsMarketplace
. No campo ao lado dele (valor inicial), insira o endereço do contrato do token ERC20 que será usado como pagamento. Clique emDeplo
- Interagindo com o contrato: Depois de implantar, seu contrato agora estará disponível na seção
Deployed Contracts
na parte inferior do painelDeploy & Run Transactions
. Aqui você pode interagir com o contrato. As funções do contrato estarão disponíveis como botões
Para listar um token para venda:
- Clique em
listTokenForSale
. - Digite o
tokenId
e oprice
nos campos correspondentes. - Clique em
transact
.
Para comprar um token:
- Clique em
buyToken
. - Digite o
tokenId
no campo correspondente. - Clique em
transact
.
E assim por diante, para as outras funções disponíveis.
Por favor, lembre-se de que para fins de teste você pode criar um token ERC20 falso no ambiente de teste. A execução de funções que interagem com tokens reais requer uma configuração de ambiente adequada e a posse dos tokens necessários.
Conclusão
Com esse exemplo espero que você mesmo que não seja desenvolvedor visualize o como a tokenização pode melhorar o setor de ticketeiras. E para os devs que esse guia te dê um bom ponto de partida para começar a brincar com Solidity e contratos inteligentes!
Lembre-se que este é só um exemplo e criar contratos de blockchain na vida real requer um bom conhecimento sobre segurança. Então, continue aprendendo!