编译器
0.8.17+commit.8df45f5f
文件 1 的 4:AdvisorUnlocking.sol
pragma solidity 0.8.17;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract TokenUnlocking is Ownable {
address public immutable lbr;
mapping(address => UnlockingRule) public UnlockingInfo;
mapping(address => bool) _paused;
event Withdraw(address indexed _addr, uint256 _amount, uint256 _timestamp);
event SetUnlockRule(
address indexed _addr,
uint256 _totalLocked,
uint256 _duration,
uint256 _unlockStartTime,
uint256 _lastWithdrawTime
);
constructor(address _lbr) {
lbr = _lbr;
}
struct UnlockingRule {
uint256 totalLocked;
uint256 duration;
uint256 unlockStartTime;
uint256 lastWithdrawTime;
address[] whitelist;
}
modifier whenNotPaused(address _user) {
require(!_paused[_user], "Vest is paused.");
_;
}
function setPause(address _user, bool val) external onlyOwner {
_paused[_user] = val;
}
function setUnlockRule(
address _addr,
uint256 _totalLocked,
uint256 _duration,
uint256 _unlockStartTime,
uint256 _lastWithdrawTime,
address[] calldata _whitelist
) external onlyOwner {
require(_unlockStartTime != 0, "Invalid time");
require(
UnlockingInfo[_addr].lastWithdrawTime == 0,
"This rule has already been set."
);
UnlockingInfo[_addr].totalLocked = _totalLocked;
UnlockingInfo[_addr].unlockStartTime = _unlockStartTime;
UnlockingInfo[_addr].lastWithdrawTime = _lastWithdrawTime;
UnlockingInfo[_addr].duration = _duration;
UnlockingInfo[_addr].whitelist = _whitelist;
emit SetUnlockRule(
_addr,
_totalLocked,
_duration,
_unlockStartTime,
_lastWithdrawTime
);
}
function addWhitelistAddresses(
address addr,
address[] calldata addrs
) external {
require(_checkWhitelist(addr), "The account is not in the whitelist.");
UnlockingInfo[addr].whitelist = addrs;
}
function _checkWhitelist(address _addr) internal view returns(bool) {
address[] storage whitelist = UnlockingInfo[_addr].whitelist;
bool isWhitelist = false;
for(uint256 i=0; i< whitelist.length;i++){
if(whitelist[i] == msg.sender){
isWhitelist = true;
break;
}
}
return isWhitelist;
}
function getUserUnlockInfo(
address _addr
) external view returns (UnlockingRule memory) {
return UnlockingInfo[_addr];
}
function getRewards(address addr) public view returns (uint256) {
if (
block.timestamp <= UnlockingInfo[addr].unlockStartTime ||
UnlockingInfo[addr].unlockStartTime == 0
) return 0;
uint256 unlockEndTime = UnlockingInfo[addr].unlockStartTime + UnlockingInfo[addr].duration;
uint256 rate = UnlockingInfo[addr].totalLocked / UnlockingInfo[addr].duration;
uint256 reward = block.timestamp > unlockEndTime ? (unlockEndTime - UnlockingInfo[addr].lastWithdrawTime) * rate : (block.timestamp - UnlockingInfo[addr].lastWithdrawTime) * rate;
return reward;
}
function withdraw(address addr) external whenNotPaused(addr) {
require(_checkWhitelist(addr), "The account is not in the whitelist.");
require(block.timestamp >= UnlockingInfo[addr].unlockStartTime, "The time has not yet arrived.");
uint256 unlockEndTime = UnlockingInfo[addr].unlockStartTime + UnlockingInfo[addr].duration;
uint256 canClaimAmount = getRewards(addr);
if (canClaimAmount > 0) {
if (block.timestamp > unlockEndTime) {
UnlockingInfo[addr].lastWithdrawTime = unlockEndTime;
} else {
UnlockingInfo[addr].lastWithdrawTime = block.timestamp;
}
IERC20(lbr).transfer(msg.sender, canClaimAmount);
emit Withdraw(addr, canClaimAmount, block.timestamp);
}
}
function withdrawTokenEmergency(address token, uint256 amount) external onlyOwner {
IERC20(token).transfer(msg.sender, amount);
}
}
文件 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) {
return msg.data;
}
}
文件 3 的 4:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, 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 from, address to, uint256 amount) external returns (bool);
}
文件 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() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
{
"compilationTarget": {
"contracts/lybra/helpers/AdvisorUnlocking.sol": "TokenUnlocking"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_lbr","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_addr","type":"address"},{"indexed":false,"internalType":"uint256","name":"_totalLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_duration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_unlockStartTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_lastWithdrawTime","type":"uint256"}],"name":"SetUnlockRule","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_addr","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"UnlockingInfo","outputs":[{"internalType":"uint256","name":"totalLocked","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"unlockStartTime","type":"uint256"},{"internalType":"uint256","name":"lastWithdrawTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"address[]","name":"addrs","type":"address[]"}],"name":"addWhitelistAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"getRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"getUserUnlockInfo","outputs":[{"components":[{"internalType":"uint256","name":"totalLocked","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"unlockStartTime","type":"uint256"},{"internalType":"uint256","name":"lastWithdrawTime","type":"uint256"},{"internalType":"address[]","name":"whitelist","type":"address[]"}],"internalType":"struct TokenUnlocking.UnlockingRule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lbr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"bool","name":"val","type":"bool"}],"name":"setPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint256","name":"_totalLocked","type":"uint256"},{"internalType":"uint256","name":"_duration","type":"uint256"},{"internalType":"uint256","name":"_unlockStartTime","type":"uint256"},{"internalType":"uint256","name":"_lastWithdrawTime","type":"uint256"},{"internalType":"address[]","name":"_whitelist","type":"address[]"}],"name":"setUnlockRule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawTokenEmergency","outputs":[],"stateMutability":"nonpayable","type":"function"}]