// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol"; contract DTRASH is ERC20Votes { uint256 public constant VESTING_DURATION = 730 days; uint256 public constant UNLOCK_START = 365 days; uint256 public unlockTime; mapping(address => uint256) private _lockedBalances; constructor(address[] memory lockedRecipients, uint256[] memory lockedAmounts, address[] memory unlockedRecipients, uint256[] memory unlockedAmounts) ERC20Votes("DecentTrash", "DTRASH") { require(lockedRecipients.length == lockedAmounts.length, "Mismatched locked"); require(unlockedRecipients.length == unlockedAmounts.length, "Mismatched unlocked"); unlockTime = block.timestamp + UNLOCK_START; for(uint i = 0; i < lockedRecipients.length; i++) { _mintAndLock(lockedRecipients[i], lockedAmounts[i]); } for(uint i = 0; i < unlockedRecipients.length; i++) { _mint(unlockedRecipients[i], unlockedAmounts[i]); } } function _mintAndLock(address to, uint256 amount) internal { _mint(to, amount); _lockedBalances[to] += amount; } function _beforeTokenTransfer(address from, address to, uint256 amount) internal override { super._beforeTokenTransfer(from, to, amount); if (from != address(0) && to != address(0)) { // not mint or burn if (_lockedBalances[from] > 0) { // address has locked tokens require(block.timestamp >= unlockTime, "Tokens are locked"); if (block.timestamp < unlockTime + VESTING_DURATION) { // if we are still within vesting period, check xfer amt uint256 timeIntoVesting = block.timestamp - unlockTime; uint256 vestedAmount = (_lockedBalances[from] * timeIntoVesting) / VESTING_DURATION; require(balanceOf(from) - amount >= _lockedBalances[from] - vestedAmount, "Exceeds vested amount"); } } } } }
0.7.1