Skip to main content

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

NameTypeDescription
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

NameTypeDescription
_recipientaddress- Address of the recipient
_startTimestampuint32- Start timestamp of the vesting
_endTimestampuint32- End timestamp of the vesting
_timelockuint32- Timelock for the vesting
_initialUnlockuint256- Initial unlock amount
_cliffReleaseTimestampuint32- Cliff release timestamp
_cliffAmountuint256- Cliff amount
_releaseIntervalSecsuint32- Release interval in seconds
_linearVestAmountuint256- Linear vest amount
_isRevocablebool- 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:

  1. Current owner calls initiateVestingTransfer
  2. New owner calls acceptVestingTransfer to complete
  3. 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.