Criar um sistema de leilão inglês e holandês

porMatheusem13/06/2022

Nesse artigo iremos aprender a como criar um sistema de leilão inglês e holandês através de um contrato inteligente.

Leilão Inglês para NFT (English Auction)

Como funciona o leilão?

  1. O vendedor da NFT deve implantar este contrato.
  2. O leilão tem duração de 7 dias.
  3. Os participantes podem dar seu lance depositando um valor em ETH maior que o lance atual.
  4. Todos os licitantes podem retirar seu lance se não for o maior lance atual.

Após o leilão terminar:

  1. O licitante do maior lance torna-se o novo proprietário da NFT.
  2. O vendedor recebe o valor de ETH do lance vencedor.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
interface IERC721 {
function safeTransferFrom(
address from,
address to,
uint tokenId
) external;
function transferFrom(
address,
address,
uint
) external;
}
contract EnglishAuction {
event Start();
event Bid(address indexed sender, uint amount);
event Withdraw(address indexed bidder, uint amount);
event End(address winner, uint amount);
IERC721 public nft;
uint public nftId;
address payable public seller;
uint public endAt;
bool public started;
bool public ended;
address public highestBidder;
uint public highestBid;
mapping(address => uint) public bids;
constructor(
address _nft,
uint _nftId,
uint _startingBid
) {
nft = IERC721(_nft);
nftId = _nftId;
seller = payable(msg.sender);
highestBid = _startingBid;
}
function start() external {
require(!started, "iniciado");
require(msg.sender == seller, "não é o vendedor");
nft.transferFrom(msg.sender, address(this), nftId);
started = true;
endAt = block.timestamp + 7 days;
emit Start();
}
function bid() external payable {
require(started, "não iniciado");
require(block.timestamp < endAt, "finalizado");
require(msg.value > highestBid, "lance < maior lance");
if (highestBidder != address(0)) {
bids[highestBidder] += highestBid;
}
highestBidder = msg.sender;
highestBid = msg.value;
emit Bid(msg.sender, msg.value);
}
function withdraw() external {
uint bal = bids[msg.sender];
bids[msg.sender] = 0;
payable(msg.sender).transfer(bal);
emit Withdraw(msg.sender, bal);
}
function end() external {
require(started, "não iniciado");
require(block.timestamp >= endAt, "não finalizado");
require(!ended, "finalizado");
ended = true;
if (highestBidder != address(0)) {
nft.safeTransferFrom(address(this), highestBidder, nftId);
seller.transfer(highestBid);
} else {
nft.safeTransferFrom(address(this), seller, nftId);
}
emit End(highestBidder, highestBid);
}
}

Leilão Holandês para NFT (Dutch Auction)

Como funciona o leilão?

  1. O vendedor de NFT implanta este contrato definindo um preço inicial para o NFT.
  2. O leilão tem duração de 7 dias.
  3. O preço do NFT diminui ao longo do tempo.
  4. Os participantes podem comprar depositando um valor ETH maior que o preço atual calculado pelo contrato inteligente.
  5. O leilão termina quando um comprador realiza a compra do NFT.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
interface IERC721 {
function transferFrom(
address _from,
address _to,
uint _nftId
) external;
}
contract DutchAuction {
uint private constant DURATION = 7 days;
IERC721 public immutable nft;
uint public immutable nftId;
address payable public immutable seller;
uint public immutable startingPrice;
uint public immutable startAt;
uint public immutable expiresAt;
uint public immutable discountRate;
constructor(
uint _startingPrice,
uint _discountRate,
address _nft,
uint _nftId
) {
seller = payable(msg.sender);
startingPrice = _startingPrice;
startAt = block.timestamp;
expiresAt = block.timestamp + DURATION;
discountRate = _discountRate;
require(_startingPrice >= _discountRate * DURATION, "preço inicial < mínimo");
nft = IERC721(_nft);
nftId = _nftId;
}
function getPrice() public view returns (uint) {
uint timeElapsed = block.timestamp - startAt;
uint discount = discountRate * timeElapsed;
return startingPrice - discount;
}
function buy() external payable {
require(block.timestamp < expiresAt, "leilão expirado");
uint price = getPrice();
require(msg.value >= price, "lance < preço");
nft.transferFrom(seller, msg.sender, nftId);
uint refund = msg.value - price;
if (refund > 0) {
payable(msg.sender).transfer(refund);
}
selfdestruct(seller);
}
}

Este sistema de leilões pode ser implantado para uma plataforma de leilões de NFT, após realizar as alterações necessárias para que o contrato suporte múltiplas ofertas de NFT e lances.


Testar no Remix