Address
0xc8d6fabbb6ba4d9231504e705ebfdf42fa479aa9Current Holdings
$0.00
TXs sent
not counted
First Active
2026-03-03
block 25,931,485
Last Active
128 days ago
block 26,522,534
Funded By
not identified
Net worth historyi
No net-worth snapshots recorded yet
partial matchHotspotsolc 0.8.21+commit.d9974bedruntime partial · creation partial
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* HOTSPOT (Hotspot)
* A fixed single-supply ERC-20 token deployed on PulseChain.
*
* Features:
* - Fixed total supply of 1 Hotspot (minted once to deployer)
* - Owner is always exempt from trading restrictions
* - Airdrop: send tokens to multiple wallets in one transaction
* - Ownership transfer and renounce supported
*/
abstract contract Ownable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event OwnershipRenounced(address indexed previousOwner);
error NotOwner();
error ZeroAddress();
constructor(address initialOwner) {
if (initialOwner == address(0)) revert ZeroAddress();
_owner = initialOwner;
emit OwnershipTransferred(address(0), initialOwner);
}
modifier onlyOwner() {
if (msg.sender != _owner) revert NotOwner();
_;
}
function owner() public view returns (address) {
return _owner;
}
function transferOwnership(address newOwner) external onlyOwner {
if (newOwner == address(0)) revert ZeroAddress();
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
function renounceOwnership() external onlyOwner {
emit OwnershipRenounced(_owner);
_owner = address(0);
}
}
contract Hotspot is Ownable {
// ── Metadata ──────────────────────────────────────────────────────────────
string public constant name = "Hotspot";
string public constant symbol = "Hotspot";
uint8 public constant decimals = 18;
// ── Supply ────────────────────────────────────────────────────────────────
uint256 public constant TOTAL_SUPPLY = 1 * 10 ** uint256(decimals);
// ── State ─────────────────────────────────────────────────────────────────
bool public tradingEnabled;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
// ── Events ────────────────────────────────────────────────────────────────
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
event TradingStarted(uint256 timestamp);
event TradingStopped(uint256 timestamp);
event AirdropSent(address indexed sender, uint256 recipientCount, uint256 totalAmount);
// ── Errors ────────────────────────────────────────────────────────────────
error TradingNotEnabled();
error InsufficientBalance();
error InsufficientAllowance();
error TransferToZeroAddress();
error ApproveToZeroAddress();
error TradingAlreadyInThisState();
error AirdropArrayMismatch();
error AirdropEmptyList();
error AirdropTooManyRecipients();
error AirdropZeroAmount();
error AirdropInsufficientBalance();
// ── Constructor ───────────────────────────────────────────────────────────
constructor() Ownable(msg.sender) {
_balances[msg.sender] = TOTAL_SUPPLY;
emit Transfer(address(0), msg.sender, TOTAL_SUPPLY);
// Trading starts DISABLED — owner must call startTrading() to open it
}
// ── Trading Control ───────────────────────────────────────────────────────
/// @notice Enable trading for all holders. Only owner.
function startTrading() external onlyOwner {
if (tradingEnabled) revert TradingAlreadyInThisState();
tradingEnabled = true;
emit TradingStarted(block.timestamp);
}
/// @notice Disable trading for all non-owner holders. Only owner.
function stopTrading() external onlyOwner {
if (!tradingEnabled) revert TradingAlreadyInThisState();
tradingEnabled = false;
emit TradingStopped(block.timestamp);
}
// ── Airdrop ───────────────────────────────────────────────────────────────
/**
* @notice Send the same fixed amount of Hotspot to multiple recipients.
* @dev Caller must hold enough tokens. Max 500 recipients per call.
* Bypasses trading gate — airdrop always works regardless of
* tradingEnabled state, so you can airdrop before launch.
* @param recipients Array of wallet addresses to receive tokens.
* @param amount Amount of Hotspot (in wei units) each recipient receives.
*/
function airdropEqual(address[] calldata recipients, uint256 amount) external {
if (recipients.length == 0) revert AirdropEmptyList();
if (recipients.length > 500) revert AirdropTooManyRecipients();
if (amount == 0) revert AirdropZeroAmount();
uint256 totalNeeded = amount * recipients.length;
if (_balances[msg.sender] < totalNeeded) revert AirdropInsufficientBalance();
unchecked {
_balances[msg.sender] -= totalNeeded;
}
for (uint256 i = 0; i < recipients.length; ) {
address to = recipients[i];
if (to == address(0)) revert TransferToZeroAddress();
unchecked {
_balances[to] += amount;
++i;
}
emit Transfer(msg.sender, to, amount);
}
emit AirdropSent(msg.sender, recipients.length, totalNeeded);
}
/**
* @notice Send different amounts of Hotspot to multiple recipients.
* @dev recipients[i] receives amounts[i]. Arrays must be same length.
* Max 500 recipients per call.
* @param recipients Array of wallet addresses.
* @param amounts Corresponding array of Hotspot amounts (in wei units).
*/
function airdropCustom(address[] calldata recipients, uint256[] calldata amounts) external {
if (recipients.length == 0) revert AirdropEmptyList();
if (recipients.length != amounts.length) revert AirdropArrayMismatch();
if (recipients.length > 500) revert AirdropTooManyRecipients();
// Pre-calculate total to validate balance upfront (safe, avoids partial sends)
uint256 totalNeeded = 0;
for (uint256 i = 0; i < amounts.length; ) {
if (amounts[i] == 0) revert AirdropZeroAmount();
unchecked {
totalNeeded += amounts[i];
++i;
}
}
if (_balances[msg.sender] < totalNeeded) revert AirdropInsufficientBalance();
unchecked {
_balances[msg.sender] -= totalNeeded;
}
for (uint256 i = 0; i < recipients.length; ) {
address to = recipients[i];
if (to == address(0)) revert TransferToZeroAddress();
unchecked {
_balances[to] += amounts[i];
++i;
}
emit Transfer(msg.sender, to, amounts[i]);
}
emit AirdropSent(msg.sender, recipients.length, totalNeeded);
}
// ── ERC-20 Standard ───────────────────────────────────────────────────────
function totalSupply() external pure returns (uint256) {
return TOTAL_SUPPLY;
}
function balanceOf(address account) external view returns (uint256) {
return _balances[account];
}
function allowance(address tokenOwner, address spender) external view returns (uint256) {
return _allowances[tokenOwner][spender];
}
function approve(address spender, uint256 amount) external returns (bool) {
if (spender == address(0)) revert ApproveToZeroAddress();
_allowances[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) external returns (bool) {
_transfer(msg.sender, to, amount);
return true;
}
function transferFrom(address from, address to, uint256 amount) external returns (bool) {
uint256 currentAllowance = _allowances[from][msg.sender];
if (currentAllowance != type(uint256).max) {
if (currentAllowance < amount) revert InsufficientAllowance();
unchecked { _allowances[from][msg.sender] = currentAllowance - amount; }
}
_transfer(from, to, amount);
return true;
}
// ── Internal ──────────────────────────────────────────────────────────────
function _transfer(address from, address to, uint256 amount) internal {
if (to == address(0)) revert TransferToZeroAddress();
// Owner is always exempt from the trading gate
if (!tradingEnabled && from != owner() && to != owner()) {
revert TradingNotEnabled();
}
uint256 fromBalance = _balances[from];
if (fromBalance < amount) revert InsufficientBalance();
unchecked {
_balances[from] = fromBalance - amount;
_balances[to] += amount;
}
emit Transfer(from, to, amount);
}
}