文件 1 的 4:BTBSlock.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract BitBaseTimeLock is Ownable {
IERC20 public BTBS;
uint256 public startDate;
address[] private addresessArray;
struct User {
uint256 bought;
uint256 withdrawn;
}
mapping(address => User) public userData;
event Claimed(address indexed account, uint256 amount);
event AddressUpdated(address indexed accountOld, address indexed accountNew);
event AddressesSet(bool set);
constructor () {
BTBS = IERC20(0x32E6C34Cd57087aBBD59B5A4AECC4cB495924356);
startDate = block.timestamp;
}
function unlocked() public view virtual returns (uint256) {
uint256 startLinearRelease = startDate + 300 days;
uint256 releasePercentage;
if (block.timestamp <= startDate + 90 days) {
releasePercentage = 0;
} else if (block.timestamp < startDate + 180 days) {
releasePercentage = 500;
} else if (block.timestamp >= startDate + 180 days && block.timestamp < startLinearRelease) {
releasePercentage = 1000;
} else if (block.timestamp >= startLinearRelease) {
uint256 timeSinceLinearRelease = block.timestamp - startLinearRelease;
uint256 linearRelease = timeSinceLinearRelease * 1000 / 1234286;
releasePercentage = 1500 + linearRelease;
}
if (releasePercentage >= 10000) {
releasePercentage = 10000;
}
return releasePercentage;
}
function _claim(address account) internal virtual {
uint256 withdrawable = availableToWithdraw(account);
userData[account].withdrawn += withdrawable;
BTBS.transfer(account, withdrawable);
emit Claimed(account, withdrawable);
}
function claim() public virtual {
_claim(msg.sender);
}
function availableToWithdraw(address account) public view virtual returns (uint256) {
return unlockedTotal(account) - claimedAmount(account);
}
function unlockedTotal(address account) public view virtual returns (uint256) {
return userData[account].bought * unlocked() / 10000;
}
function boughtAmount(address account) public view virtual returns (uint256) {
return userData[account].bought;
}
function claimedAmount(address account) public view virtual returns (uint256) {
return userData[account].withdrawn;
}
function leftToClaim(address account) public view virtual returns (uint256) {
return userData[account].bought - userData[account].withdrawn;
}
function updateAddress(address accountOld, address accountNew) public virtual onlyOwner {
userData[accountNew].withdrawn = userData[accountOld].withdrawn;
userData[accountNew].bought = userData[accountOld].bought;
userData[accountOld].withdrawn = 0;
userData[accountOld].bought = 0;
emit AddressUpdated(accountOld, accountNew);
}
function recoverERC20(address tokenAddress, uint256 amount) public virtual onlyOwner {
IERC20 token = IERC20(tokenAddress);
if (amount == 0) {
uint256 balance = token.balanceOf(address(this));
token.transfer(owner(), balance);
} else if (amount != 0) {
token.transfer(owner(), amount);
}
}
function setBoughtAmounts(address[] memory accounts, uint256[] memory amounts) public virtual onlyOwner {
addresessArray = accounts;
for (uint256 i = 0; i < accounts.length; i++) {
userData[accounts[i]].bought = amounts[i];
}
emit AddressesSet(true);
}
function sendToAll() public virtual onlyOwner {
for (uint256 i = 0; i < addresessArray.length; i++) {
_claim(addresessArray[i]);
}
}
}
文件 2 的 4:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
this;
return msg.data;
}
}
文件 3 的 4:IERC20.sol
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);
}
文件 4 的 4:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
{
"compilationTarget": {
"contracts/BTBSlock.sol": "BitBaseTimeLock"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"accountOld","type":"address"},{"indexed":true,"internalType":"address","name":"accountNew","type":"address"}],"name":"AddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"set","type":"bool"}],"name":"AddressesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"BTBS","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"availableToWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"boughtAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"claimedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"leftToClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sendToAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"setBoughtAmounts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unlocked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"unlockedTotal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"accountOld","type":"address"},{"internalType":"address","name":"accountNew","type":"address"}],"name":"updateAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userData","outputs":[{"internalType":"uint256","name":"bought","type":"uint256"},{"internalType":"uint256","name":"withdrawn","type":"uint256"}],"stateMutability":"view","type":"function"}]