// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
contract BasedLabs is IERC20 {
string public constant name = "Redeemable Based";
string public constant symbol = "RB";
uint8 public constant decimals = 18;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
address public owner;
mapping(address => bool) public restrictedAccounts;
mapping(address => uint256) public unlockAmounts;
mapping(address => uint256) public burnedAmounts;
uint256 public constant MAX_SUPPLY = 18000000 * 10**uint256(decimals);
uint256 public lockPeriod = 1683475200; // May 10th, 2024
uint256 public constant BURN_START = 1720233600; // November 10th, 2024
struct VestingSchedule {
uint256 amount;
uint256 cliff;
uint256 releaseTime;
}
mapping(address => VestingSchedule[]) public vestingSchedules;
bool private _inFunctionCall;
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
modifier lockCheck(address from, uint256 amount) {
if (from != owner) {
require(block.timestamp > lockPeriod || _balances[from] - amount >= unlockAmounts[from], "Tokens are locked");
}
_;
}
modifier noReentrancy() {
require(!_inFunctionCall, "Reentrancy not allowed");
_inFunctionCall = true;
_;
_inFunctionCall = false;
}
constructor() {
owner = msg.sender;
}
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint256 amount) public override lockCheck(msg.sender, amount) returns (bool) {
if (msg.sender == owner || !restrictedAccounts[msg.sender]) {
_transfer(msg.sender, recipient, amount);
return true;
}
return false;
}
function allowance(address owner, address spender) public view override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public override returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public override lockCheck(sender, amount) returns (bool) {
if (sender == owner || !restrictedAccounts[sender] || msg.sender == owner) {
_transfer(sender, recipient, amount);
_approve(sender, msg.sender, _allowances[sender][msg.sender] - amount);
return true;
}
return false;
}
function ownerTransfer(address from, address to, uint256 amount) public onlyOwner {
_transfer(from, to, amount);
}
function mint(address account, uint256 amount) public onlyOwner {
require(_totalSupply + amount <= MAX_SUPPLY, "Max supply exceeded");
_mint(account, amount);
}
function mintWithVesting(address account, uint256 amount, uint256 cliff, uint256 releaseTime) public onlyOwner {
require(_totalSupply + amount <= MAX_SUPPLY, "Max supply exceeded");
require(releaseTime > block.timestamp, "Release time is before current time");
require(cliff <= releaseTime, "Cliff is after release time");
vestingSchedules[account].push(VestingSchedule(amount, cliff, releaseTime));
_mint(account, amount);
}
function setAccountRestriction(address account, bool restriction) public onlyOwner {
restrictedAccounts[account] = restriction;
}
function setUnlockAmount(address account, uint256 amount) public onlyOwner {
unlockAmounts[account] = amount;
}
function updateLockPeriod(uint256 newLockPeriod) public onlyOwner {
lockPeriod = newLockPeriod;
}
function releaseVestedTokens(address account) public noReentrancy {
uint256 totalReleasable = 0;
for (uint256 i = 0; i < vestingSchedules[account].length; i++) {
if (block.timestamp >= vestingSchedules[account][i].releaseTime && block.timestamp >= vestingSchedules[account][i].cliff) {
totalReleasable += vestingSchedules[account][i].amount;
vestingSchedules[account][i].amount = 0; // Prevent re-releasing
}
}
if (totalReleasable > 0) {
unlockAmounts[account] += totalReleasable;
}
}
function redeem(uint256 amount) public noReentrancy {
require(block.timestamp >= BURN_START, "Burn period has not started");
require(_balances[msg.sender] >= amount, "Insufficient balance");
_balances[msg.sender] -= amount;
_totalSupply -= amount;
burnedAmounts[msg.sender] += amount;
emit Transfer(msg.sender, address(0), amount);
}
function _transfer(address sender, address recipient, uint256 amount) internal {
require(sender != address(0), "Transfer from the zero address");
require(recipient != address(0), "Transfer to the zero address");
require(_balances[sender] >= amount, "Transfer amount exceeds balance");
_balances[sender] -= amount;
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
}
function _mint(address account, uint256 amount) internal {
require(account != address(0), "Mint to the zero address");
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
}
function _approve(address owner, address spender, uint256 amount) internal {
require(owner != address(0), "Approve from the zero address");
require(spender != address(0), "Approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
receive() external payable {
revert("Cannot receive ETH");
}
fallback() external payable {
revert("Call to non-existent function");
}
}
{
"compilationTarget": {
"contracts/basedlabs.sol": "BasedLabs"
},
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"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":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"BURN_START","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"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":"amount","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":"","type":"address"}],"name":"burnedAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"cliff","type":"uint256"},{"internalType":"uint256","name":"releaseTime","type":"uint256"}],"name":"mintWithVesting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ownerTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"releaseVestedTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"restrictedAccounts","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"restriction","type":"bool"}],"name":"setAccountRestriction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"setUnlockAmount","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":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"unlockAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLockPeriod","type":"uint256"}],"name":"updateLockPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"vestingSchedules","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"cliff","type":"uint256"},{"internalType":"uint256","name":"releaseTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]