PreSale
0xb99d5c89dc8468090b53704917e2a8daef7a6919
Verification
Verified
v0.8.30+commit.73712a01
Type
Contract
6,985 bytes
ABI entries
33
15 read · 9 write
License
mit
Contract information
- Address
- 0xb99d5c89dc8468090b53704917e2a8daef7a6919
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.30+commit.73712a01
- Optimization
- Enabled
- Creator
- 0xf51FDDD34e…941b6A4e14
- Creation tx
- 0xe5deb2a8e2…b467d9f0ad
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (15)
currentPhase() → uint8
distributed(address) → bool
getWinnerAddresses() → address[]
hardCap() → uint256
isWinnerAdded(address) → bool
maxPerWallet() → uint256
maxSupply() → uint256
mintPrice() → uint256
owner() → address
reservations(address) → uint256
softCap() → uint256
totalEthRaised() → uint256
totalReserved() → uint256
winnerAddresses(uint256) → address
winners(address) → uint256
Events (8)
DistributedEthWithdrawnOwnershipTransferredPhaseChangedRefundClaimedReservationCancelledReservedWinnerSet
ABI
[
{
"inputs": [
{
"internalType": "uint256",
"name": "_maxSupply",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_mintPrice",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_maxPerWallet",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_softCap",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_hardCap",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "winner",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "Distributed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "EthWithdrawn",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "enum PreSale.Phase",
"name": "newPhase",
"type": "uint8"
},
{
"indexed": false,
"internalType": "uint256",
"name": "timestamp",
"type": "uint256"
}
],
"name": "PhaseChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "user",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "timestamp",
"type": "uint256"
}
],
"name": "RefundClaimed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "user",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "timestamp",
"type": "uint256"
}
],
"name": "ReservationCancelled",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "user",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "timestamp",
"type": "uint256"
}
],
"name": "Reserved",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "winner",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "WinnerSet",
"type": "event"
},
{
"inputs": [],
"name": "cancelReservation",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "claimRefund",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "currentPhase",
"outputs": [
{
"internalType": "enum PreSale.Phase",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "nftContractAddress",
"type": "address"
},
{
"internalType": "address[]",
"name": "_winners",
"type": "address[]"
}
],
"name": "distribute",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "nftContractAddress",
"type": "address"
},
{
"internalType": "uint256",
"name": "startIndex",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "count",
"type": "uint256"
}
],
"name": "distributeBatch",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "distributed",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getWinnerAddresses",
"outputs": [
{
"internalType": "address[]",
"name": "",
"type": "address[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "hardCap",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "isWinnerAdded",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "maxPerWallet",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "maxSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "mintPrice",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "reservations",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
}
],
"name": "reserve",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "enum PreSale.Phase",
"name": "newPhase",
"type": "uint8"
}
],
"name": "setPhase",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "_winners",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "_amounts",
"type": "uint256[]"
}
],
"name": "setWinners",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "softCap",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalEthRaised",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalReserved",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "winnerAddresses",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "winners",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "withdrawETH",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// src/Ownable.sol
/// @title Ownable
/// @author SquiBid
/// @notice A simple ownership contract.
abstract contract Ownable {
address private _owner;
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
constructor() {
_owner = msg.sender;
emit OwnershipTransferred(address(0), msg.sender);
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == msg.sender, "Ownable: caller is not the owner");
_;
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(
newOwner != address(0),
"Ownable: new owner is the zero address"
);
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// src/ReentrancyGuard.sol
/// @title ReentrancyGuard
/// @author SquiBid
/// @notice A simple reentrancy guard to prevent reentrancy attacks.
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
// src/PreSale.sol
/// @title Squibid ($SB)
/// @notice SquiBid is a decentralized, on-chain collectible sale infrastructure that empowers creators and projects.
/// @dev Web: http://squibid.io/ · X: https://x.com/Squibid
/// @custom:version squihood-syndicate-v1
///
/// Squibid allows you to discover, bid on, and collect NFTs through a fair and transparent Initial Collectible Offering process.
/// Our platform ensures that genuine supporters get fair access to the most anticipated drops.
///
contract PreSale is Ownable, ReentrancyGuard {
enum Phase {
Open,
Closed,
Refund,
NftDistribution
}
Phase public currentPhase;
// Pre-sale configuration parameters
uint256 public immutable maxSupply;
uint256 public immutable mintPrice;
uint256 public immutable maxPerWallet;
uint256 public immutable softCap;
uint256 public immutable hardCap;
uint256 public totalReserved;
uint256 public totalEthRaised; // Net active ETH raised (subtracts cancellations/refunds)
// User reservations and distribution info
mapping(address => uint256) public reservations;
mapping(address => uint256) public winners;
mapping(address => bool) public distributed;
// Winners tracking
address[] public winnerAddresses;
mapping(address => bool) public isWinnerAdded;
// Events
event Reserved(
address indexed user,
uint256 quantity,
uint256 amount,
uint256 timestamp
);
event ReservationCancelled(
address indexed user,
uint256 quantity,
uint256 amount,
uint256 timestamp
);
event RefundClaimed(
address indexed user,
uint256 quantity,
uint256 amount,
uint256 timestamp
);
event PhaseChanged(Phase indexed newPhase, uint256 timestamp);
event WinnerSet(address indexed winner, uint256 amount);
event Distributed(address indexed winner, uint256 amount);
event EthWithdrawn(address indexed owner, uint256 amount);
constructor(
uint256 _maxSupply,
uint256 _mintPrice,
uint256 _maxPerWallet,
uint256 _softCap,
uint256 _hardCap
) {
require(_maxSupply > 0, "Invalid max supply");
require(_mintPrice > 0, "Invalid mint price");
require(_maxPerWallet > 0, "Invalid max per wallet");
require(_softCap > 0, "Invalid soft cap");
require(_hardCap >= _softCap, "Hard cap must be >= soft cap");
maxSupply = _maxSupply;
mintPrice = _mintPrice;
maxPerWallet = _maxPerWallet;
softCap = _softCap;
hardCap = _hardCap;
currentPhase = Phase.Closed; // Starts Closed
}
function reserve(uint256 quantity) external payable nonReentrant {
require(currentPhase == Phase.Open, "Pre-sale is not open");
require(quantity > 0, "Quantity must be > 0");
require(
reservations[msg.sender] + quantity <= maxPerWallet,
"Exceeds max per wallet limit"
);
uint256 requiredEth = quantity * mintPrice;
require(msg.value == requiredEth, "Incorrect ETH amount sent");
// Enforce hard cap limit
require(
totalEthRaised + msg.value <= hardCap,
"Exceeds hard cap limit"
);
reservations[msg.sender] += quantity;
totalReserved += quantity;
totalEthRaised += msg.value;
emit Reserved(msg.sender, quantity, msg.value, block.timestamp);
}
function cancelReservation() external nonReentrant {
require(currentPhase == Phase.Open, "Can only cancel in Open phase");
uint256 quantity = reservations[msg.sender];
require(quantity > 0, "No reservation to cancel");
uint256 refundAmount = quantity * mintPrice;
reservations[msg.sender] = 0;
totalReserved -= quantity;
totalEthRaised -= refundAmount;
(bool success, ) = msg.sender.call{value: refundAmount}("");
require(success, "ETH refund transfer failed");
emit ReservationCancelled(
msg.sender,
quantity,
refundAmount,
block.timestamp
);
}
function claimRefund() external nonReentrant {
require(
currentPhase == Phase.Refund,
"Can only claim refund in Refund phase"
);
uint256 quantity = reservations[msg.sender];
require(quantity > 0, "No reservation to refund");
uint256 refundAmount = quantity * mintPrice;
reservations[msg.sender] = 0;
totalReserved -= quantity;
totalEthRaised -= refundAmount;
(bool success, ) = msg.sender.call{value: refundAmount}("");
require(success, "ETH refund transfer failed");
emit RefundClaimed(msg.sender, quantity, refundAmount, block.timestamp);
}
function setPhase(Phase newPhase) external onlyOwner {
currentPhase = newPhase;
emit PhaseChanged(newPhase, block.timestamp);
}
function setWinners(
address[] calldata _winners,
uint256[] calldata _amounts
) external onlyOwner {
require(
currentPhase == Phase.NftDistribution,
"Not in NftDistribution phase"
);
require(_winners.length == _amounts.length, "Mismatched input arrays");
for (uint256 i = 0; i < _winners.length; i++) {
address winner = _winners[i];
uint256 amount = _amounts[i];
require(winner != address(0), "Invalid winner address");
winners[winner] = amount;
if (!isWinnerAdded[winner]) {
isWinnerAdded[winner] = true;
winnerAddresses.push(winner);
}
emit WinnerSet(winner, amount);
}
}
function distribute(
address nftContractAddress,
address[] calldata _winners
) external onlyOwner nonReentrant {
require(
currentPhase == Phase.NftDistribution,
"Not in NftDistribution phase"
);
require(
nftContractAddress != address(0),
"Invalid NFT contract address"
);
for (uint256 i = 0; i < _winners.length; i++) {
address winner = _winners[i];
uint256 amount = winners[winner];
if (amount > 0 && !distributed[winner]) {
distributed[winner] = true;
(bool success, ) = nftContractAddress.call(
abi.encodeWithSignature(
"mint(address,uint256)",
winner,
amount
)
);
require(success, "NFT mint call failed");
emit Distributed(winner, amount);
}
}
}
function distributeBatch(
address nftContractAddress,
uint256 startIndex,
uint256 count
) external onlyOwner nonReentrant {
require(
currentPhase == Phase.NftDistribution,
"Not in NftDistribution phase"
);
require(
nftContractAddress != address(0),
"Invalid NFT contract address"
);
uint256 length = winnerAddresses.length;
require(startIndex < length, "Start index out of bounds");
uint256 endIndex = startIndex + count;
if (endIndex > length) {
endIndex = length;
}
for (uint256 i = startIndex; i < endIndex; i++) {
address winner = winnerAddresses[i];
uint256 amount = winners[winner];
if (amount > 0 && !distributed[winner]) {
distributed[winner] = true;
(bool success, ) = nftContractAddress.call(
abi.encodeWithSignature(
"mint(address,uint256)",
winner,
amount
)
);
require(success, "NFT mint call failed");
emit Distributed(winner, amount);
}
}
}
function withdrawETH() external onlyOwner nonReentrant {
uint256 balance = address(this).balance;
require(balance > 0, "No ETH to withdraw");
(bool success, ) = msg.sender.call{value: balance}("");
require(success, "ETH withdrawal failed");
emit EthWithdrawn(msg.sender, balance);
}
function getWinnerAddresses() external view returns (address[] memory) {
return winnerAddresses;
}
}
Chain explorer2841msChain node89ms