编译器
0.8.19+commit.7dd6d404
文件 1 的 12:AccessControl.sol
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
文件 2 的 12: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 的 12:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 4 的 12:IAccessControl.sol
pragma solidity ^0.8.0;
interface IAccessControl {
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
文件 5 的 12:IBEP20.sol
pragma solidity ^0.8.19;
interface IBEP20 {
function totalSupply() external view returns (uint256);
function decimals() external view returns (uint8);
function symbol() external view returns (string memory);
function name() external view returns (string memory);
function getOwner() external view returns (address);
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);
}
文件 6 的 12:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 7 的 12:Math.sol
pragma solidity ^0.8.0;
library Math {
enum Rounding {
Down,
Up,
Zero
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
require(denominator > prod1, "Math: mulDiv overflow");
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
文件 8 的 12:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
}
function _nonReentrantAfter() private {
_status = _NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
文件 9 的 12:SafeMath.sol
pragma solidity ^0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
文件 10 的 12:SignedMath.sol
pragma solidity ^0.8.0;
library SignedMath {
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
function average(int256 a, int256 b) internal pure returns (int256) {
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
function abs(int256 n) internal pure returns (uint256) {
unchecked {
return uint256(n >= 0 ? n : -n);
}
}
}
文件 11 的 12:Strings.sol
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}
文件 12 的 12:Vesting.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./IBEP20.sol";
contract Vesting is AccessControl, ReentrancyGuard {
using SafeMath for uint256;
bytes32 public constant TREASURY_ROLE = keccak256("TREASURY_ROLE");
uint256 public projectIndex;
uint256 public poolIndex;
mapping(uint256 => Pool) public pools;
mapping(uint256 => Project) public projects;
event CreatePoolEvent(uint256 poolId);
event CreateProjectEvent(uint256 project, string name, address tokenFund);
event AddFundEvent(uint256 poolId, address user, uint256 fundAmount);
event RemoveFundEvent(uint256 poolId, address user);
event ClaimFundEvent(
uint256 poolId,
address user,
uint256 fundClaimed,
address contractAddress
);
event DepositFundEvent(
address contractAddress,
address user,
uint256 fundAmount
);
event WithdrawFundEvent(
address contractAddress,
address user,
uint256 fundAmount
);
uint8 private constant VESTING_TYPE_MILESTONE_UNLOCK_FIRST = 1;
uint8 private constant VESTING_TYPE_MILESTONE_CLIFF_FIRST = 2;
uint8 private constant VESTING_TYPE_LINEAR_UNLOCK_FIRST = 3;
uint8 private constant VESTING_TYPE_LINEAR_CLIFF_FIRST = 4;
uint256 private constant ONE_HUNDRED_PERCENT_SCALED = 10000;
uint256 private constant ONE_HUNDRED_YEARS_IN_S = 3153600000;
enum PoolState {
NEW,
STARTING,
PAUSE,
SUCCESS
}
struct Project {
uint256 id;
IBEP20 tokenFund;
string name;
uint256[] poolIds;
}
struct Pool {
IBEP20 tokenFund;
uint256 id;
Project project;
string name;
uint8 vestingType;
uint256 tge;
uint256 cliff;
uint256 unlockPercent;
uint256 linearVestingDuration;
uint256[] milestoneTimes;
uint256[] milestonePercents;
mapping(address => uint256) funds;
mapping(address => uint256) released;
uint256 fundsTotal;
uint256 fundsClaimed;
PoolState state;
}
constructor(address admin, address treasury) {
_setupRole(DEFAULT_ADMIN_ROLE, admin);
_setupRole(TREASURY_ROLE, treasury);
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
poolIndex = 200;
projectIndex = 1;
}
modifier onlyAdmin() {
require(
hasRole(DEFAULT_ADMIN_ROLE, msg.sender),
"Restricted to admins!"
);
_;
}
modifier onlyTreasury() {
require(hasRole(TREASURY_ROLE, msg.sender), "Restricted to treasury!");
_;
}
function createProject(
address _tokenFund,
string memory _name
) external nonReentrant onlyAdmin {
uint256 index = projectIndex++;
Project storage project = projects[index];
project.id = index;
project.name = _name;
project.tokenFund = IBEP20(_tokenFund);
emit CreateProjectEvent(index, _name, _tokenFund);
}
function createPool(
address _tokenFund,
string memory _name,
uint256 _projectId,
uint8 _vestingType,
uint256 _tge,
uint256 _cliff,
uint256 _unlockPercent,
uint256 _linearVestingDuration,
uint256[] memory _milestoneTimes,
uint256[] memory _milestonePercents
) external nonReentrant onlyAdmin {
_validateSetup(
_vestingType,
_unlockPercent,
_tge,
_cliff,
_linearVestingDuration,
_milestoneTimes,
_milestonePercents
);
require(
_projectId > 0 && _projectId <= projectIndex,
"Invalid project id"
);
Project storage project = projects[_projectId];
require(address(project.tokenFund) == _tokenFund, "Invalid tokenFund");
uint256 index = poolIndex++;
Pool storage pool = pools[index];
pool.id = index;
pool.tokenFund = IBEP20(_tokenFund);
pool.name = _name;
pool.vestingType = _vestingType;
pool.tge = _tge;
pool.cliff = _cliff;
pool.unlockPercent = _unlockPercent;
pool.linearVestingDuration = _linearVestingDuration;
pool.milestoneTimes = _milestoneTimes;
pool.milestonePercents = _milestonePercents;
pool.fundsTotal = 0;
pool.fundsClaimed = 0;
pool.state = PoolState.NEW;
project.poolIds.push(pool.id);
pool.project = project;
emit CreatePoolEvent(index);
}
function start(uint256 _poolId) external nonReentrant onlyAdmin {
Pool storage pool = pools[_poolId];
require(
pool.state == PoolState.NEW || pool.state == PoolState.PAUSE,
"Invalid action"
);
pool.state = PoolState.STARTING;
}
function pause(uint256 _poolId) external nonReentrant onlyAdmin {
Pool storage pool = pools[_poolId];
require(pool.state != PoolState.PAUSE, "Invalid action");
pool.state = PoolState.PAUSE;
}
function end(uint256 _poolId) external nonReentrant onlyAdmin {
Pool storage pool = pools[_poolId];
require(pool.state == PoolState.STARTING, "Invalid action");
pool.state = PoolState.SUCCESS;
}
function addFunds(
uint256 _poolId,
uint256[] memory _fundAmounts,
address[] memory _users
) external nonReentrant onlyAdmin {
require(
_users.length == _fundAmounts.length,
"Input arrays length mismatch"
);
Pool storage pool = pools[_poolId];
for (uint256 i = 0; i < _users.length; i++) {
address user = _users[i];
uint256 fundAmount = _fundAmounts[i];
uint256 oldFund = pool.funds[user];
if (oldFund > 0) {
pool.fundsTotal = pool.fundsTotal.add(fundAmount);
pool.funds[user] = pool.funds[user].add(fundAmount);
} else {
pool.fundsTotal = pool.fundsTotal.add(fundAmount);
pool.funds[user] = pool.funds[user].add(fundAmount);
pool.released[user] = 0;
}
emit AddFundEvent(_poolId, user, fundAmount);
}
}
function removeFunds(
uint256 _poolId,
address[] memory _users
) external nonReentrant onlyAdmin {
Pool storage pool = pools[_poolId];
for (uint256 i = 0; i < _users.length; i++) {
address user = _users[i];
uint256 oldFund = pool.funds[user];
if (oldFund > 0) {
pool.funds[user] = 0;
pool.released[user] = 0;
pool.fundsTotal = pool.fundsTotal.sub(oldFund);
emit RemoveFundEvent(_poolId, user);
}
}
}
function claimFund(uint256 _poolId) external nonReentrant {
_validateClaimFund(_poolId);
_claim(_poolId);
}
function claimAll(uint256 _projectId) external nonReentrant {
require(
_projectId > 0 && _projectId <= projectIndex,
"Invalid project id"
);
for (uint256 i = 0; i < projects[_projectId].poolIds.length; i++) {
uint256 poolId = projects[_projectId].poolIds[i];
if(checkClaimablePool(poolId, _msgSender())){
_claim(poolId);
}
}
}
function _claim(uint256 _poolId) internal {
Pool storage pool = pools[_poolId];
uint256 _now = block.timestamp;
require(_now >= pool.tge, "Invalid Time");
uint256 claimPercent = computeClaimPercent(_poolId, _now);
require(claimPercent > 0, "Not enough unlock token to claim");
uint256 claimTotal = (pool.funds[_msgSender()].mul(claimPercent)).div(
ONE_HUNDRED_PERCENT_SCALED
);
require(claimTotal > pool.released[_msgSender()], "Not enough unlock token to claim");
uint256 claimRemain = claimTotal.sub(pool.released[_msgSender()]);
pool.tokenFund.transfer(_msgSender(), claimRemain);
pool.released[_msgSender()] = pool.released[_msgSender()].add(
claimRemain
);
pool.fundsClaimed = pool.fundsClaimed.add(claimRemain);
emit ClaimFundEvent(_poolId, _msgSender(), claimRemain, address(this));
}
function depositFund(
uint256 _poolId,
uint256 _fundAmount
) external nonReentrant onlyTreasury {
require(_fundAmount > 0, "Amount must be greater than zero");
Pool storage pool = pools[_poolId];
require(
pool.tokenFund.balanceOf(_msgSender()) >= _fundAmount,
"Error: not enough Token"
);
pool.tokenFund.transferFrom(_msgSender(), address(this), _fundAmount);
emit DepositFundEvent(address(this), _msgSender(), _fundAmount);
}
function withdrawFund(
uint256 _poolId,
uint256 _fundAmount
) external nonReentrant onlyTreasury {
require(_fundAmount > 0, "Amount must be greater than zero");
Pool storage pool = pools[_poolId];
require(
pool.tokenFund.balanceOf(address(this)) >= _fundAmount,
"Fund insufficient!"
);
pool.tokenFund.transfer(_msgSender(), _fundAmount);
emit WithdrawFundEvent(address(this), _msgSender(), _fundAmount);
}
function computeClaimPercent(
uint256 _poolId,
uint256 _now
) public view returns (uint256) {
Pool storage pool = pools[_poolId];
uint256[] memory milestoneTimes = pool.milestoneTimes;
uint256[] memory milestonePercents = pool.milestonePercents;
uint256 totalPercent = 0;
uint256 tge = pool.tge;
if (pool.vestingType == VESTING_TYPE_MILESTONE_CLIFF_FIRST) {
if (_now >= tge.add(pool.cliff)) {
totalPercent = totalPercent.add(pool.unlockPercent);
for (uint i = 0; i < milestoneTimes.length; i++) {
uint256 milestoneTime = milestoneTimes[i];
uint256 milestonePercent = milestonePercents[i];
if (_now >= milestoneTime) {
totalPercent = totalPercent.add(milestonePercent);
}
}
}
} else if (pool.vestingType == VESTING_TYPE_MILESTONE_UNLOCK_FIRST) {
if (_now >= tge) {
totalPercent = totalPercent.add(pool.unlockPercent);
if (_now >= tge.add(pool.cliff)) {
for (uint i = 0; i < milestoneTimes.length; i++) {
uint256 milestoneTime = milestoneTimes[i];
uint256 milestonePercent = milestonePercents[i];
if (_now >= milestoneTime) {
totalPercent = totalPercent.add(milestonePercent);
}
}
}
}
} else if (pool.vestingType == VESTING_TYPE_LINEAR_UNLOCK_FIRST) {
if (_now >= tge) {
totalPercent = totalPercent.add(pool.unlockPercent);
if (_now >= tge.add(pool.cliff)) {
uint256 delta = _now.sub(tge).sub(pool.cliff);
totalPercent = totalPercent.add(
delta
.mul(
ONE_HUNDRED_PERCENT_SCALED.sub(
pool.unlockPercent
)
)
.div(pool.linearVestingDuration)
);
}
}
} else if (pool.vestingType == VESTING_TYPE_LINEAR_CLIFF_FIRST) {
if (_now >= tge.add(pool.cliff)) {
totalPercent = totalPercent.add(pool.unlockPercent);
uint256 delta = _now.sub(tge).sub(pool.cliff);
totalPercent = totalPercent.add(
delta
.mul(ONE_HUNDRED_PERCENT_SCALED.sub(pool.unlockPercent))
.div(pool.linearVestingDuration)
);
}
}
return
(totalPercent < ONE_HUNDRED_PERCENT_SCALED)
? totalPercent
: ONE_HUNDRED_PERCENT_SCALED;
}
function getFundByUser(
uint256 _poolId,
address _user
) public view returns (uint256, uint256) {
return (pools[_poolId].funds[_user], pools[_poolId].released[_user]);
}
function getInfoUserReward(
uint256 _poolId
) public view returns (uint256, uint256) {
Pool storage pool = pools[_poolId];
uint256 tokenTotal = pool.fundsTotal;
uint256 claimedTotal = pool.fundsClaimed;
return (tokenTotal, claimedTotal);
}
function checkClaimablePool(uint256 _poolId, address _user) public view returns (bool) {
Pool storage pool = pools[_poolId];
if (pool.state != PoolState.STARTING) return false;
uint256 _now = block.timestamp;
if (_now < pool.tge) return false;
if (pool.funds[_user] <= 0) return false;
if (pool.funds[_user] <= pool.released[_user])
return false;
uint256 claimPercent = computeClaimPercent(_poolId, _now);
if (claimPercent <= 0) return false;
uint256 claimTotal = (pool.funds[_user].mul(claimPercent)).div(
ONE_HUNDRED_PERCENT_SCALED
);
if (claimTotal <= pool.released[_user]) return false;
return true;
}
function checkClaimableProject(uint256 _projectId, address _user) public view returns (bool) {
require(
_projectId > 0 && _projectId <= projectIndex,
"Invalid project id"
);
for (uint256 i = 0; i < projects[_projectId].poolIds.length; i++) {
if(checkClaimablePool(projects[_projectId].poolIds[i], _user)){
return true;
}
}
return false;
}
function getPool(
uint256 _poolId
)
public
view
returns (
address,
string memory,
uint8,
uint256,
uint256,
uint256,
uint256,
uint256[] memory,
uint256[] memory,
uint256,
uint256,
PoolState
)
{
Pool storage pool = pools[_poolId];
return (
address(pool.tokenFund),
pool.name,
pool.vestingType,
pool.tge,
pool.cliff,
pool.unlockPercent,
pool.linearVestingDuration,
pool.milestoneTimes,
pool.milestonePercents,
pool.fundsTotal,
pool.fundsClaimed,
pool.state
);
}
function _validateClaimFund(uint256 _poolId) private view {
Pool storage pool = pools[_poolId];
require(pool.state == PoolState.STARTING, "Invalid action");
require(
pool.funds[_msgSender()] > 0,
"Amount must be greater than zero"
);
require(
pool.funds[_msgSender()] > pool.released[_msgSender()],
"All money has been claimed"
);
}
function _validateSetup(
uint8 _vestingType,
uint256 _unlockPercent,
uint256 _tge,
uint256 _cliff,
uint256 _linearVestingDuration,
uint256[] memory _milestoneTimes,
uint256[] memory _milestonePercents
) private {
require(
_vestingType >= VESTING_TYPE_MILESTONE_UNLOCK_FIRST &&
_vestingType <= VESTING_TYPE_LINEAR_CLIFF_FIRST,
"Invalid action"
);
require(
_unlockPercent >= 0 &&
_unlockPercent <= ONE_HUNDRED_PERCENT_SCALED &&
_cliff >= 0,
"Invalid input parameter"
);
if (
_vestingType == VESTING_TYPE_MILESTONE_CLIFF_FIRST ||
_vestingType == VESTING_TYPE_MILESTONE_UNLOCK_FIRST
) {
require(
_milestoneTimes.length == _milestonePercents.length &&
_milestoneTimes.length >= 0 &&
_linearVestingDuration >= 0,
"Invalid vesting parameter"
);
uint256 total = _unlockPercent;
uint256 curTime = 0;
for (uint i = 0; i < _milestoneTimes.length; i++) {
total = total + _milestonePercents[i];
uint256 tmpTime = _milestoneTimes[i];
require(
tmpTime >= _tge + _cliff && tmpTime > curTime,
"Invalid input parameter"
);
curTime = tmpTime;
}
require(
total == ONE_HUNDRED_PERCENT_SCALED,
"Invalid vesting parameter"
);
} else {
require(
_milestoneTimes.length == 0 &&
_milestonePercents.length == 0 &&
(_linearVestingDuration > 0 &&
_linearVestingDuration <= ONE_HUNDRED_YEARS_IN_S),
"Invalid vesting parameter"
);
}
}
}
{
"compilationTarget": {
"contracts/Vesting.sol": "Vesting"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"treasury","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"fundAmount","type":"uint256"}],"name":"AddFundEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"fundClaimed","type":"uint256"},{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"}],"name":"ClaimFundEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"poolId","type":"uint256"}],"name":"CreatePoolEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"project","type":"uint256"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"tokenFund","type":"address"}],"name":"CreateProjectEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"fundAmount","type":"uint256"}],"name":"DepositFundEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"}],"name":"RemoveFundEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"fundAmount","type":"uint256"}],"name":"WithdrawFundEvent","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TREASURY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"uint256[]","name":"_fundAmounts","type":"uint256[]"},{"internalType":"address[]","name":"_users","type":"address[]"}],"name":"addFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"checkClaimablePool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"checkClaimableProject","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"claimAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"}],"name":"claimFund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"uint256","name":"_now","type":"uint256"}],"name":"computeClaimPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenFund","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"uint8","name":"_vestingType","type":"uint8"},{"internalType":"uint256","name":"_tge","type":"uint256"},{"internalType":"uint256","name":"_cliff","type":"uint256"},{"internalType":"uint256","name":"_unlockPercent","type":"uint256"},{"internalType":"uint256","name":"_linearVestingDuration","type":"uint256"},{"internalType":"uint256[]","name":"_milestoneTimes","type":"uint256[]"},{"internalType":"uint256[]","name":"_milestonePercents","type":"uint256[]"}],"name":"createPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenFund","type":"address"},{"internalType":"string","name":"_name","type":"string"}],"name":"createProject","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"uint256","name":"_fundAmount","type":"uint256"}],"name":"depositFund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"}],"name":"end","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"getFundByUser","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"}],"name":"getInfoUserReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"}],"name":"getPool","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"string","name":"","type":"string"},{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"enum Vesting.PoolState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"}],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"poolIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pools","outputs":[{"internalType":"contract IBEP20","name":"tokenFund","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"contract IBEP20","name":"tokenFund","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256[]","name":"poolIds","type":"uint256[]"}],"internalType":"struct Vesting.Project","name":"project","type":"tuple"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint8","name":"vestingType","type":"uint8"},{"internalType":"uint256","name":"tge","type":"uint256"},{"internalType":"uint256","name":"cliff","type":"uint256"},{"internalType":"uint256","name":"unlockPercent","type":"uint256"},{"internalType":"uint256","name":"linearVestingDuration","type":"uint256"},{"internalType":"uint256","name":"fundsTotal","type":"uint256"},{"internalType":"uint256","name":"fundsClaimed","type":"uint256"},{"internalType":"enum Vesting.PoolState","name":"state","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"projectIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"projects","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"contract IBEP20","name":"tokenFund","type":"address"},{"internalType":"string","name":"name","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"address[]","name":"_users","type":"address[]"}],"name":"removeFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"}],"name":"start","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"uint256","name":"_fundAmount","type":"uint256"}],"name":"withdrawFund","outputs":[],"stateMutability":"nonpayable","type":"function"}]