// 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);
}
}