Skip to main content

NativeTokenVestingManager

The NativeTokenVestingManager contract manages ETH and native token vesting schedules. Unlike the ERC20-focused TokenVestingManager, this contract handles native blockchain tokens directly, providing efficient gas-based fee structures and simplified funding mechanisms.

Overview

contract NativeTokenVestingManager is AccessProtected, INativeTokenVestingManager

Key Features:

  • Native token vesting for ETH and other native blockchain tokens
  • Gas-based fees only - no token-based fee collection
  • Direct ETH funding through payable functions
  • Simplified architecture without token transfer complexities
  • Efficient batch operations for mass native token distributions
  • Revocable vestings with immediate ETH recovery

Use Cases:

  • ETH-based employee compensation
  • Native token rewards distribution
  • Blockchain validator rewards vesting
  • Platform revenue sharing
  • Mining reward distributions

Key Differences from TokenVestingManager:

  • Works with native tokens (ETH) instead of ERC20 tokens
  • Only supports gas-based fees
  • Uses msg.value for funding instead of token transfers
  • No token approval requirements
  • Lower gas costs for native token operations

Constructor

constructor(
uint256 fee_,
address feeCollector_,
ITypes.FundingType fundingType_
)

Parameters:

  • fee_: Fixed fee amount in wei for claiming operations
  • feeCollector_: Address authorized to collect accumulated fees
  • fundingType_: Funding model (Full or Partial)

Requirements:

  • Fee collector address must be non-zero
  • All parameters are immutable after deployment

Notable Differences:

  • No token address parameter (works with native tokens)
  • Fee type is always ITypes.FeeType.Gas (hardcoded)
  • Simpler constructor with fewer parameters

State Variables

FEE_TYPE

Fee type for this contract (only Gas fee is supported)

ITypes.FeeType public constant FEE_TYPE = ITypes.FeeType.Gas;

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 native tokens reserved for vesting

uint256 public numTokensReservedForVesting;

numTokensReservedForFees

Total number of accumulated fees

uint256 public numTokensReservedForFees;

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

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

mapping(bytes32 => TokenVestingLib.Vesting) public vestingById;

pendingVestingTransfers

Mapping: vestingId => newOwner

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 payable onlyAdmin

Creates a new ETH vesting schedule for a recipient.

Parameters:

  • _recipient: Beneficiary address
  • _startTimestamp: Vesting start time (unix timestamp)
  • _endTimestamp: Vesting end time (unix timestamp)
  • _timelock: Earliest claim timestamp (0 for no timelock)
  • _initialUnlock: ETH immediately available at start
  • _cliffReleaseTimestamp: When cliff amount becomes available
  • _cliffAmount: ETH released at cliff
  • _releaseIntervalSecs: Frequency of linear releases
  • _linearVestAmount: Total ETH vested linearly after cliff
  • _isRevocable: Whether admin can revoke this vesting

Access: Admin only

Funding Behavior:

  • Full funding: msg.value must equal total vesting amount
  • Partial funding: msg.value must be zero; funding done separately

Example:

// Create 2-year ETH vesting with 6-month cliff
// Total: 10 ETH (1 initial + 2 cliff + 7 linear)
nativeVestingManager.createVesting{value: 10 ether}(
0x123...789, // employee address
block.timestamp, // start now
block.timestamp + 2 * 365 * 24 * 3600, // 2 years
0, // no timelock
1 ether, // 1 ETH initial unlock
block.timestamp + 6 * 30 * 24 * 3600, // 6 months cliff
2 ether, // 2 ETH at cliff
30 * 24 * 3600, // monthly releases
7 ether, // 7 ETH linear over 18 months
true // revocable
);

createVestingBatch

function createVestingBatch(
CreateVestingBatchParams calldata params
) external payable onlyAdmin

Creates multiple ETH vesting schedules in a single transaction.

Parameters:

  • params: Struct containing arrays of vesting parameters

Funding Behavior:

  • Full funding: msg.value must equal sum of all vesting amounts
  • Partial funding: msg.value must be zero

Gas Efficiency:

  • Significantly more efficient than individual vesting creation
  • Optimal for team compensation distribution
  • Recommended for 5+ vestings simultaneously

Example:

// Create vestings for 3 employees with different amounts
CreateVestingBatchParams memory params = CreateVestingBatchParams({
_recipients: [employee1, employee2, employee3],
_startTimestamps: [startTime, startTime, startTime],
_endTimestamps: [endTime, endTime, endTime],
// ... other parameters
});

// Total funding: 30 ETH (10 + 8 + 12)
nativeVestingManager.createVestingBatch{value: 30 ether}(params);

fundVesting

function fundVesting(bytes32 _vestingId, uint256 _fundingAmount) external payable

Adds ETH funding to an existing vesting schedule (partial funding only).

Parameters:

  • _vestingId: Unique identifier of the vesting to fund
  • _fundingAmount: Amount of ETH to add (must match msg.value)

Requirements:

  • Contract must use FundingType.Partial
  • msg.value must equal _fundingAmount
  • Cannot exceed total vesting amount

Use Cases:

  • Gradual funding based on milestone completion
  • Multiple contributors funding single vesting
  • Conditional funding based on performance metrics

fundVestingBatch

function fundVestingBatch(
bytes32[] memory _vestingIds,
uint256[] memory _fundingAmounts
) external payable

Funds multiple vesting schedules in a single transaction.

Requirements:

  • msg.value must equal sum of all funding amounts
  • Arrays must have equal length

Claiming Functions

claim

function claim(bytes32 _vestingId) external payable

Allows vesting recipients to claim their vested ETH.

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
  • msg.value must equal the claiming fee

Behavior:

  • Claims all currently vested and unclaimed ETH
  • Transfers ETH directly to recipient
  • Deducts claiming fee from msg.value
  • Accumulates fees for fee collector

Example:

// Claim vested ETH (assuming 0.001 ETH claiming fee)
vestingRecipient.claim{value: 0.001 ether}(vestingId);

adminClaim

function adminClaim(bytes32 _vestingId) external payable onlyAdmin

Allows admin to claim vested ETH on behalf of a recipient.

Use Cases:

  • Assisting recipients with transaction difficulties
  • Bulk claiming for operational efficiency
  • Emergency claiming during system maintenance

batchAdminClaim

function batchAdminClaim(bytes32[] memory _vestingIds) external payable onlyAdmin

Claims vested ETH for multiple recipients in a single transaction.

Requirements:

  • msg.value must cover fees for all claims
  • Each vesting must have claimable amount

Administrative Functions

revokeVesting

function revokeVesting(bytes32 _vestingId) external onlyAdmin

Revokes an active vesting schedule and recovers unvested ETH.

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 ETH
  • Returns unvested ETH to contract for admin withdrawal

batchRevokeVestings

function batchRevokeVestings(bytes32[] memory _vestingIds) external onlyAdmin

Revokes multiple vesting schedules in a single transaction.

withdrawAdmin

function withdrawAdmin(uint256 _amountRequested) external onlyAdmin

Withdraws ETH not committed to active vestings.

Parameters:

  • _amountRequested: Amount of ETH to withdraw in wei

Requirements:

  • Requested amount must not exceed available ETH
  • Available = Contract Balance - Reserved for Vesting - Reserved for Fees

Calculation:

uint256 available = address(this).balance - numTokensReservedForVesting - numTokensReservedForFees;

Query Functions

getVestingInfo

function getVestingInfo(bytes32 _vestingId)
external view returns (TokenVestingLib.Vesting memory)

Returns complete vesting information (same structure as TokenVestingManager).

getVestedAmount

function getVestedAmount(bytes32 _vestingId, uint32 _referenceTimestamp)
external view returns (uint256)

Calculates total vested ETH amount at a specific timestamp.

getClaimableAmount

function getClaimableAmount(bytes32 _vestingId)
external view returns (uint256)

Returns currently claimable ETH (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 ETH funding to pay all amounts.

Ownership Transfer Functions

Transfer functions work identically to TokenVestingManager:

initiateVestingTransfer

function initiateVestingTransfer(bytes32 _vestingId, address _newOwner) external

Initiates transfer of vesting ownership to a new address.

acceptVestingTransfer

function acceptVestingTransfer(bytes32 _vestingId) external

Accepts a pending vesting transfer.

cancelVestingTransfer

function cancelVestingTransfer(bytes32 _vestingId) external

Cancels a pending vesting transfer.

directVestingTransfer

function directVestingTransfer(bytes32 _vestingId, address _newOwner) external

Directly transfers vesting ownership without requiring acceptance.

Fee Management Functions

withdrawGasFee

function withdrawGasFee(address recipient, uint256 amount) external onlyFeeCollector

Withdraws accumulated claiming fees.

Parameters:

  • recipient: Address to receive the fees
  • amount: Amount of ETH to withdraw in wei

Requirements:

  • Caller must be fee collector
  • Amount must not exceed accumulated fees

transferFeeCollectorRole

function transferFeeCollectorRole(address newFeeCollector) external onlyAdmin

Updates the fee collector address.

Access: Admin only

Events

Events are identical to TokenVestingManager except for the absence of token-specific events:

VestingCreated

event VestingCreated(
bytes32 indexed vestingId,
address indexed recipient,
TokenVestingLib.Vesting vesting
);

VestingFunded

event VestingFunded(
bytes32 indexed vestingId,
address indexed funder,
uint256 amount,
uint256 totalFunded,
uint256 totalRequired
);

Claimed

event Claimed(
bytes32 indexed vestingId,
address indexed recipient,
uint256 withdrawalAmount
);

VestingRevoked

event VestingRevoked(
bytes32 indexed vestingId,
uint256 numTokensWithheld,
TokenVestingLib.Vesting vesting
);

GasFeeWithdrawn

event GasFeeWithdrawn(address indexed recipient, uint256 amount);

All Functions

isVestingActive

Reverts if the vesting is not active

modifier isVestingActive(bytes32 _vestingId);

onlyVestingRecipient

Reverts if caller is not the recipient of the vesting

modifier onlyVestingRecipient(bytes32 _vestingId);

onlyFeeCollector

modifier onlyFeeCollector();

constructor

Initialize the native token vesting manager

constructor(uint256 fee_, address feeCollector_, ITypes.FundingType fundingType_);

Parameters

NameTypeDescription
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)

createVesting

Create a new vesting

function createVesting(
address _recipient,
uint32 _startTimestamp,
uint32 _endTimestamp,
uint32 _timelock,
uint256 _initialUnlock,
uint32 _cliffReleaseTimestamp,
uint256 _cliffAmount,
uint32 _releaseIntervalSecs,
uint256 _linearVestAmount,
bool _isRevocable
) external payable 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

createVestingBatch

Create a batch of vestings

function createVestingBatch(CreateVestingBatchParams calldata params) external payable onlyAdmin;

Parameters

NameTypeDescription
paramsCreateVestingBatchParams- Parameters for creating the vesting batch

fundVesting

Fund an existing vesting schedule

function fundVesting(bytes32 _vestingId) external payable isVestingActive(_vestingId) onlyAdmin;

Parameters

NameTypeDescription
_vestingIdbytes32- Identifier of the vesting to fund

fundVestingBatch

Fund multiple vestings in batch

function fundVestingBatch(bytes32[] calldata _vestingIds, uint256[] calldata _fundingAmounts)
external
payable
onlyAdmin;

Parameters

NameTypeDescription
_vestingIdsbytes32[]- Array of vesting identifiers to fund
_fundingAmountsuint256[]- Array of funding amounts for each vesting

claim

Claim vested native tokens

function claim(bytes32 _vestingId) external payable onlyVestingRecipient(_vestingId);

Parameters

NameTypeDescription
_vestingIdbytes32- Identifier of the vesting

adminClaim

Admin claims vested tokens on behalf of a recipient (gas sponsoring)

function adminClaim(bytes32 _vestingId) external payable onlyAdmin;

Parameters

NameTypeDescription
_vestingIdbytes32- Identifier of the vesting

batchAdminClaim

Admin claims vested tokens for multiple recipients (batch gas sponsoring)

function batchAdminClaim(bytes32[] calldata _vestingIds) external payable onlyAdmin;

Parameters

NameTypeDescription
_vestingIdsbytes32[]- Array of vesting identifiers to claim

revokeVesting

Revoke active Vesting

function revokeVesting(bytes32 _vestingId) external onlyAdmin;

Parameters

NameTypeDescription
_vestingIdbytes32- Vesting Identifier

batchRevokeVestings

Revoke multiple vestings in batch

More gas efficient than calling revokeVesting multiple times

function batchRevokeVestings(bytes32[] calldata _vestingIds) external onlyAdmin;

Parameters

NameTypeDescription
_vestingIdsbytes32[]- Array of vesting identifiers to revoke

withdrawAdmin

Allow the owner to withdraw any balance not currently tied up in Vestings

function withdrawAdmin(uint256 _amountRequested) external onlyAdmin;

Parameters

NameTypeDescription
_amountRequesteduint256- Amount to withdraw

withdrawOtherToken

Withdraw a token which isn't controlled by the vesting contract. Useful when someone accidentally sends tokens to the contract

function withdrawOtherToken(address _otherTokenAddress) external onlyAdmin;

Parameters

NameTypeDescription
_otherTokenAddressaddress- the token which we want to withdraw

initiateVestingTransfer

Initiate the transfer of vesting ownership to a new address

function initiateVestingTransfer(bytes32 _vestingId, address _newOwner)
external
onlyVestingRecipient(_vestingId)
isVestingActive(_vestingId);

Parameters

NameTypeDescription
_vestingIdbytes32The ID of the vesting to transfer
_newOwneraddressThe address of the new owner

cancelVestingTransfer

Cancel a pending vesting transfer

function cancelVestingTransfer(bytes32 _vestingId) external onlyVestingRecipient(_vestingId);

Parameters

NameTypeDescription
_vestingIdbytes32The ID of the vesting with a pending transfer

acceptVestingTransfer

Accept a vesting transfer as the new owner

function acceptVestingTransfer(bytes32 _vestingId) external isVestingActive(_vestingId);

Parameters

NameTypeDescription
_vestingIdbytes32The ID of the vesting to accept

directVestingTransfer

Direct transfer of vesting ownership by admin (for contract compatibility)

This is specifically for compatibility with contracts that cannot call acceptVestingTransfer

function directVestingTransfer(bytes32 _vestingId, address _newOwner)
external
onlyVestingRecipient(_vestingId)
isVestingActive(_vestingId);

Parameters

NameTypeDescription
_vestingIdbytes32The ID of the vesting to transfer
_newOwneraddressThe address of the new owner

withdrawGasFee

Allows only fee collector to withdraw collected gas fees

This function is completely separate from distributor admin controls

function withdrawGasFee(address recipient, uint256 amount) external onlyFeeCollector;

Parameters

NameTypeDescription
recipientaddressAddress to receive the fee
amountuint256Amount to withdraw, if 0 withdraws all available fees

transferFeeCollectorRole

Updates the fee collector address

Can only be called by the fee collector

function transferFeeCollectorRole(address newFeeCollector) external onlyFeeCollector;

Parameters

NameTypeDescription
newFeeCollectoraddressAddress of the new fee collector

getVestingFundingInfo

Get funding information for a vesting

function getVestingFundingInfo(bytes32 _vestingId)
external
view
returns (uint8 fundingType, uint256 totalFunded, uint256 totalRequired);

Parameters

NameTypeDescription
_vestingIdbytes32- Identifier of the vesting

Returns

NameTypeDescription
fundingTypeuint8- Type of funding (Full or Partial)
totalFundeduint256- Total amount of tokens funded so far
totalRequireduint256- Total amount of tokens required for full funding

isVestingFullyFunded

Check if a vesting is fully funded

function isVestingFullyFunded(bytes32 _vestingId) external view returns (bool);

Parameters

NameTypeDescription
_vestingIdbytes32- Identifier of the vesting

Returns

NameTypeDescription
<none>boolisFullyFunded - True if the vesting is fully funded

getVestingInfo

Get the vesting information

function getVestingInfo(bytes32 _vestingId) external view returns (TokenVestingLib.Vesting memory);

Parameters

NameTypeDescription
_vestingIdbytes32- Identifier of the vesting

Returns

NameTypeDescription
<none>TokenVestingLib.Vestingvesting - Vesting information

getVestedAmount

Get the vested amount for a Vesting, at a given timestamp.

function getVestedAmount(bytes32 _vestingId, uint32 _referenceTimestamp) external view returns (uint256);

Parameters

NameTypeDescription
_vestingIdbytes32The vesting ID
_referenceTimestampuint32Timestamp for which we're calculating

getClaimableAmount

Get the claimable amount for a vesting

function getClaimableAmount(bytes32 _vestingId) external view returns (uint256 claimable);

Parameters

NameTypeDescription
_vestingIdbytes32- Identifier of the vesting

Returns

NameTypeDescription
claimableuint256- The amount of tokens that can be claimed at the current time

getAllRecipients

Get all recipients

function getAllRecipients() external view returns (address[] memory);

Returns

NameTypeDescription
<none>address[]recipients - The list of recipients

getAllRecipientsLength

Get the length of all recipients

function getAllRecipientsLength() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256length - The length of all recipients

getAllRecipientsSliced

Get all recipients in a range

function getAllRecipientsSliced(uint256 _from, uint256 _to) external view returns (address[] memory);

Parameters

NameTypeDescription
_fromuint256- The start index (inclusive)
_touint256- The end index (exclusive)

Returns

NameTypeDescription
<none>address[]recipientsSliced - The list of recipients in the range

getAllRecipientVestings

Get all vestings for a recipient

function getAllRecipientVestings(address _recipient) external view returns (bytes32[] memory);

Parameters

NameTypeDescription
_recipientaddress- The recipient address

Returns

NameTypeDescription
<none>bytes32[]recipientVestings - The list of vestings for the recipient

getAllRecipientVestingsSliced

Get all vestings for a recipient in a range

function getAllRecipientVestingsSliced(uint256 _from, uint256 _to, address _recipient)
external
view
returns (bytes32[] memory);

Parameters

NameTypeDescription
_fromuint256- The start index (inclusive)
_touint256- The end index (exclusive)
_recipientaddress- The recipient address

Returns

NameTypeDescription
<none>bytes32[]recipientVestingsSliced - The list of vestings for the recipient in the range

getAllRecipientVestingsLength

Get the length of all vestings for a recipient

function getAllRecipientVestingsLength(address _recipient) external view returns (uint256);

Parameters

NameTypeDescription
_recipientaddress- The recipient address

Returns

NameTypeDescription
<none>uint256length - The length of all vestings for the recipient

getPendingVestingTransfer

Get the pending owner for a vesting transfer

function getPendingVestingTransfer(bytes32 _vestingId) external view returns (address);

Parameters

NameTypeDescription
_vestingIdbytes32The ID of the vesting

Returns

NameTypeDescription
<none>addressThe address of the pending owner if there is one, or zero address

amountAvailableToWithdrawByAdmin

Amount of tokens available to withdraw by the admin

function amountAvailableToWithdrawByAdmin() public view returns (uint256);

Returns

NameTypeDescription
<none>uint256The amount of tokens available to withdraw

isRecipient

Check if a recipient has vestings

function isRecipient(address recipient) external view returns (bool);

Parameters

NameTypeDescription
recipientaddress- The recipient address

Returns

NameTypeDescription
<none>boolisRecipient - True if the recipient has vestings

_createVesting

Internal function to create a new vesting

function _createVesting(TokenVestingLib.VestingParams memory params) internal;

Parameters

NameTypeDescription
paramsTokenVestingLib.VestingParams- Vesting parameters

_claim

Internal function to claim vested tokens

function _claim(bytes32 _vestingId) internal;

Parameters

NameTypeDescription
_vestingIdbytes32- Identifier of the vesting

_revokeVesting

Internal function to revoke a vesting

function _revokeVesting(bytes32 _vestingId) internal isVestingActive(_vestingId);

Parameters

NameTypeDescription
_vestingIdbytes32- Vesting Identifier

_removeVestingFromRecipient

Helper function to remove a vesting ID from a recipient's array

function _removeVestingFromRecipient(address _recipient, bytes32 _vestingId) internal;

Parameters

NameTypeDescription
_recipientaddressThe address of the recipient
_vestingIdbytes32The ID of the vesting to remove

_removeRecipient

Helper function to remove a recipient from the recipients array

function _removeRecipient(address _recipient) internal;

Parameters

NameTypeDescription
_recipientaddressThe address of the recipient to remove

_isRecipient

Internal function to check if an address is a recipient

function _isRecipient(address recipient) internal view returns (bool);

Parameters

NameTypeDescription
recipientaddressThe address to check

Returns

NameTypeDescription
<none>boolTrue if the address is a recipient, false otherwise

_checkArrayLengthMismatch

Internal function to check if all array lengths in batch params match the expected length

function _checkArrayLengthMismatch(CreateVestingBatchParams calldata params, uint256 expectedLength) internal pure;

Parameters

NameTypeDescription
paramsCreateVestingBatchParams- Batch parameters to validate
expectedLengthuint256- The expected length all arrays should match