Lição: 238: Contratos de Leilão
Introdução
Nesta aula, iremos explorar como criar um contrato de leilão usando Solidity. Os leilões são uma forma popular de vender bens e serviços, e os contratos inteligentes nos permitem automatizar e garantir esse processo na blockchain Ethereum. Vamos implementar um contrato de leilão simples que permite aos participantes fazer lances e concluir o leilão.
Conceitos Chave
Antes de mergulharmos no código, vamos recapitular alguns conceitos fundamentais sobre leilões:
- Hora de Início: O leilão tem um horário de início definido.
- Hora de Término: O leilão possui um horário de término definido, após o qual não podem ser feitos lances.
- Lance Mínimo: Cada lance subsequente deve ser maior do que o maior lance atual.
- Lances: Os participantes podem fazer lances até que o leilão termine.
- Seleção do Vencedor: O maior pulador ao final do leilão é o vencedor.
- Retirada: Os licitantes não vencedores devem conseguir retirar seus lances.
Estrutura do Contrato
Nosso contrato de leilão consistirá nos seguintes componentes principais:
- Variáveis de estado para armazenar os parâmetros do leilão.
- Um mapeamento para rastrear os lances.
- Funções para iniciar o leilão, fazer lances e finalizar o leilão.
Implementação
Vamos quebrar a implementação passo a passo.
Passo 1: Definir o Contrato
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Leilao {
address public leiloeiro;
uint public horarioFimLeilao;
uint public maiorLance;
address public maiorLicitante;
bool public encerrado;
mapping(address => uint) public retornosPendentes;
event NovoLance(address indexed licitante, uint valor);
event LeilaoEncerrado(address vencedor, uint valor);
constructor(uint _tempoDeLance) {
leiloeiro = msg.sender;
horarioFimLeilao = block.timestamp + _tempoDeLance;
}
}
Passo 2: Fazer Lances
Agora, implementaremos uma função para fazer lances. A função verificará se o lance é válido com base no status atual do leilão.
function lance() public payable {
require(block.timestamp < horarioFimLeilao, "O leilão já terminou.");
require(msg.value > maiorLance, "O valor do lance não é alto o suficiente.");
// Armazenar o maior lance anterior para retirada
if (maiorLance != 0) {
retornosPendentes[maiorLicitante] += maiorLance;
}
maiorLicitante = msg.sender;
maiorLance = msg.value;
emit NovoLance(msg.sender, msg.value);
}
Passo 3: Retiradas
Em seguida, vamos implementar uma função de retirada para os licitantes não vencedores.
function retirar() public returns (bool) {
uint valor = retornosPendentes[msg.sender];
if (valor > 0) {
retornosPendentes[msg.sender] = 0;
payable(msg.sender).transfer(valor);
return true;
}
return false;
}
Passo 4: Encerrar o Leilão
Finalmente, implementaremos uma função para encerrar o leilão e declarar o vencedor.
function encerrarLeilao() public {
require(msg.sender == leiloeiro, "Apenas o leiloeiro pode encerrar o leilão.");
require(block.timestamp >= horarioFimLeilao, "O leilão ainda não terminou.");
require(!encerrado, "O leilão já foi encerrado.");
encerrado = true;
emit LeilaoEncerrado(maiorLicitante, maiorLance);
// Transferir o valor do maior lance para o leiloeiro
payable(leiloeiro).transfer(maiorLance);
}
Contrato Completo
Aqui está o contrato de leilão completo com todos os componentes combinados:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Leilao {
address public leiloeiro;
uint public horarioFimLeilao;
uint public maiorLance;
address public maiorLicitante;
bool public encerrado;
mapping(address => uint) public retornosPendentes;
event NovoLance(address indexed licitante, uint valor);
event LeilaoEncerrado(address vencedor, uint valor);
constructor(uint _tempoDeLance) {
leiloeiro = msg.sender;
horarioFimLeilao = block.timestamp + _tempoDeLance;
}
function lance() public payable {
require(block.timestamp < horarioFimLeilao, "O leilão já terminou.");
require(msg.value > maiorLance, "O valor do lance não é alto o suficiente.");
if (maiorLance != 0) {
retornosPendentes[maiorLicitante] += maiorLance;
}
maiorLicitante = msg.sender;
maiorLance = msg.value;
emit NovoLance(msg.sender, msg.value);
}
function retirar() public returns (bool) {
uint valor = retornosPendentes[msg.sender];
if (valor > 0) {
retornosPendentes[msg.sender] = 0;
payable(msg.sender).transfer(valor);
return true;
}
return false;
}
function encerrarLeilao() public {
require(msg.sender == leiloeiro, "Apenas o leiloeiro pode encerrar o leilão.");
require(block.timestamp >= horarioFimLeilao, "O leilão ainda não terminou.");
require(!encerrado, "O leilão já foi encerrado.");
encerrado = true;
emit LeilaoEncerrado(maiorLicitante, maiorLance);
payable(leiloeiro).transfer(maiorLance);
}
}
Conclusão
Nesta aula, criamos um contrato de leilão simples em Solidity. Implementamos funcionalidades chave, como fazer lances, retirar fundos e encerrar o leilão. Este conhecimento fundamental pode ser expandido para criar sistemas de leilão mais complexos com recursos adicionais, como preços de reserva, opções de compra imediata e extensões de tempo.
Isso é apenas o começo; sinta-se à vontade para experimentar com o contrato e adicionar mais funcionalidades à medida que você se aprofunda no desenvolvimento de contratos inteligentes!