// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import {IERC20} from "./IERC20.sol";
import {IERC20Errors} from "./Errors.sol";
contract RIZE is IERC20, IERC20Errors {
/**
* @dev Wallet and smart contract variables
*/
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
mapping(address account => uint256) private _lastActive;
bool private activityTracker;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Operation addresses
*/
address private tokenOwner;
address private tokenDelegate;
address private treasury;
// Event emitted when ownder or delegate is changed, for EVM logging
event OwnerSet(address indexed oldOwner, address indexed newOwner);
event DelegateSet(address indexed oldDelegate, address indexed newDelegate);
/**
* @dev Modifier to check if the caller is the owner or delegate
*/
modifier isOwner() {
require(msg.sender == tokenOwner || msg.sender == tokenDelegate, "Caller is not owner/delegate");
_;
}
modifier isSoleOwner() {
require(msg.sender == tokenOwner, "Caller is not owner");
_;
}
/**
* @dev Construction values
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
_mint(msg.sender, 15_000_000_000 * 10 ** decimals());
tokenOwner = msg.sender;
tokenDelegate = msg.sender;
treasury = msg.sender;
}
/**
* @dev Metadata
*/
function name() public view virtual returns (string memory) {
return _name;
}
function symbol() public view virtual returns (string memory) {
return _symbol;
}
function decimals() public view virtual returns (uint8) {
return 18;
}
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
function lastActivity(address account) public view returns (uint256) {
if(_lastActive[account] != 0){
return block.timestamp - _lastActive[account]; // Returns last activity in seconds
}else{
return 0;
}
}
/**
* @dev Last activity tracker
*/
function trackActivity(bool setTracker) public isOwner{
activityTracker = setTracker;
}
function checkActivityTracker() public isOwner view returns(bool){
return activityTracker;
}
function setActivity() public{
_lastActive[msg.sender] = block.timestamp;
}
/**
* @dev Change owner or delegate
* Delegate can be a zero address
*/
function changeOwner(address newOwner) public isSoleOwner {
require(newOwner != address(0), "New owner cannot be a zero address");
emit OwnerSet(tokenOwner, newOwner);
tokenOwner = newOwner;
}
function changeDelegate(address newDelegate) public isOwner {
emit DelegateSet(tokenDelegate, newDelegate);
tokenDelegate = newDelegate;
}
/**
* @dev Return owner/delegate address
*/
function getOwner() isOwner external view returns (address) {
return tokenOwner;
}
function getDelegate() isOwner external view returns (address) {
return tokenDelegate;
}
/**
* @dev See {IERC20-transfer}. Logs activity.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
* - wallet must not be locked
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = msg.sender;
if(activityTracker == true){
setActivity();
}
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = msg.sender;
_approve(owner, spender, value, true);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Skips emitting an {Approval} event indicating an allowance update. This is not
* required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = msg.sender;
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* {walletCheck} verifies if calling address belongs to the team and will prevent the transaction if the
* locking period is still in effect.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev External mint and burn functions to be called by owner or delegate
*/
function mintTokens(uint256 value) external isOwner {
_mint(msg.sender, value);
}
function burnTokens(uint256 value) external isOwner {
_burn(msg.sender, value);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
*
* ```solidity
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
/**
* @dev Tax processing. Sends 2 transactions to the intended recipient and the treasury.
* Additional public function to change the treasury wallet that collects taxes
*/
function transferWithTax(address recipient, uint256 amount, uint8 taxPercentage) public {
require(recipient != address(0), "Recipient cannot be a zero address");
require(taxPercentage <= 100, "Tax percentage equals or is above 100%");
uint tax = (amount / 100) * taxPercentage; // Calculate tax
require(transfer(recipient, amount - tax), "Unable to transfer to recepient");
require(transfer(treasury, tax), "Unable to transfer tax to treasury");
}
event TreasuryUpdated(address indexed oldTreasury, address indexed newTreasury);
function changeTreasury(address newTreasury) isSoleOwner public {
require(newTreasury != address(0), "New owner cannot be a zero address");
emit TreasuryUpdated(treasury, newTreasury);
treasury = newTreasury;
}
function getTreasury() external view returns(address){
return treasury;
}
/**
* @dev Batch transfer function.
* Will throw if the tokenHolder[] length does not match the amouts[] length.
*/
function batchTransfer(address[] calldata tokenHolders, uint256[] calldata amounts) isOwner external {
require(tokenHolders.length == amounts.length, "Holder list does not match amount list");
for(uint256 i = 0; i < tokenHolders.length; i++) {
require(transfer(tokenHolders[i], amounts[i]), "Unable to transfer token to the account");
}
}
}
{
"compilationTarget": {
"RIZE.sol": "RIZE"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"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":"oldDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"newDelegate","type":"address"}],"name":"DelegateSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerSet","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldTreasury","type":"address"},{"indexed":true,"internalType":"address","name":"newTreasury","type":"address"}],"name":"TreasuryUpdated","type":"event"},{"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":"value","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":[{"internalType":"address[]","name":"tokenHolders","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"batchTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burnTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newDelegate","type":"address"}],"name":"changeDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"changeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTreasury","type":"address"}],"name":"changeTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"checkActivityTracker","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDelegate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTreasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"lastActivity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"mintTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"setActivity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"setTracker","type":"bool"}],"name":"trackActivity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"taxPercentage","type":"uint8"}],"name":"transferWithTax","outputs":[],"stateMutability":"nonpayable","type":"function"}]