contract TimberTimeToken is ERC20, ERC20Burnable, Ownable2Step, Pausable, ReentrancyGuard {
using SafeMath for uint256;
string public constant NAME = "TimberTime";
string public constant SYMBOL = "TT";
address public immutable timHagedorn = 0x19a0f118F028Edbe6e42B7E8986a8f696E6c4920; // Address of Tim Hagedorn, the contract owner
uint8 private constant _decimals = 18;
uint256 private constant _initialSupply = 1000000000 * (10 ** uint256(_decimals)); // 1 billion tokens
uint256 public constant MAX_SUPPLY = 1000000000 * (10 ** uint256(_decimals)); // Cap at 1 billion tokens
uint256 public transferFeeRate = 5; // 0.05% fee rate
// Whitelist to control who can interact with the token
mapping(address => bool) public whitelist;
// Events
event FeeRateChanged(uint256 oldFeeRate, uint256 newFeeRate);
event AddressWhitelisted(address indexed user, bool status);
event TokensLocked(address indexed beneficiary, uint256 amount, uint256 unlockDate);
event Staked(address indexed user, uint256 amount);
event Unstaked(address indexed user, uint256 amount, uint256 reward);
// Staking
mapping(address => uint256) public stakedAmounts;
mapping(address => uint256) public stakeStartTime;
uint256 public constant STAKING_REWARD_RATE = 1; // 1% per year
constructor() ERC20(NAME, SYMBOL) {
_mint(msg.sender, _initialSupply);
whitelist[msg.sender] = true; // Initial deployer should be whitelisted
}
// Minting can only be done by the contract owner
function mint(address account, uint256 amount) public onlyOwner whenNotPaused {
require(totalSupply() + amount <= MAX_SUPPLY, "Cannot mint beyond maximum supply");
_mint(account, amount);
}
// Override transfer function to include a fee mechanism and whitelist check
function _transfer(address sender, address recipient, uint256 amount) internal virtual override whenNotPaused {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
require(whitelist[sender] || whitelist[recipient], "One of the addresses must be whitelisted");
uint256 feeAmount = amount.mul(transferFeeRate).div(10000); // Assuming 4 decimal places for percentage
uint256 transferAmount = amount.sub(feeAmount);
super._transfer(sender, recipient, transferAmount);
if (feeAmount > 0) {
_burn(sender, feeAmount); // Burn the fee
}
emit Transfer(sender, recipient, amount);
}
// Function to change fee rate
function setTransferFeeRate(uint256 _transferFeeRate) public onlyOwner {
require(_transferFeeRate <= 100, "Fee must not exceed 1%");
emit FeeRateChanged(transferFeeRate, _transferFeeRate);
transferFeeRate = _transferFeeRate;
}
// Governance functions
function pause() public onlyOwner {
_pause();
}
function unpause() public onlyOwner {
_unpause();
}
// Whitelist management
function addToWhitelist(address _address) public onlyOwner {
whitelist[_address] = true;
emit AddressWhitelisted(_address, true);
}
function removeFromWhitelist(address _address) public onlyOwner {
whitelist[_address] = false;
emit AddressWhitelisted(_address, false);
}
// Staking functionality
function stake(uint256 amount) external whenNotPaused {
require(amount > 0, "Cannot stake 0");
stakedAmounts[msg.sender] = stakedAmounts[msg.sender].add(amount);
stakeStartTime[msg.sender] = block.timestamp;
_transfer(msg.sender, address(this), amount); // Stake by transferring to contract
emit Staked(msg.sender, amount);
}
function unstake(uint256 amount) external whenNotPaused nonReentrant {
require(stakedAmounts[msg.sender] >= amount, "Not enough staked");
uint256 reward = calculateReward(msg.sender, amount);
stakedAmounts[msg.sender] = stakedAmounts[msg.sender].sub(amount);
_transfer(address(this), msg.sender, amount.add(reward)); // Unstake and send reward
emit Unstaked(msg.sender, amount, reward);
}
function calculateReward(address account, uint256 amount) public view returns (uint256) {
uint256 timeStaked = block.timestamp.sub(stakeStartTime[account]);
uint256 dailyRewardRate = STAKING_REWARD_RATE.mul(1e18).div(365 days); // Convert annual rate to daily rate
uint256 reward = amount.mul(timeStaked).mul(dailyRewardRate).div(1e18); // Avoid precision loss with 1e18
return reward;
}
// Lock tokens functionality with events
mapping(address => LockInfo) private _locked;
struct LockInfo {
uint256 amount;
uint256 releaseTime;
}
function lockTokens(address _beneficiary, uint256 _amount, uint256 _unlockDate) public onlyOwner whenNotPaused {
require(_unlockDate > block.timestamp, "Unlock time should be in the future");
require(_amount <= balanceOf(owner()), "Not enough tokens to lock");
_transfer(owner(), address(this), _amount);
_locked[_beneficiary] = LockInfo(_amount, _unlockDate);
emit TokensLocked(_beneficiary, _amount, _unlockDate);
}
function unlockTokens() public whenNotPaused {
LockInfo storage lockInfo = _locked[msg.sender];
require(block.timestamp >= lockInfo.releaseTime, "Tokens are still locked");
require(lockInfo.amount > 0, "No tokens locked for this address");
uint256 amount = lockInfo.amount;
_locked[msg.sender] = LockInfo(0, block.timestamp); // Reset lock info
_transfer(address(this), msg.sender, amount);
}
TimberTime coin contract 🔺per grok
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/security/Pausable.sol"; import "@openzeppelin/contracts/access/Ownable2Step.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract TimberTimeToken is ERC20, ERC20Burnable, Ownable2Step, Pausable, ReentrancyGuard { using SafeMath for uint256; string public constant NAME = "TimberTime"; string public constant SYMBOL = "TT";
}