// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.2;
// interface need to claim rouge tokens from contract and handle upgraded functions
abstract contract IERC20 {
function balanceOf(address owner) public view virtual returns (uint256);
function transfer(address to, uint256 amount) public virtual;
function allowance(address owner, address spender)
public
view
virtual
returns (uint256);
function totalSupply() public view virtual returns (uint256);
}
// interface to potential future upgraded contract,
// only essential write functions that need check that this contract is caller
abstract contract IUpgradedToken {
function transferByLegacy(
address sender,
address to,
uint256 amount
) public virtual returns (bool);
function transferFromByLegacy(
address sender,
address from,
address to,
uint256 amount
) public virtual returns (bool);
function approveByLegacy(
address sender,
address spender,
uint256 amount
) public virtual;
}
//
// The ultimate ERC20 token contract for TecraCoin project
//
contract TcrToken {
//
// ERC20 basic information
//
uint8 public constant decimals = 8;
string public constant name = "TecraCoin";
string public constant symbol = "TCR";
uint256 private _totalSupply;
uint256 public constant maxSupply = 21000000000000000;
string public constant version = "1";
uint256 public immutable getChainId;
//
// other flags, data and constants
//
address public owner;
address public newOwner;
bool public paused;
bool public deprecated;
address public upgradedAddress;
bytes32 public immutable DOMAIN_SEPARATOR;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 public constant PERMIT_TYPEHASH =
0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
string private constant ERROR_DAS = "Different array sizes";
string private constant ERROR_BTL = "Balance too low";
string private constant ERROR_ATL = "Allowance too low";
string private constant ERROR_OO = "Only Owner";
//
// events
//
event Transfer(address indexed from, address indexed to, uint256 value);
event Paused();
event Unpaused();
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
event AddedToBlacklist(address indexed account);
event RemovedFromBlacklist(address indexed account);
//
// data stores
//
mapping(address => mapping(address => uint256)) private _allowances;
mapping(address => uint256) private _balances;
mapping(address => bool) public isBlacklisted;
mapping(address => bool) public isBlacklistAdmin;
mapping(address => bool) public isMinter;
mapping(address => bool) public isPauser;
mapping(address => uint256) public nonces;
//
// contract constructor
//
constructor() {
owner = msg.sender;
getChainId = block.chainid;
// EIP712 Domain
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
),
keccak256(bytes(name)),
keccak256(bytes(version)),
block.chainid,
address(this)
)
);
}
//
// "approve"
//
function approve(address spender, uint256 amount) external {
if (deprecated) {
return
IUpgradedToken(upgradedAddress).approveByLegacy(
msg.sender,
spender,
amount
);
}
_approve(msg.sender, spender, amount);
}
//
// "burnable"
//
function burn(uint256 amount) external {
require(_balances[msg.sender] >= amount, ERROR_BTL);
_burn(msg.sender, amount);
}
function burnFrom(address from, uint256 amount) external {
require(_allowances[msg.sender][from] >= amount, ERROR_ATL);
require(_balances[from] >= amount, ERROR_BTL);
_approve(msg.sender, from, _allowances[msg.sender][from] - amount);
_burn(from, amount);
}
//
// "transfer"
//
function transfer(address to, uint256 amount) external returns (bool) {
if (deprecated) {
return
IUpgradedToken(upgradedAddress).transferByLegacy(
msg.sender,
to,
amount
);
}
require(_balances[msg.sender] >= amount, ERROR_BTL);
_transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool) {
if (deprecated) {
return
IUpgradedToken(upgradedAddress).transferFromByLegacy(
msg.sender,
from,
to,
amount
);
}
_allowanceTransfer(msg.sender, from, to, amount);
return true;
}
//
// non-ERC20 functionality
//
// Rouge tokens and ETH withdrawal
function acquire(address token) external onlyOwner {
if (token == address(0)) {
payable(owner).transfer(address(this).balance);
} else {
uint256 amount = IERC20(token).balanceOf(address(this));
require(amount > 0, ERROR_BTL);
IERC20(token).transfer(owner, amount);
}
}
//
// "blacklist"
//
function addBlacklister(address user) external onlyOwner {
isBlacklistAdmin[user] = true;
}
function removeBlacklister(address user) external onlyOwner {
isBlacklistAdmin[user] = false;
}
modifier onlyBlacklister {
require(isBlacklistAdmin[msg.sender], "Not a Blacklister");
_;
}
modifier notOnBlacklist(address user) {
require(!isBlacklisted[user], "Address on blacklist");
_;
}
function addBlacklist(address user) external onlyBlacklister {
isBlacklisted[user] = true;
emit AddedToBlacklist(user);
}
function removeBlacklist(address user) external onlyBlacklister {
isBlacklisted[user] = false;
emit RemovedFromBlacklist(user);
}
function burnBlackFunds(address user) external onlyOwner {
require(isBlacklisted[user], "Address not on blacklist");
_burn(user, _balances[user]);
}
//
// "bulk transfer"
//
// transfer to list of address-amount
function bulkTransfer(address[] calldata to, uint256[] calldata amount)
external
returns (bool)
{
require(to.length == amount.length, ERROR_DAS);
for (uint256 i = 0; i < to.length; i++) {
require(_balances[msg.sender] >= amount[i], ERROR_BTL);
_transfer(msg.sender, to[i], amount[i]);
}
return true;
}
// transferFrom to list of address-amount
function bulkTransferFrom(
address from,
address[] calldata to,
uint256[] calldata amount
) external returns (bool) {
require(to.length == amount.length, ERROR_DAS);
for (uint256 i = 0; i < to.length; i++) {
_allowanceTransfer(msg.sender, from, to[i], amount[i]);
}
return true;
}
// send same amount to multiple addresses
function bulkTransfer(address[] calldata to, uint256 amount)
external
returns (bool)
{
require(_balances[msg.sender] >= amount * to.length, ERROR_BTL);
for (uint256 i = 0; i < to.length; i++) {
_transfer(msg.sender, to[i], amount);
}
return true;
}
// send same amount to multiple addresses by allowance
function bulkTransferFrom(
address from,
address[] calldata to,
uint256 amount
) external returns (bool) {
require(_balances[from] >= amount * to.length, ERROR_BTL);
for (uint256 i = 0; i < to.length; i++) {
_allowanceTransfer(msg.sender, from, to[i], amount);
}
return true;
}
//
// "mint"
//
modifier onlyMinter {
require(isMinter[msg.sender], "Not a Minter");
_;
}
function addMinter(address user) external onlyOwner {
isMinter[user] = true;
}
function removeMinter(address user) external onlyOwner {
isMinter[user] = false;
}
function mint(address to, uint256 amount) external onlyMinter {
_balances[to] += amount;
_totalSupply += amount;
require(_totalSupply < maxSupply, "You can not mine that much");
emit Transfer(address(0), to, amount);
}
//
// "ownable"
//
modifier onlyOwner {
require(msg.sender == owner, ERROR_OO);
_;
}
function giveOwnership(address _newOwner) external onlyOwner {
newOwner = _newOwner;
}
function acceptOwnership() external {
require(msg.sender == newOwner, ERROR_OO);
newOwner = address(0);
owner = msg.sender;
}
//
// "pausable"
//
function addPauser(address user) external onlyOwner {
isPauser[user] = true;
}
function removePauser(address user) external onlyOwner {
isPauser[user] = false;
}
modifier onlyPauser {
require(isPauser[msg.sender], "Not a Pauser");
_;
}
modifier notPaused {
require(!paused, "Contract is paused");
_;
}
function pause() external onlyPauser notPaused {
paused = true;
emit Paused();
}
function unpause() external onlyPauser {
require(paused, "Contract not paused");
paused = false;
emit Unpaused();
}
//
// "permit"
// Uniswap integration EIP-2612
//
function permit(
address user,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
require(deadline >= block.timestamp, "permit: EXPIRED");
bytes32 digest =
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(
abi.encode(
PERMIT_TYPEHASH,
user,
spender,
value,
nonces[user]++,
deadline
)
)
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(
recoveredAddress != address(0) && recoveredAddress == user,
"permit: INVALID_SIGNATURE"
);
_approve(user, spender, value);
}
//
// upgrade contract
//
function upgrade(address token) external onlyOwner {
deprecated = true;
upgradedAddress = token;
}
//
// ERC20 view functions
//
function balanceOf(address account) external view returns (uint256) {
if (deprecated) {
return IERC20(upgradedAddress).balanceOf(account);
}
return _balances[account];
}
function allowance(address account, address spender)
external
view
returns (uint256)
{
if (deprecated) {
return IERC20(upgradedAddress).allowance(account, spender);
}
return _allowances[account][spender];
}
function totalSupply() external view returns (uint256) {
if (deprecated) {
return IERC20(upgradedAddress).totalSupply();
}
return _totalSupply;
}
//
// internal functions
//
function _approve(
address account,
address spender,
uint256 amount
) private notOnBlacklist(account) notOnBlacklist(spender) notPaused {
_allowances[account][spender] = amount;
emit Approval(account, spender, amount);
}
function _allowanceTransfer(
address spender,
address from,
address to,
uint256 amount
) private {
require(_allowances[from][spender] >= amount, ERROR_ATL);
require(_balances[from] >= amount, ERROR_BTL);
// exception for Uniswap "approve forever"
if (_allowances[from][spender] != type(uint256).max) {
_approve(from, spender, _allowances[from][spender] - amount);
}
_transfer(from, to, amount);
}
function _burn(address from, uint256 amount) private notPaused {
_balances[from] -= amount;
_totalSupply -= amount;
emit Transfer(from, address(0), amount);
}
function _transfer(
address from,
address to,
uint256 amount
) private notOnBlacklist(from) notOnBlacklist(to) notPaused {
require(to != address(0), "Use burn instead");
require(from != address(0), "What a Terrible Failure");
_balances[from] -= amount;
_balances[to] += amount;
emit Transfer(from, to, amount);
}
}
// rav3n_pl was here
{
"compilationTarget": {
"TcrToken.sol": "TcrToken"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AddedToBlacklist","type":"event"},{"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":[],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"RemovedFromBlacklist","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":[],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"acquire","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"addBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"addBlacklister","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"addMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"addPauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","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":"amount","type":"uint256"}],"name":"approve","outputs":[],"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":"to","type":"address[]"},{"internalType":"uint256[]","name":"amount","type":"uint256[]"}],"name":"bulkTransfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"to","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"bulkTransfer","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":"amount","type":"uint256"}],"name":"bulkTransferFrom","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":"amount","type":"uint256[]"}],"name":"bulkTransferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"burnBlackFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deprecated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"giveOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isBlacklistAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isBlacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isPauser","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"removeBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"removeBlacklister","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"removeMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"removePauser","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":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","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":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"upgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upgradedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]