Description:
ERC20 token contract with Pausable, Factory capabilities. Standard implementation for fungible tokens on Ethereum.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/* ===========================================================
OpenZeppelin dependencies (flattened for verification)
Version: OpenZeppelin Contracts v5.0.2
=========================================================== */
// --- Context.sol ---
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
}
// --- Ownable.sol ---
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
_transferOwnership(initialOwner);
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
_checkOwner();
_;
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is zero");
_transferOwnership(newOwner);
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// --- ReentrancyGuard.sol ---
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;
}
}
// --- Pausable.sol ---
abstract contract Pausable is Context {
bool private _paused;
event Paused(address account);
event Unpaused(address account);
constructor() {
_paused = false;
}
function paused() public view virtual returns (bool) {
return _paused;
}
modifier whenNotPaused() {
require(!_paused, "Pausable: paused");
_;
}
modifier whenPaused() {
require(_paused, "Pausable: not paused");
_;
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
// --- IERC20.sol ---
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
// --- SafeERC20.sol ---
library Address {
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
require(address(target).code.length > 0, "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
require(success, "Address: low-level call failed");
return returndata;
}
}
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
(bool success, bytes memory returndata) = address(token).call(data);
if (!success) {
if (returndata.length > 0) {
assembly {
revert(add(32, returndata), mload(returndata))
}
} else {
revert("SafeERC20: call failed");
}
}
}
}
/* ===============================================================
PRESALE CONTRACT NPC9000 (direct deploy + verifiable)
=============================================================== */
contract PresaleNPC9000 is Ownable, ReentrancyGuard, Pausable {
using SafeERC20 for IERC20;
IERC20 public immutable token;
uint256 public immutable tokensPerEth;
uint256 public immutable hardCapWei;
bool public autoForwardETH;
uint256 public totalRaised;
uint256 public minContributionWei;
uint256 public maxContributionWei;
mapping(address => uint256) public userContributedWei;
mapping(address => uint256) public purchased;
event Purchased(address indexed buyer, uint256 ethAmount, uint256 tokenAmount);
event Claimed(address indexed buyer, uint256 tokenAmount);
event DepositTokens(address indexed from, uint256 amount);
event WithdrawETH(address indexed to, uint256 amount);
event AutoForwardUpdated(bool enabled);
event LimitsUpdated(uint256 minWei, uint256 maxWei);
constructor(address token_, address initialOwner, bool autoForward_) Ownable(initialOwner) {
require(token_ != address(0), "token zero");
token = IERC20(token_);
tokensPerEth = 800_000 * 1e18;
hardCapWei = 500 ether;
autoForwardETH = autoForward_;
emit AutoForwardUpdated(autoForward_);
}
function saleOpen() public view returns (bool) {
return totalRaised < hardCapWei && !paused();
}
function claimEnabled() public view returns (bool) {
return totalRaised >= hardCapWei;
}
function claimable(address user) external view returns (uint256) {
return claimEnabled() ? purchased[user] : 0;
}
function buyTokens() public payable nonReentrant whenNotPaused {
require(msg.value > 0, "zero ETH");
require(totalRaised < hardCapWei, "hard cap reached");
uint256 newTotal = totalRaised + msg.value;
require(newTotal <= hardCapWei, "exceeds hardcap");
uint256 newUser = userContributedWei[msg.sender] + msg.value;
if (minContributionWei > 0) require(newUser >= minContributionWei, "below min");
if (maxContributionWei > 0) require(newUser <= maxContributionWei, "above max");
uint256 tokenAmount = (msg.value * tokensPerEth) / 1e18;
require(tokenAmount > 0, "too small");
userContributedWei[msg.sender] = newUser;
purchased[msg.sender] += tokenAmount;
totalRaised = newTotal;
emit Purchased(msg.sender, msg.value, tokenAmount);
if (autoForwardETH) {
(bool ok, ) = payable(owner()).call{value: msg.value}("");
require(ok, "ETH forward failed");
}
}
receive() external payable { buyTokens(); }
function claimTokens() external nonReentrant {
require(claimEnabled(), "Claim not enabled");
uint256 amount = purchased[msg.sender];
require(amount > 0, "Nothing to claim");
purchased[msg.sender] = 0;
token.safeTransfer(msg.sender, amount);
emit Claimed(msg.sender, amount);
}
function depositTokens(uint256 amount) external onlyOwner {
require(amount > 0, "amount zero");
token.safeTransferFrom(msg.sender, address(this), amount);
emit DepositTokens(msg.sender, amount);
}
function setAutoForwardETH(bool enabled) external onlyOwner {
autoForwardETH = enabled;
emit AutoForwardUpdated(enabled);
}
function setContributionLimits(uint256 minWei, uint256 maxWei) external onlyOwner {
require(maxWei == 0 || minWei <= maxWei, "bad limits");
minContributionWei = minWei;
maxContributionWei = maxWei;
emit LimitsUpdated(minWei, maxWei);
}
function pause() external onlyOwner { _pause(); }
function unpause() external onlyOwner { _unpause(); }
function withdrawETH(address payable to, uint256 amount) external onlyOwner nonReentrant {
require(to != address(0), "to zero");
(bool ok, ) = to.call{value: amount}("");
require(ok, "ETH transfer failed");
emit WithdrawETH(to, amount);
}
function sweepRemainingTokens(address to) external onlyOwner {
require(claimEnabled(), "not finished");
uint256 bal = token.balanceOf(address(this));
token.safeTransfer(to, bal);
}
function renounceOwnership() public override onlyOwner {
revert("Disabled");
}
}
Submitted on: 2025-10-27 13:32:55
Comments
Log in to comment.
No comments yet.