// SPDX-License-Identifier: MIT
pragma solidity 0.8.27;
interface IERC20 {
function totalSupply() external pure returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, 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 sender, address recipient, uint256 amount) external returns (bool);
}
contract GambleX is IERC20 {
string private constant _name = "GambleX";
string private constant _symbol = "GMBLX";
uint8 private constant _decimals = 18;
uint256 private constant _totalSupply = 100_000_000 * 1e18;
address public immutable feeWallet;
address public immutable mainWallet;
uint256 private constant _FEE_PERCENT = 5; // Represents 0.5%
uint256 private constant _FEE_DIVISOR = 1000;
struct Account {
uint256 balance;
bool isBlacklisted;
}
mapping(address => Account) private _accounts;
mapping(address => mapping(address => uint256)) private _allowances;
address private _owner;
address private _pendingOwner;
error NotOwner();
error Blacklisted(address account);
error InvalidRecipient();
error InsufficientBalance();
error TransferFailed();
error ZeroAddress();
error NoETHToWithdraw();
error TokenAddressNotContract();
error AllowanceExceeded();
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
event AddedToBlacklist(address indexed account);
event RemovedFromBlacklist(address indexed account);
event EmergencyWithdrawal(address indexed token, uint256 amount);
event OwnershipTransferInitiated(address indexed previousOwner, address indexed newOwner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event ETHWithdrawn(address indexed owner, uint256 amount);
modifier onlyOwner() {
if (msg.sender != _owner) revert NotOwner();
_;
}
modifier notBlacklisted(address account) {
if (_accounts[account].isBlacklisted) revert Blacklisted(account);
_;
}
modifier validRecipient(address recipient) {
if (recipient == address(0) || recipient == address(this)) revert InvalidRecipient();
_;
}
constructor(address _feeWalletAddress, address _mainWalletAddress) payable {
if (_feeWalletAddress == address(0)) revert ZeroAddress();
if (_mainWalletAddress == address(0)) revert ZeroAddress();
feeWallet = _feeWalletAddress;
mainWallet = _mainWalletAddress;
_owner = _mainWalletAddress;
_accounts[_mainWalletAddress].balance = _totalSupply;
emit Transfer(address(0), _mainWalletAddress, _totalSupply);
}
receive() external payable {
revert("Cannot send ETH to this contract");
}
fallback() external payable {
revert("Cannot send ETH to this contract");
}
function name() external pure returns (string memory) {
return _name;
}
function symbol() external pure returns (string memory) {
return _symbol;
}
function decimals() external pure returns (uint8) {
return _decimals;
}
function totalSupply() external pure override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) external view override returns (uint256) {
return _accounts[account].balance;
}
function transfer(address recipient, uint256 amount)
external
override
notBlacklisted(msg.sender)
notBlacklisted(recipient)
validRecipient(recipient)
returns (bool)
{
_transfer(msg.sender, recipient, amount);
return true;
}
function allowance(address owner_, address spender) external view override returns (uint256) {
return _allowances[owner_][spender];
}
function approve(address spender, uint256 amount) external override returns (bool) {
if (spender == address(0)) revert ZeroAddress();
if (_allowances[msg.sender][spender] != amount) {
_allowances[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
}
return true;
}
function transferFrom(
address sender,
address recipient,
uint256 amount
)
external
override
notBlacklisted(sender)
notBlacklisted(recipient)
validRecipient(recipient)
returns (bool)
{
uint256 currentAllowance = _allowances[sender][msg.sender];
if (currentAllowance < amount) revert AllowanceExceeded();
unchecked {
_allowances[sender][msg.sender] = currentAllowance - amount;
}
emit Approval(sender, msg.sender, _allowances[sender][msg.sender]);
_transfer(sender, recipient, amount);
return true;
}
function addToBlacklist(address account) external payable onlyOwner {
if (_accounts[account].isBlacklisted) revert Blacklisted(account);
_accounts[account].isBlacklisted = true;
emit AddedToBlacklist(account);
}
function removeFromBlacklist(address account) external payable onlyOwner {
if (!_accounts[account].isBlacklisted) revert Blacklisted(account);
_accounts[account].isBlacklisted = false;
emit RemovedFromBlacklist(account);
}
function emergencyWithdraw(address tokenAddress, uint256 amount) external payable onlyOwner {
if (tokenAddress.code.length == 0) revert TokenAddressNotContract();
bool success = IERC20(tokenAddress).transfer(_owner, amount);
if (!success) revert TransferFailed();
emit EmergencyWithdrawal(tokenAddress, amount);
}
function withdrawETH() external payable onlyOwner {
uint256 ethBalance;
assembly {
ethBalance := selfbalance()
}
if (ethBalance == 0) revert NoETHToWithdraw();
(bool success, ) = _owner.call{value: ethBalance}("");
if (!success) revert TransferFailed();
emit ETHWithdrawn(_owner, ethBalance);
}
function initiateOwnershipTransfer(address newOwner) external payable onlyOwner {
if (newOwner == address(0)) revert ZeroAddress();
_pendingOwner = newOwner;
emit OwnershipTransferInitiated(_owner, newOwner);
}
function acceptOwnership() external {
if (msg.sender != _pendingOwner) revert NotOwner();
if (_owner != _pendingOwner) {
address previousOwner = _owner;
_owner = _pendingOwner;
_pendingOwner = address(0);
emit OwnershipTransferred(previousOwner, _owner);
} else {
_pendingOwner = address(0);
}
}
function _transfer(
address sender,
address recipient,
uint256 amount
)
internal
{
Account storage senderAccount = _accounts[sender];
Account storage recipientAccount = _accounts[recipient];
uint256 senderBalance = senderAccount.balance;
if (senderBalance < amount) revert InsufficientBalance();
uint256 feeAmount = (amount * _FEE_PERCENT + (_FEE_DIVISOR >> 1)) / _FEE_DIVISOR;
uint256 transferAmount = amount - feeAmount;
// Check for rounding errors
require(feeAmount + transferAmount == amount, "Invalid transfer amount");
unchecked {
senderAccount.balance = senderBalance - amount;
_accounts[feeWallet].balance += feeAmount;
recipientAccount.balance += transferAmount;
}
emit Transfer(sender, feeWallet, feeAmount);
emit Transfer(sender, recipient, transferAmount);
}
}
{
"compilationTarget": {
"GambleX.sol": "GambleX"
},
"evmVersion": "cancun",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_feeWalletAddress","type":"address"},{"internalType":"address","name":"_mainWalletAddress","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"AllowanceExceeded","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"Blacklisted","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"NoETHToWithdraw","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"TokenAddressNotContract","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AddedToBlacklist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","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":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferInitiated","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":"address","name":"account","type":"address"}],"name":"RemovedFromBlacklist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addToBlacklist","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"feeWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"initiateOwnershipTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mainWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"removeFromBlacklist","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawETH","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]