TokenVestingManager
The TokenVestingManager
contract is the core ERC20 token vesting implementation in the TokenOps suite. It manages linear vesting schedules with cliff periods, initial unlocks, and configurable release intervals for any ERC20 token.
Overview
contract TokenVestingManager is AccessProtected, ITokenVestingManager
Key Features:
- Linear vesting schedules with customizable cliff periods and release intervals
- Flexible funding models supporting both full pre-funding and partial funding
- Configurable fee structures with gas-based or token-based fee collection
- Revocable vestings for employment and partnership scenarios
- Ownership transfers enabling vesting assignment and secondary markets
- Batch operations for efficient mass vesting creation and management
Use Cases:
- Employee equity compensation
- Advisor token allocations
- Partnership vesting agreements
- Community token distributions
- Investor token releases
Constructor
constructor(
address tokenAddress_,
ITypes.FeeType feeType_,
uint256 fee_,
address feeCollector_,
ITypes.FundingType fundingType_
);
Parameters
Name | Type | Description |
---|---|---|
tokenAddress_ | address | - Address of the token to be vested |
feeType_ | ITypes.FeeType | - Fee type for this contract |
fee_ | uint256 | - Fee amount for this contract |
feeCollector_ | address | - Address of the fee collector |
fundingType_ | ITypes.FundingType | - Type of funding for this contract (Full or Partial) |
Requirements:
- Token address and fee collector must be non-zero
- Token fee percentage cannot exceed 100% (10000 basis points)
- All parameters are immutable after deployment
State Variables
BASIS_POINTS
Basis points for fee calculation
uint256 public constant BASIS_POINTS = 10000;
TOKEN_ADDRESS
Address of the token to be vested
address public immutable TOKEN_ADDRESS;
FEE_TYPE
Fee type for this contract
ITypes.FeeType public immutable FEE_TYPE;
FUNDING_TYPE
Funding type for this contract
ITypes.FundingType public immutable FUNDING_TYPE;
DEPLOYMENT_BLOCK_NUMBER
Block number when this contract was deployed
uint256 public immutable DEPLOYMENT_BLOCK_NUMBER;
FEE
Fee amount for this contract
uint256 public immutable FEE;
numTokensReservedForVesting
Total number of tokens reserved for vesting
uint256 public numTokensReservedForVesting;
numTokensReservedForFee
Number of tokens reserved for fees
uint256 public numTokensReservedForFee;
vestingIdNonce
Nonce to generate vesting IDs
uint256 private vestingIdNonce;
feeCollector
Address of the fee collector
address public feeCollector;
recipients
List of all recipients
address[] public recipients;
recipientToIndex
Mapping: recipient address => index+1 in recipients array (0 means not in array)
mapping(address => uint256) private recipientToIndex;
vestingFunding
Mapping: vestingId => funding amount
mapping(bytes32 => uint256) public vestingFunding;
recipientVestings
Mapping: recipient => vestingIds Holds the vesting ids for each recipient
mapping(address => bytes32[]) public recipientVestings;
vestingToRecipientIndex
Mapping: recipient => vestingId => index+1 in recipientVestings array (0 means not in array)
mapping(address => mapping(bytes32 => uint256)) private vestingToRecipientIndex;
vestingById
Mapping: vestingId => vesting Holds the vesting information for each vesting id
mapping(bytes32 => TokenVestingLib.Vesting) public vestingById;
pendingVestingTransfers
Mapping: vestingId => newOwner Tracks pending ownership transfers for each vesting ID
mapping(bytes32 => address) public pendingVestingTransfers;
Vesting Management Functions
createVesting
function createVesting(
address _recipient,
uint32 _startTimestamp,
uint32 _endTimestamp,
uint32 _timelock,
uint256 _initialUnlock,
uint32 _cliffReleaseTimestamp,
uint256 _cliffAmount,
uint32 _releaseIntervalSecs,
uint256 _linearVestAmount,
bool _isRevocable
) external onlyAdmin;
Parameters
Name | Type | Description |
---|---|---|
_recipient | address | - Address of the recipient |
_startTimestamp | uint32 | - Start timestamp of the vesting |
_endTimestamp | uint32 | - End timestamp of the vesting |
_timelock | uint32 | - Timelock for the vesting |
_initialUnlock | uint256 | - Initial unlock amount |
_cliffReleaseTimestamp | uint32 | - Cliff release timestamp |
_cliffAmount | uint256 | - Cliff amount |
_releaseIntervalSecs | uint32 | - Release interval in seconds |
_linearVestAmount | uint256 | - Linear vest amount |
_isRevocable | bool | - Whether the vesting is revocable |
Access: Admin only
Funding Behavior:
- Full funding: Tokens transferred immediately from caller
- Partial funding: Vesting created without funding; requires separate funding
Example:
// Create 4-year employee vesting with 1-year cliff
vestingManager.createVesting(
0x123...789, // employee address
block.timestamp, // start now
block.timestamp + 4 * 365 * 24 * 3600, // 4 years
0, // no timelock
100_000e18, // 10% initial unlock
block.timestamp + 365 * 24 * 3600, // 1 year cliff
250_000e18, // 25% at cliff
30 * 24 * 3600, // monthly releases
650_000e18, // 65% linear over remaining 3 years
true // revocable
);
createVestingBatch
function createVestingBatch(
CreateVestingBatchParams calldata params
) external onlyAdmin
Creates multiple vesting schedules in a single transaction.
Parameters:
params
: Struct containing arrays of vesting parameters
Requirements:
- All parameter arrays must have equal length
- Each vesting follows the same validation rules as
createVesting
Gas Optimization:
- Batch creation is significantly more gas-efficient than individual calls
- Recommended for creating 10+ vestings simultaneously
fundVesting
function fundVesting(bytes32 _vestingId, uint256 _fundingAmount) external
Adds funding to an existing vesting schedule (partial funding only).
Parameters:
_vestingId
: Unique identifier of the vesting to fund_fundingAmount
: Amount of tokens to add as funding
Requirements:
- Contract must use
FundingType.Partial
- Cannot exceed total vesting amount
- Caller must approve token transfer
Use Cases:
- Gradual funding of large vesting schedules
- Multiple funders contributing to single vesting
- Funding adjustment based on performance milestones
fundVestingBatch
function fundVestingBatch(
bytes32[] memory _vestingIds,
uint256[] memory _fundingAmounts
) external
Funds multiple vesting schedules in a single transaction.
Claiming Functions
claim
function claim(bytes32 _vestingId) external payable
Allows vesting recipients to claim their vested tokens.
Parameters:
_vestingId
: Unique identifier of the vesting to claim from
Requirements:
- Caller must be vesting recipient
- Vesting must be active (not revoked)
- Timelock period must have passed
- Gas fee payment (if using gas-based fees)
Behavior:
- Claims all currently vested and unclaimed tokens
- Automatically handles cliff and linear vesting calculations
- Transfers tokens directly to recipient
- Deducts applicable fees
adminClaim
function adminClaim(bytes32 _vestingId) external payable onlyAdmin
Allows admin to claim vested tokens on behalf of a recipient.
Use Cases:
- Assisting recipients who cannot execute transactions
- Bulk claiming for operational efficiency
- Emergency claiming during contract migrations
batchAdminClaim
function batchAdminClaim(bytes32[] memory _vestingIds) external payable onlyAdmin
Claims vested tokens for multiple recipients in a single transaction.
Administrative Functions
revokeVesting
function revokeVesting(bytes32 _vestingId) external onlyAdmin
Revokes an active vesting schedule.
Requirements:
- Vesting must be marked as revocable
- Vesting must be active
- Caller must be admin
Behavior:
- Immediately stops further vesting
- Allows claiming of already vested tokens
- Returns unvested tokens to admin control
batchRevokeVestings
function batchRevokeVestings(bytes32[] memory _vestingIds) external onlyAdmin
Revokes multiple vesting schedules in a single transaction.
withdrawAdmin
function withdrawAdmin(uint256 _amountRequested) external onlyAdmin
Withdraws tokens not committed to active vestings.
Parameters:
_amountRequested
: Amount of tokens to withdraw
Requirements:
- Requested amount must not exceed uncommitted tokens
- Uncommitted = Total Balance - Reserved for Vesting - Reserved for Fees
Query Functions
getVestingInfo
function getVestingInfo(bytes32 _vestingId)
external view returns (TokenVestingLib.Vesting memory)
Returns complete vesting information.
Returns:
struct Vesting {
address recipient;
uint32 startTimestamp;
uint32 endTimestamp;
uint32 deactivationTimestamp;
uint32 timelock;
uint256 initialUnlock;
uint32 cliffReleaseTimestamp;
uint256 cliffAmount;
uint32 releaseIntervalSecs;
uint256 linearVestAmount;
uint256 claimedAmount;
bool isRevocable;
}
getVestedAmount
function getVestedAmount(bytes32 _vestingId, uint32 _referenceTimestamp)
external view returns (uint256)
Calculates total vested amount at a specific timestamp.
Parameters:
_vestingId
: Vesting identifier_referenceTimestamp
: Timestamp to calculate vesting at
Returns: Total tokens vested at the reference timestamp
getClaimableAmount
function getClaimableAmount(bytes32 _vestingId)
external view returns (uint256)
Returns currently claimable tokens (vested minus already claimed).
getVestingFundingInfo
function getVestingFundingInfo(bytes32 _vestingId)
external view returns (uint8 fundingType, uint256 totalFunded, uint256 totalRequired)
Returns funding status for a vesting schedule.
isVestingFullyFunded
function isVestingFullyFunded(bytes32 _vestingId) external view returns (bool)
Checks if a vesting has sufficient funding to pay all tokens.
Ownership Transfer Functions
initiateVestingTransfer
function initiateVestingTransfer(bytes32 _vestingId, address _newOwner) external
Initiates transfer of vesting ownership to a new address.
Access: Current vesting owner only
Process:
- Current owner calls
initiateVestingTransfer
- New owner calls
acceptVestingTransfer
to complete - Or current owner calls
cancelVestingTransfer
to abort
acceptVestingTransfer
function acceptVestingTransfer(bytes32 _vestingId) external
Accepts a pending vesting transfer.
Access: Designated new owner only
cancelVestingTransfer
function cancelVestingTransfer(bytes32 _vestingId) external
Cancels a pending vesting transfer.
Access: Current vesting owner only
directVestingTransfer
function directVestingTransfer(bytes32 _vestingId, address _newOwner) external
Directly transfers vesting ownership without requiring acceptance.
Access: Current vesting owner only
Use Case: Transferring to smart contracts that cannot call acceptVestingTransfer
Fee Management Functions
withdrawTokenFee
function withdrawTokenFee(address recipient, uint256 amount) external onlyFeeCollector
Withdraws accumulated token fees.
withdrawGasFee
function withdrawGasFee(address recipient, uint256 amount) external onlyFeeCollector
Withdraws accumulated gas fees (ETH).
transferFeeCollectorRole
function transferFeeCollectorRole(address newFeeCollector) external onlyAdmin
Updates the fee collector address.
Events
VestingCreated
event VestingCreated(
bytes32 indexed vestingId,
address indexed recipient,
TokenVestingLib.Vesting vesting
);
Emitted when a new vesting is created.
VestingFunded
event VestingFunded(
bytes32 indexed vestingId,
address indexed funder,
uint256 amount,
uint256 totalFunded,
uint256 totalRequired
);
Emitted when a vesting receives funding.
Claimed
event Claimed(
bytes32 indexed vestingId,
address indexed recipient,
uint256 withdrawalAmount
);
Emitted when tokens are claimed from a vesting.
VestingRevoked
event VestingRevoked(
bytes32 indexed vestingId,
uint256 numTokensWithheld,
TokenVestingLib.Vesting vesting
);
Emitted when a vesting is revoked.
VestingTransferInitiated
event VestingTransferInitiated(
address indexed currentOwner,
address indexed newOwner,
bytes32 indexed vestingId
);
Emitted when vesting ownership transfer is initiated.
VestingTransferred
event VestingTransferred(
address indexed previousOwner,
address indexed newOwner,
bytes32 indexed vestingId
);
Emitted when vesting ownership is transferred.