// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import "https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.3.0/contracts/token/ERC20/IERC20.sol";
import "https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.3.0/contracts/token/ERC20/ERC20.sol";
import "https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.3.0/contracts/access/Ownable.sol";
import "https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.3.0/contracts/security/ReentrancyGuard.sol";
import "https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.3.0/contracts/security/Pausable.sol";
contract SafeMoneyUp is ERC20, Ownable, ReentrancyGuard, Pausable {
uint256 private constant FIXED_SUPPLY = 400 * 1e6 * 1e18;
address private constant DEAD_ADDRESS = 0x000000000000000000000000000000000000dEaD;
mapping(address => bool) public excludedFromFees;
event TokensPurchased(address indexed buyer, uint256 tokensAmount, uint256 ethAmount);
event TokensSold(address indexed seller, uint256 tokensAmount, uint256 ethAmount);
constructor() ERC20("SafeMoney Up", "SMU") {
_mint(address(this), FIXED_SUPPLY);
excludedFromFees[owner()] = true;
}
function getPrice() public view returns (uint256) {
uint256 contractEthBalance = address(this).balance;
uint256 supplyWithoutContract = totalSupply() - balanceOf(address(this)) - balanceOf(DEAD_ADDRESS);
uint256 price = contractEthBalance * 1e18 / supplyWithoutContract;
return price;
}
function buyTokens() public payable whenNotPaused nonReentrant {
require(msg.value > 0, "Amount must be greater than 0");
uint256 price = getPrice();
uint256 tokensToBuy = msg.value * 1e18 / price;
uint256 fee = tokensToBuy * 2 / 100;
uint256 tokensWithFee = tokensToBuy - fee;
if (!excludedFromFees[msg.sender]) {
tokensToBuy = tokensWithFee;
}
_transfer(address(this), msg.sender, tokensToBuy);
emit TokensPurchased(msg.sender, tokensToBuy, msg.value);
}
function sellTokens(uint256 tokensToSell) public whenNotPaused nonReentrant {
require(tokensToSell > 0, "Amount must be greater than 0");
uint256 price = getPrice();
uint256 ethAmount = tokensToSell * price / 1e18;
uint256 fee = ethAmount * 2 / 100;
uint256 ethWithFee = ethAmount - fee;
if (!excludedFromFees[msg.sender]) {
ethAmount = ethWithFee;
}
_transfer(msg.sender, address(this), tokensToSell);
payable(msg.sender).transfer(ethAmount);
emit TokensSold(msg.sender, tokensToSell, ethAmount);
}
function excludeFromFees(address account, bool excluded) public onlyOwner {
require(account != address(0), "Invalid address");
excludedFromFees[account] = excluded;
}
function withdrawTokens(IERC20 token, uint256 amount) public onlyOwner {
require(address(token) != address(0), "Invalid token address");
token.transfer(msg.sender, amount);
}
function transferEthToContract() public payable onlyOwner {
require(msg.value > 0, "Amount must be greater than 0");
}
function pause() public onlyOwner {
_pause();
}
function unpause() public onlyOwner {
_unpause();
}
function receiveETH() external payable {
}
function withdrawETH(uint256 amount) public onlyOwner {
require(amount <= address(this).balance, "Insufficient contract balance");
payable(owner()).transfer(amount);
}
}