编译器
0.8.17+commit.8df45f5f
文件 1 的 11: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;
}
}
文件 2 的 11:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 3 的 11: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 的 11:IERC721.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function setApprovalForAll(address operator, bool approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
文件 5 的 11:IERC721Enumerable.sol
pragma solidity ^0.8.0;
import "../IERC721.sol";
interface IERC721Enumerable is IERC721 {
function totalSupply() external view returns (uint256);
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
function tokenByIndex(uint256 index) external view returns (uint256);
}
文件 6 的 11:IPresaleCvgSeed.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
interface IPresaleCvgSeed is IERC721Enumerable {
enum SaleState {
NOT_ACTIVE,
PRESEED,
SEED,
OVER
}
struct PresaleInfo {
uint256 vestingType;
uint256 cvgAmount;
}
function setSaleState(SaleState _saleState) external;
function grantPreseed(address _wallet, uint256 _amount) external;
function grantSeed(address _wallet, uint256 _amount) external;
function investMint(bool _isDai) external;
function presaleInfoTokenId(uint256 _tokenId) external view returns (PresaleInfo memory);
function saleState() external view returns (SaleState);
function tokenOfOwnerByIndex(address owner, uint256 index) external view override returns (uint256);
function getTokenIdAndType(
address _wallet,
uint256 _index
) external view returns (uint256 tokenId, uint256 typeVesting);
function getTokenIdsForWallet(address _wallet) external view returns (uint256[] memory);
function getTotalCvg() external view returns (uint256);
function withdrawFunds() external;
function withdrawToken(address _token) external;
}
文件 7 的 11:IPresaleCvgWl.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
interface IPresaleCvgWl is IERC721Enumerable {
enum SaleState {
NOT_ACTIVE,
WL,
OVER
}
struct PresaleInfo {
uint256 vestingType;
uint256 cvgAmount;
}
function setSaleState(SaleState _saleState) external;
function setMerkleRootWlS(bytes32 _newMerkleRootWlS) external;
function setMerkleRootWlM(bytes32 _newMerkleRootWlM) external;
function setMerkleRootWlL(bytes32 _newMerkleRootWlL) external;
function investMint(bytes32[] calldata _merkleProof, uint256 _amount) external;
function presaleInfos(uint256 _tokenId) external view returns (PresaleInfo memory);
function getAmountCvgForVesting() external view returns (uint256);
function getTotalCvg() external view returns (uint256);
function saleState() external view returns (SaleState);
function tokenOfOwnerByIndex(address owner, uint256 index) external view override returns (uint256);
function getTokenIdAndType(
address _wallet,
uint256 _index
) external view returns (uint256 tokenId, uint256 typeVesting);
function getTokenIdsForWallet(address _wallet) external view returns (uint256[] memory);
function MAX_SUPPLY_PRESALE() external view returns (uint256);
function withdrawFunds() external;
function withdrawToken(address _token) external;
}
文件 8 的 11:IboInterface.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
interface IboInterface is IERC721Enumerable {
function totalCvgPerToken(uint256 tokenId) external view returns (uint256);
function iboStartTimestamp() external view returns (uint256);
function getTokenIdsForWallet(address _wallet) external view returns (uint256[] memory);
function getTotalCvgDue() external view returns (uint256);
}
文件 9 的 11: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);
}
}
文件 10 的 11:Ownable2Step.sol
pragma solidity ^0.8.0;
import "./Ownable.sol";
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
function acceptOwnership() public virtual {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
}
文件 11 的 11:VestingCvg.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable2Step.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IPresaleCvgWl.sol";
import "../interfaces/IPresaleCvgSeed.sol";
import "../interfaces/IboInterface.sol";
contract VestingCvg is Ownable2Step {
enum VestingType {
SEED,
WL,
IBO,
TEAM,
DAO
}
enum State {
NOT_ACTIVE,
SET,
OPEN
}
struct VestingSchedule {
uint80 daysBeforeCliff;
uint80 daysAfterCliff;
uint96 dropCliff;
uint256 totalAmount;
uint256 totalReleased;
}
struct InfoVestingTokenId {
uint256 amountReleasable;
uint256 totalCvg;
uint256 amountRedeemed;
}
uint256 public constant MAX_SUPPLY_TEAM = 12_750_000 * 10 ** 18;
uint256 public constant MAX_SUPPLY_DAO = 14_250_000 * 10 ** 18;
uint256 public constant ONE_DAY = 1 days;
uint256 public constant ONE_GWEI = 10 ** 9;
State public state;
IPresaleCvgWl public presaleWl;
IPresaleCvgSeed public presaleSeed;
IboInterface public ibo;
IERC20 public cvg;
address public whitelistedTeam;
address public whitelistedDao;
uint256 public startTimestamp;
mapping(VestingType => VestingSchedule) public vestingSchedules;
mapping(uint256 => uint256) public amountReleasedIdSeed;
mapping(uint256 => uint256) public amountReleasedIdWl;
mapping(uint256 => uint256) public amountReleasedIdIbo;
constructor(IPresaleCvgWl _presaleWl, IPresaleCvgSeed _presaleSeed, IboInterface _ibo) {
presaleWl = _presaleWl;
presaleSeed = _presaleSeed;
ibo = _ibo;
}
modifier onlyOwnerOfSeed(uint256 _tokenId) {
require(presaleSeed.ownerOf(_tokenId) == msg.sender, "NOT_OWNED");
_;
}
modifier onlyOwnerOfWl(uint256 _tokenId) {
require(presaleWl.ownerOf(_tokenId) == msg.sender, "NOT_OWNED");
_;
}
modifier onlyOwnerOfIbo(uint256 _tokenId) {
require(ibo.ownerOf(_tokenId) == msg.sender, "NOT_OWNED");
_;
}
function setWhitelistTeam(address newWhitelistedTeam) external onlyOwner {
whitelistedTeam = newWhitelistedTeam;
}
function setWhitelistDao(address newWhitelistedDao) external onlyOwner {
whitelistedDao = newWhitelistedDao;
}
function getTotalReleasedScheduleId(VestingType _vestingType) external view returns (uint256) {
return (vestingSchedules[_vestingType].totalReleased);
}
function getInfoVestingTokenId(
uint256 _tokenId,
VestingType _vestingType
) external view returns (InfoVestingTokenId memory) {
(uint256 amountReleasable, uint256 totalCvg, uint256 amountRedeemed) = _computeReleaseAmount(
_tokenId,
_vestingType
);
return
InfoVestingTokenId({
amountReleasable: amountReleasable,
totalCvg: totalCvg,
amountRedeemed: amountRedeemed
});
}
function setVesting(IERC20 _cvg) external onlyOwner {
require(state == State.NOT_ACTIVE, "VESTING_ALREADY_SET");
state = State.SET;
require(
presaleSeed.saleState() == IPresaleCvgSeed.SaleState.OVER &&
presaleWl.saleState() == IPresaleCvgWl.SaleState.OVER,
"PRESALE_ROUND_NOT_FINISHED"
);
startTimestamp = block.timestamp;
uint256 seedAmount = presaleSeed.getTotalCvg();
vestingSchedules[VestingType.SEED] = VestingSchedule({
totalAmount: seedAmount,
totalReleased: 0,
daysBeforeCliff: 4 * 30,
daysAfterCliff: 15 * 30,
dropCliff: 50
});
uint256 wlAmount = presaleWl.MAX_SUPPLY_PRESALE();
vestingSchedules[VestingType.WL] = VestingSchedule({
totalAmount: wlAmount,
totalReleased: 0,
daysBeforeCliff: 0,
daysAfterCliff: 3 * 30,
dropCliff: 330
});
uint256 iboAmount = ibo.getTotalCvgDue();
vestingSchedules[VestingType.IBO] = VestingSchedule({
totalAmount: iboAmount,
totalReleased: 0,
daysBeforeCliff: 0,
daysAfterCliff: 2 * 30,
dropCliff: 0
});
uint256 teamAmount = MAX_SUPPLY_TEAM;
vestingSchedules[VestingType.TEAM] = VestingSchedule({
totalAmount: teamAmount,
totalReleased: 0,
daysBeforeCliff: 180,
daysAfterCliff: 18 * 30,
dropCliff: 50
});
uint256 daoAmount = MAX_SUPPLY_DAO;
vestingSchedules[VestingType.DAO] = VestingSchedule({
totalAmount: daoAmount,
totalReleased: 0,
daysBeforeCliff: 0,
daysAfterCliff: 18 * 30,
dropCliff: 50
});
require(address(_cvg) != address(0), "CVG_ZERO");
cvg = _cvg;
require(
_cvg.balanceOf(address(this)) >= seedAmount + wlAmount + iboAmount + teamAmount + daoAmount,
"NOT_ENOUGH_CVG"
);
}
function openVesting() external onlyOwner {
require(state == State.SET, "VESTING_ALREADY_OPENED");
state = State.OPEN;
}
function releaseSeed(uint256 _tokenId) external onlyOwnerOfSeed(_tokenId) {
require(state == State.OPEN, "VESTING_NOT_OPEN");
(uint256 amountToRelease, , ) = _computeReleaseAmount(_tokenId, VestingType.SEED);
require(amountToRelease != 0, "NOT_RELEASABLE");
vestingSchedules[VestingType.SEED].totalReleased += amountToRelease;
amountReleasedIdSeed[_tokenId] += amountToRelease;
cvg.transfer(msg.sender, amountToRelease);
}
function releaseWl(uint256 _tokenId) external onlyOwnerOfWl(_tokenId) {
require(state == State.OPEN, "VESTING_NOT_OPEN");
(uint256 amountToRelease, , ) = _computeReleaseAmount(_tokenId, VestingType.WL);
require(amountToRelease != 0, "NOT_RELEASABLE");
vestingSchedules[VestingType.WL].totalReleased += amountToRelease;
amountReleasedIdWl[_tokenId] += amountToRelease;
cvg.transfer(msg.sender, amountToRelease);
}
function releaseIbo(uint256 _tokenId) external onlyOwnerOfIbo(_tokenId) {
require(state == State.OPEN, "VESTING_NOT_OPEN");
(uint256 amountToRelease, , ) = _computeReleaseAmount(_tokenId, VestingType.IBO);
require(amountToRelease != 0, "NOT_RELEASABLE");
vestingSchedules[VestingType.IBO].totalReleased += amountToRelease;
amountReleasedIdIbo[_tokenId] += amountToRelease;
cvg.transfer(msg.sender, amountToRelease);
}
function releaseTeamOrDao(bool _isTeam) external {
uint256 amountToRelease;
VestingType _vestingType;
if (_isTeam) {
require(msg.sender == whitelistedTeam, "NOT_TEAM");
_vestingType = VestingType.TEAM;
} else {
require(msg.sender == whitelistedDao, "NOT_DAO");
_vestingType = VestingType.DAO;
}
(amountToRelease, , ) = _computeReleaseAmount(0, _vestingType);
require(amountToRelease != 0, "NOT_RELEASABLE");
vestingSchedules[_vestingType].totalReleased += amountToRelease;
cvg.transfer(msg.sender, amountToRelease);
}
function _computeReleaseAmount(
uint256 _tokenId,
VestingType _vestingType
) internal view returns (uint256 amountToRelease, uint256 totalAmount, uint256 totalAmountReleased) {
if (_vestingType == VestingType.SEED) {
totalAmountReleased = amountReleasedIdSeed[_tokenId];
totalAmount = presaleSeed.presaleInfoTokenId(_tokenId).cvgAmount;
} else if (_vestingType == VestingType.WL) {
totalAmountReleased = amountReleasedIdWl[_tokenId];
totalAmount = presaleWl.presaleInfos(_tokenId).cvgAmount;
} else if (_vestingType == VestingType.IBO) {
totalAmountReleased = amountReleasedIdIbo[_tokenId];
totalAmount = ibo.totalCvgPerToken(_tokenId);
} else if (_vestingType == VestingType.TEAM) {
totalAmountReleased = vestingSchedules[_vestingType].totalReleased;
totalAmount = MAX_SUPPLY_TEAM;
} else {
totalAmountReleased = vestingSchedules[_vestingType].totalReleased;
totalAmount = MAX_SUPPLY_DAO;
}
amountToRelease = _calculateRelease(_vestingType, totalAmount, totalAmountReleased);
}
function _calculateRelease(
VestingType vestingType,
uint256 totalAmount,
uint256 totalAmountReleased
) private view returns (uint256 amountToRelease) {
uint256 cliffTimestamp = startTimestamp + vestingSchedules[vestingType].daysBeforeCliff * ONE_DAY;
uint256 endVestingTimestamp = cliffTimestamp + vestingSchedules[vestingType].daysAfterCliff * ONE_DAY;
if (block.timestamp > cliffTimestamp) {
if (block.timestamp > endVestingTimestamp) {
amountToRelease = totalAmount - totalAmountReleased;
} else {
uint256 ratio = ((endVestingTimestamp - block.timestamp) * ONE_GWEI) /
(endVestingTimestamp - cliffTimestamp);
uint256 amountDroppedAtCliff = (totalAmount * vestingSchedules[vestingType].dropCliff) / 1000;
uint256 totalAmountAfterCliff = totalAmount - amountDroppedAtCliff;
amountToRelease =
amountDroppedAtCliff +
(((ONE_GWEI - ratio) * totalAmountAfterCliff) / ONE_GWEI) -
totalAmountReleased;
}
}
}
}
{
"compilationTarget": {
"contracts/PresaleVesting/VestingCvg.sol": "VestingCvg"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 250
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IPresaleCvgWl","name":"_presaleWl","type":"address"},{"internalType":"contract IPresaleCvgSeed","name":"_presaleSeed","type":"address"},{"internalType":"contract IboInterface","name":"_ibo","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":"OwnershipTransferStarted","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":"MAX_SUPPLY_DAO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SUPPLY_TEAM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE_DAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE_GWEI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"amountReleasedIdIbo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"amountReleasedIdSeed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"amountReleasedIdWl","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cvg","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"enum VestingCvg.VestingType","name":"_vestingType","type":"uint8"}],"name":"getInfoVestingTokenId","outputs":[{"components":[{"internalType":"uint256","name":"amountReleasable","type":"uint256"},{"internalType":"uint256","name":"totalCvg","type":"uint256"},{"internalType":"uint256","name":"amountRedeemed","type":"uint256"}],"internalType":"struct VestingCvg.InfoVestingTokenId","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum VestingCvg.VestingType","name":"_vestingType","type":"uint8"}],"name":"getTotalReleasedScheduleId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ibo","outputs":[{"internalType":"contract IboInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"openVesting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"presaleSeed","outputs":[{"internalType":"contract IPresaleCvgSeed","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"presaleWl","outputs":[{"internalType":"contract IPresaleCvgWl","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"releaseIbo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"releaseSeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isTeam","type":"bool"}],"name":"releaseTeamOrDao","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"releaseWl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_cvg","type":"address"}],"name":"setVesting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newWhitelistedDao","type":"address"}],"name":"setWhitelistDao","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newWhitelistedTeam","type":"address"}],"name":"setWhitelistTeam","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"state","outputs":[{"internalType":"enum VestingCvg.State","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum VestingCvg.VestingType","name":"","type":"uint8"}],"name":"vestingSchedules","outputs":[{"internalType":"uint80","name":"daysBeforeCliff","type":"uint80"},{"internalType":"uint80","name":"daysAfterCliff","type":"uint80"},{"internalType":"uint96","name":"dropCliff","type":"uint96"},{"internalType":"uint256","name":"totalAmount","type":"uint256"},{"internalType":"uint256","name":"totalReleased","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whitelistedDao","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whitelistedTeam","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]