// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Snapshot.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/security/Pausable.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol"; // CoinOfGrace is an ERC20 token with additional features: // - It can be paused and unpaused by an account with the DEFAULT_ADMIN_ROLE. // - It can be minted by an account with the MINTER_ROLE, up to a maximum supply. // - It charges a 10% fee on transfers, which is sent to the tax address. contract CoinOfGrace is ERC20, ERC20Snapshot, AccessControl, Pausable, ERC20Permit { mapping (address => uint256) private _feesPaid; address private _taxAddress; uint256 private _maxSupply = 47000000 * 10 ** decimals(); // Define the Minter role identifier bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); constructor() ERC20("Coin of Grace", "GRACE") ERC20Permit("Coin of Grace") { // Set the tax address to the contract deployer _taxAddress = msg.sender; // Mint initial supply of tokens to the tax address _mint(_taxAddress, 1000000 * 10 ** decimals()); // Set up roles: the deployer gets the default admin and minter roles _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); _setupRole(MINTER_ROLE, _msgSender()); } // Allows an account with the DEFAULT_ADMIN_ROLE to create a new snapshot function snapshot() public onlyRole(DEFAULT_ADMIN_ROLE) { _snapshot(); } // Allows an account with the DEFAULT_ADMIN_ROLE to pause token transfers function pause() public onlyRole(DEFAULT_ADMIN_ROLE) { _pause(); } // Allows an account with the DEFAULT_ADMIN_ROLE to unpause token transfers function unpause() public onlyRole(DEFAULT_ADMIN_ROLE) { _unpause(); } // Returns the total fees paid by an account function feesPaid(address account) public view returns (uint256) { return _feesPaid[account]; } // Hook that is called before any transfer of tokens // This is used to pause the contract: when the contract is paused, this will revert any transfer function _beforeTokenTransfer(address from, address to, uint256 amount) internal whenNotPaused override(ERC20, ERC20Snapshot) { super._beforeTokenTransfer(from, to, amount); } // Override the standard _transfer function to add the fee and tax logic function _transfer(address sender, address recipient, uint256 amount) internal override { // Calculate the tax amount (10% of the transferred amount) uint256 taxAmount = amount * 10 / 100; // Calculate the net amount to be transferred uint256 netAmount = amount - taxAmount; // Record the tax paid by the sender _feesPaid[sender] += taxAmount; // Transfer the tax to the tax address super._transfer(sender, _taxAddress, taxAmount); // Transfer the net amount to the recipient super._transfer(sender, recipient, netAmount); } // Allows an account with the MINTER_ROLE to mint new tokens, as long as the total supply doesn't exceed the max supply function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) { require(totalSupply() + amount <= _maxSupply, "Exceeds max supply"); _mint(to, amount); } // Allows an account with the DEFAULT_ADMIN_ROLE to withdraw tokens from the contract address function withdraw(uint256 amount) public onlyRole(DEFAULT_ADMIN_ROLE) { _transfer(address(this), _taxAddress, amount); } }