|
// SPDX-License-Identifier: GPL-3.0-or-later |
|
pragma solidity ^0.8.13; |
|
|
|
import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol"; |
|
import {Poke} from "src/Poke.sol"; |
|
|
|
/// @title An experiment in collaborative gaming |
|
/// @author olias.eth |
|
/// @notice This is experimental software, use at your own risk. |
|
contract EthPlaysAuction is Ownable { |
|
/* -------------------------------------------------------------------------- */ |
|
/* TYPES */ |
|
/* -------------------------------------------------------------------------- */ |
|
|
|
struct BannerBid { |
|
address from; |
|
uint256 amount; |
|
string message; |
|
} |
|
|
|
/* -------------------------------------------------------------------------- */ |
|
/* STORAGE */ |
|
/* -------------------------------------------------------------------------- */ |
|
|
|
/// @notice [Contract] The POKE token contract |
|
Poke public poke; |
|
|
|
/// @notice [Parameter] The number of seconds between banner auctions |
|
uint256 public bannerAuctionCooldown; |
|
/// @notice [Parameter] The number of seconds that the banner auction lasts |
|
uint256 public bannerAuctionDuration; |
|
/// @notice [State] The best bid for the current banner auction |
|
BannerBid private bestBannerBid; |
|
/// @notice [State] The block timestamp of the start of the current banner auction |
|
uint256 private bannerAuctionTimestamp; |
|
|
|
/* -------------------------------------------------------------------------- */ |
|
/* EVENTS */ |
|
/* -------------------------------------------------------------------------- */ |
|
|
|
// Auction events |
|
event NewBannerBid(address from, uint256 amount, string message); |
|
event Banner(address from, string message); |
|
|
|
// Parameter update events |
|
event SetBannerAuctionCooldown(uint256 bannerAuctionCooldown); |
|
event SetBannerAuctionDuration(uint256 bannerAuctionDuration); |
|
|
|
/* -------------------------------------------------------------------------- */ |
|
/* ERRORS */ |
|
/* -------------------------------------------------------------------------- */ |
|
|
|
// Auction errors |
|
error InsufficientBalanceForBid(); |
|
error InsufficientBidAmount(); |
|
error AuctionInProgress(); |
|
error AuctionNotActive(); |
|
error AuctionHasNoBids(); |
|
|
|
/* -------------------------------------------------------------------------- */ |
|
/* MODIFIERS */ |
|
/* -------------------------------------------------------------------------- */ |
|
|
|
/* ... redacted ... */ |
|
|
|
/* -------------------------------------------------------------------------- */ |
|
/* INITIALIZATION */ |
|
/* -------------------------------------------------------------------------- */ |
|
|
|
constructor(address pokeAddress) { |
|
poke = Poke(pokeAddress); |
|
|
|
bannerAuctionCooldown = 120; |
|
bannerAuctionDuration = 60; |
|
bestBannerBid = BannerBid(address(0), 0, ""); |
|
} |
|
|
|
/* -------------------------------------------------------------------------- */ |
|
/* GAMEPLAY */ |
|
/* -------------------------------------------------------------------------- */ |
|
|
|
/* ... redacted ... */ |
|
|
|
/* -------------------------------------------------------------------------- */ |
|
/* REDEEMS */ |
|
/* -------------------------------------------------------------------------- */ |
|
|
|
/* ... redacted ... */ |
|
|
|
/* -------------------------------------------------------------------------- */ |
|
/* AUCTIONS */ |
|
/* -------------------------------------------------------------------------- */ |
|
|
|
/// @notice Submit a bid in the active banner auction. |
|
/// @param amount The bid amount in POKE |
|
/// @param message The requested banner message text |
|
function submitBannerBid(uint256 amount, string memory message) external { |
|
if (block.timestamp < bannerAuctionTimestamp + bannerAuctionCooldown) { |
|
revert AuctionNotActive(); |
|
} |
|
|
|
if (poke.balanceOf(msg.sender) < amount) { |
|
revert InsufficientBalanceForBid(); |
|
} |
|
|
|
if (amount <= bestBannerBid.amount) { |
|
revert InsufficientBidAmount(); |
|
} |
|
|
|
if (bestBannerBid.from != address(0)) { |
|
poke.gameTransfer( |
|
address(this), |
|
bestBannerBid.from, |
|
bestBannerBid.amount |
|
); |
|
} |
|
poke.gameTransfer(msg.sender, address(this), amount); |
|
bestBannerBid = BannerBid(msg.sender, amount, message); |
|
emit NewBannerBid(msg.sender, amount, message); |
|
} |
|
|
|
/// @notice End the current banner auction and start the cooldown for the next one. |
|
function rolloverBannerAuction() external { |
|
if ( |
|
block.timestamp < |
|
bannerAuctionTimestamp + |
|
bannerAuctionCooldown + |
|
bannerAuctionDuration |
|
) { |
|
revert AuctionInProgress(); |
|
} |
|
|
|
if (bestBannerBid.from == address(0)) { |
|
revert AuctionHasNoBids(); |
|
} |
|
|
|
emit Banner(bestBannerBid.from, bestBannerBid.message); |
|
bannerAuctionTimestamp = block.timestamp; |
|
bestBannerBid = BannerBid(address(0), 0, ""); |
|
} |
|
|
|
/* -------------------------------------------------------------------------- */ |
|
/* ADMIN */ |
|
/* -------------------------------------------------------------------------- */ |
|
|
|
function setBannerAuctionCooldown(uint256 _bannerAuctionCooldown) |
|
external |
|
onlyOwner |
|
{ |
|
bannerAuctionCooldown = _bannerAuctionCooldown; |
|
emit SetBannerAuctionCooldown(_bannerAuctionCooldown); |
|
} |
|
|
|
function setBannerAuctionDuration(uint256 _bannerAuctionDuration) |
|
external |
|
onlyOwner |
|
{ |
|
bannerAuctionDuration = _bannerAuctionDuration; |
|
emit SetBannerAuctionDuration(_bannerAuctionDuration); |
|
} |
|
} |