Description:
ERC20 token contract with Factory capabilities. Standard implementation for fungible tokens on Ethereum.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"@openzeppelin/contracts/access/AccessControl.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
"
},
"@openzeppelin/contracts/access/IAccessControl.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC-165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted to signal this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
* Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}
"
},
"@openzeppelin/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
"
},
"@openzeppelin/contracts/utils/Context.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
"
},
"@openzeppelin/contracts/utils/introspection/ERC165.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
"
},
"@openzeppelin/contracts/utils/introspection/IERC165.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
"
},
"contracts/CoindepoPoolsVesting/CoindepoPoolsVesting.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.27;
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ICoindepoPoolsVesting} from "./ICoindepoPoolsVesting.sol";
/**
* @title CoindepoPoolsVesting
* @author PixelPlex.inc
* @notice Vesting contract for multiple tokenomics pools with flexible parameters and individual beneficiaries.
* @dev Pools can only be created before vesting is started (TGE). Unlocking can only be performed after start.
* All actions are restricted to ADMIN_ROLE.
*/
contract CoindepoPoolsVesting is ICoindepoPoolsVesting, AccessControl {
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
uint256 public constant MONTH = 30 days;
IERC20 public immutable coinDepoToken;
bool private _started;
uint256 private _startedAt;
uint256 private _totalLockAmount;
mapping(bytes32 name => Pool) private _pools;
/**
* @inheritdoc ICoindepoPoolsVesting
*/
function started() external view returns (bool status) {
return _started;
}
/**
* @inheritdoc ICoindepoPoolsVesting
*/
function startedAt() external view returns (uint256 timestamp) {
return _startedAt;
}
/**
* @inheritdoc ICoindepoPoolsVesting
*/
function totalLockAmount() external view returns (uint256 amount) {
return _totalLockAmount;
}
/**
* @inheritdoc ICoindepoPoolsVesting
*/
function getPool(bytes32 name) external view returns (Pool memory pool) {
return _pools[name];
}
/**
* @inheritdoc ICoindepoPoolsVesting
*/
function getAvailableUnlockAmount(bytes32 name) public view returns (uint256 amount) {
Pool storage pool = _pools[name];
require(pool.amount != 0, InvalidPoolName());
amount = _availableToUnlock(pool);
}
/**
* @inheritdoc ICoindepoPoolsVesting
*/
function getAvailableUnlockAmounts(bytes32[] calldata names) external view returns (uint256[] memory amounts) {
uint256 length = names.length;
amounts = new uint256[](length);
for (uint256 i = 0; i < length; i++) {
amounts[i] = getAvailableUnlockAmount(names[i]);
}
}
/**
* @notice Initializes the contract with the specified parameters.
* @dev Grants admin roles and sets immutable CoinDepo token address.
*
* Requirements:
* - `admin_` must not be the zero address.
* - `coinDepoToken_` must not be the zero address.
*
* @param admin_ Address to be granted admin and default admin roles.
* @param coinDepoToken_ ERC20 token address for vesting.
*/
constructor(address admin_, address coinDepoToken_) onlyValidAddress(admin_) onlyValidAddress(coinDepoToken_) {
_grantRole(DEFAULT_ADMIN_ROLE, admin_);
_grantRole(ADMIN_ROLE, admin_);
coinDepoToken = IERC20(coinDepoToken_);
}
/**
* @inheritdoc ICoindepoPoolsVesting
*/
function start(uint256 startTimestamp) external onlyRole(ADMIN_ROLE) onlyNotStarted returns (uint256 startedAt_) {
uint256 totalLockAmount_ = _totalLockAmount;
require(totalLockAmount_ != 0, NoPools());
require(startTimestamp >= block.timestamp, InvalidStartTimestamp());
_started = true;
_startedAt = startedAt_ = startTimestamp;
coinDepoToken.transferFrom(msg.sender, address(this), totalLockAmount_);
emit VestingStarted(totalLockAmount_, startedAt_);
}
/**
* @inheritdoc ICoindepoPoolsVesting
*/
function createPool(PoolParams calldata params) external onlyRole(ADMIN_ROLE) onlyNotStarted returns (bool) {
_createPool(params);
return true;
}
/**
* @inheritdoc ICoindepoPoolsVesting
*/
function batchCreatePool(PoolParams[] calldata params) external onlyRole(ADMIN_ROLE) onlyNotStarted returns (bool) {
uint256 length = params.length;
for (uint256 i = 0; i < length; i++) {
_createPool(params[i]);
}
return true;
}
/**
* @inheritdoc ICoindepoPoolsVesting
*/
function unlockTokens(bytes32 poolName) external onlyRole(ADMIN_ROLE) onlyStarted returns (uint256 unlockAmount) {
unlockAmount = _unlockTokens(poolName);
}
/**
* @inheritdoc ICoindepoPoolsVesting
*/
function batchUnlockTokens(
bytes32[] calldata poolNames
) external onlyRole(ADMIN_ROLE) onlyStarted returns (uint256 totalUnlockAmount) {
uint256 length = poolNames.length;
for (uint256 i = 0; i < length; i++) {
totalUnlockAmount += _unlockTokens(poolNames[i]);
}
}
/**
* @notice Creates a new vesting pool in storage.
* @dev Calculates and stores initial unlock and monthly unlock values. Emits {PoolCreated}.
* @param params Pool parameters.
*/
function _createPool(PoolParams calldata params) private {
require(params.poolName != bytes32(0), InvalidPoolName());
require(params.beneficiary != address(0), InvalidAddress());
require(params.amount != 0, InvalidPoolAmount());
require(params.initialUnlockX18 != 0 && params.initialUnlockX18 <= 1e18, InvalidPoolInitialUnlockX18());
require(params.vesting != 0, InvalidVesting());
Pool storage pool = _pools[params.poolName];
require(pool.amount == 0, PoolAlreadyExists());
pool.beneficiary = params.beneficiary;
pool.amount = params.amount;
pool.initialUnlockAmount = (params.amount * params.initialUnlockX18) / 1e18;
pool.initialUnlockDelay = params.initialUnlockDelay;
pool.vesting = params.vesting * MONTH;
pool.monthlyUnlock = ((params.amount - pool.initialUnlockAmount) * MONTH) / pool.vesting;
_totalLockAmount += params.amount;
emit PoolCreated(params.poolName, pool);
}
/**
* @notice Unlocks and transfers tokens for a specific pool.
* @dev Transfers unlocked tokens to the beneficiary and updates withdrawn amount. Emits {Unlocked}.
* @param poolName Name of the pool.
* @return unlockAmount Amount of tokens transferred.
*/
function _unlockTokens(bytes32 poolName) private returns (uint256 unlockAmount) {
Pool storage pool = _pools[poolName];
require(pool.amount != 0, InvalidPoolName());
unlockAmount = _availableToUnlock(pool);
if (unlockAmount != 0) {
pool.withdrawn = pool.withdrawn + unlockAmount;
coinDepoToken.transfer(pool.beneficiary, unlockAmount);
emit Unlocked(poolName, unlockAmount);
}
}
/**
* @notice Calculates the amount of tokens available for unlocking for a pool.
* @param pool Reference to pool struct.
* @return unlockAmount Amount currently available for unlock.
*/
function _availableToUnlock(Pool storage pool) private view returns (uint256 unlockAmount) {
uint256 timestamp = block.timestamp;
uint256 startTimestamp = _startedAt + pool.initialUnlockDelay;
uint256 endTimestamp = startTimestamp + pool.vesting;
if (timestamp < startTimestamp) return 0;
else if (timestamp >= endTimestamp) return pool.amount - pool.withdrawn;
else {
uint256 closeMonths = (timestamp - startTimestamp) / MONTH;
uint256 vestingClaimAmount = closeMonths * pool.monthlyUnlock;
uint256 withdrawAmount = pool.initialUnlockAmount + vestingClaimAmount;
unlockAmount = withdrawAmount <= pool.withdrawn ? 0 : withdrawAmount - pool.withdrawn;
}
}
/**
* @notice Modifier that checks that the passed address is not zero address.
* @dev Checks the `address_` is not zero address.
* @param address_ Address to check.
*/
modifier onlyValidAddress(address address_) {
require(address_ != address(0), InvalidAddress());
_;
}
/**
* @notice Modifier that allows functions to execute only if the lockup has started.
* @dev Checks the `_started` flag to ensure the lockup process is active.
*/
modifier onlyStarted() {
require(_started, NotStarted());
_;
}
/**
* @notice Modifier that allows functions to execute only if the lockup has not started.
* @dev Checks the `_started` flag to ensure the lockup process is inactive.
*/
modifier onlyNotStarted() {
require(!_started, AlreadyStarted());
_;
}
}
"
},
"contracts/CoindepoPoolsVesting/ICoindepoPoolsVesting.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
/**
* @title ICoindepoPoolsVesting
* @author PixelPlex.inc
* @notice Interface for Coindepo tokenomics pools vesting contract.
*/
interface ICoindepoPoolsVesting {
struct PoolParams {
bytes32 poolName; ///< Unique name of the pool.
address beneficiary; ///< Address receiving unlocked tokens.
uint256 amount; ///< Total amount allocated to the pool.
uint256 initialUnlockX18; ///< Initial unlock percentage (scaled by 1e18).
uint256 initialUnlockDelay; ///< Delay (in seconds) before initial unlock.
uint256 vesting; ///< Total vesting duration (in months).
}
struct Pool {
address beneficiary; ///< Address receiving unlocked tokens.
uint256 amount; ///< Total amount allocated to the pool.
uint256 initialUnlockAmount; ///< Absolute value of initial unlock.
uint256 initialUnlockDelay; ///< Delay (in seconds) before initial unlock.
uint256 vesting; ///< Total vesting duration (in seconds).
uint256 monthlyUnlock; ///< Amount unlocked every month (after initial unlock).
uint256 withdrawn; ///< Total amount already withdrawn.
}
/**
* @notice Emitted when vesting is started.
* @param totalLockAmount Total amount of tokens locked for vesting.
* @param startedAt Timestamp when vesting started.
*/
event VestingStarted(uint256 totalLockAmount, uint256 startedAt);
/**
* @notice Emitted when a new pool is created.
* @param poolName Unique name of the pool.
* @param pool Pool struct with configuration parameters.
*/
event PoolCreated(bytes32 indexed poolName, Pool pool);
/**
* @notice Emitted when tokens are unlocked for a pool.
* @param poolName Name of the pool.
* @param amount Amount of tokens unlocked.
*/
event Unlocked(bytes32 indexed poolName, uint256 amount);
/**
* @notice Indicates that a zero address was provided where a valid address is required.
*/
error InvalidAddress();
/**
* @notice Indicates that the provided pool name is invalid or zero.
*/
error InvalidPoolName();
/**
* @notice Indicates that the provided pool amount is invalid or zero.
*/
error InvalidPoolAmount();
/**
* @notice Indicates that the provided initial unlock value is invalid or zero.
*/
error InvalidPoolInitialUnlockX18();
/**
* @notice Indicates that the provided vesting count is zero.
*/
error InvalidVesting();
/**
* @notice Indicates that a pool with the specified name already exists.
*/
error PoolAlreadyExists();
/**
* @notice Indicates that no vesting pools have been created yet.
*/
error NoPools();
/**
* @notice Indicates that the provided start timestamp is invalid (lt now).
*/
error InvalidStartTimestamp();
/**
* @notice Indicates that vesting has not started yet.
*/
error NotStarted();
/**
* @notice Indicates that vesting has already started.
*/
error AlreadyStarted();
/**
* @notice Returns true if vesting has started.
* @return status True if vesting started, false otherwise.
*/
function started() external view returns (bool status);
/**
* @notice Returns the timestamp when vesting started.
* @return timestamp Timestamp of vesting start, or 0 if not started.
*/
function startedAt() external view returns (uint256 timestamp);
/**
* @notice Returns the total amount of tokens locked for all pools.
* @return amount Total locked amount.
*/
function totalLockAmount() external view returns (uint256 amount);
/**
* @notice Returns pool configuration and state by pool name.
* @param name Pool name.
* @return pool Pool struct.
*/
function getPool(bytes32 name) external view returns (Pool memory pool);
/**
* @notice Returns the currently available amount for unlocking for a given pool.
* @param name Pool name.
* @return amount Amount available for unlock.
*/
function getAvailableUnlockAmount(bytes32 name) external view returns (uint256 amount);
/**
* @notice Returns available amounts for unlocking for multiple pools.
* @param names Array of pool names.
* @return amounts Array of amounts available for unlock.
*/
function getAvailableUnlockAmounts(bytes32[] calldata names) external view returns (uint256[] memory amounts);
/**
* @notice Starts the vesting schedule and locks all tokens for all created pools.
* @dev
* - Transfers the total required amount of tokens from the caller to the contract.
* - Sets the vesting start timestamp for all pools.
* - Emits a {VestingStarted} event.
*
* Requirements:
* - Must be called only once, before vesting is started.
* - There must be at least one pool created.
* - The caller must approve the contract to spend at least the total required token amount.
* - All required tokens must be successfully transferred from the caller to the contract.
*
* @param startTimestamp The timestamp when vesting starts.
* @return startedAt_ The timestamp when vesting started.
*/
function start(uint256 startTimestamp) external returns (uint256 startedAt_);
/**
* @notice Creates a new vesting pool with the given parameters.
* @dev
* - Registers a new pool in storage using provided parameters.
* - Calculates initial and monthly unlock values based on input.
* - Increases the global total lock amount by the pool's amount.
* - Emits a {PoolCreated} event.
*
* Requirements:
* - Must be called before vesting is started.
* - Pool name must not be zero.
* - Beneficiary address must not be zero.
* - Amount must not be zero.
* - Initial unlock value (initialUnlockX18) must not be zero.
* - A pool with the same name must not already exist.
*
* @param params The pool parameters (name, beneficiary, amount, initial unlock %, delay, vesting duration).
* @return success True if the pool was successfully created.
*/
function createPool(PoolParams calldata params) external returns (bool success);
/**
* @notice Creates multiple vesting pools in a single transaction.
* @dev
* - Registers each pool using the provided parameters.
* - Each pool is created according to the same requirements as {createPool}.
* - Increases the total lock amount by the sum of amounts for all pools.
* - Emits a {PoolCreated} event for each created pool.
*
* Requirements:
* - Must be called before vesting is started.
* - Each pool in the input array must satisfy all requirements of {createPool}.
*
* @param params Array of pool parameters (name, beneficiary, amount, initial unlock %, delay, vesting).
* @return success True if all pools were successfully created.
*/
function batchCreatePool(PoolParams[] calldata params) external returns (bool success);
/**
* @notice Unlocks and transfers available tokens for a specific pool to its beneficiary.
* @dev
* - Calculates the currently available amount to unlock for the given pool.
* - Transfers unlocked tokens to the beneficiary address of the pool.
* - Updates the withdrawn amount in the pool.
* - Emits an {Unlocked} event on successful unlock.
*
* Requirements:
* - Vesting must have started.
* - Pool with the given name must exist.
* - Pool must have available tokens to unlock.
*
* @param poolName The name of the pool for which to unlock tokens.
* @return unlockAmount The amount of tokens unlocked and transferred.
*/
function unlockTokens(bytes32 poolName) external returns (uint256 unlockAmount);
/**
* @notice Unlocks and transfers available tokens for multiple pools in a batch operation.
* @dev
* - For each pool in the input array, calculates the available amount to unlock and transfers tokens to its
* beneficiary.
* - Updates the withdrawn amount for each pool.
* - Emits an {Unlocked} event for each successful unlock.
*
* Requirements:
* - Vesting must have started.
* - Each pool in the input array must exist.
* - Each pool must have available tokens to unlock.
*
* @param poolNames Array of pool names for which to unlock tokens.
* @return totalUnlockAmount The sum of all tokens unlocked and transferred in this batch.
*/
function batchUnlockTokens(bytes32[] calldata poolNames) external returns (uint256 totalUnlockAmount);
}
"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}}
Submitted on: 2025-09-22 17:04:45
Comments
Log in to comment.
No comments yet.