Overview
MultiTokenVesting is a Solidity smart contract designed for linear vesting of multiple ERC-20 tokens from a single deployment. An Owner (admin) creates vesting schedules for beneficiaries, and beneficiaries claim vested tokens over time.
Key behaviors:
- Vesting is linear (optionally with a cliff)
- Schedules can be revoked by the Owner
- The contract enforces a solvency check by pulling tokens in at schedule creation
Key features
Multi-token support
One contract can manage vesting schedules for many ERC-20 tokens (e.g., USDC, WETH, UNI), without redeploying per token.Revocable schedules
When the Owner revokes a schedule:- The vested amount remains claimable by the beneficiary
- The unvested portion is refunded back to the Owner
Gas optimization
The contract is optimized for production use through:- Packed data structures (addresses + flags)
- Custom errors (cheaper than revert strings)
- Direct claiming by schedule index
Safety features
- Solvency check: tokens required for a schedule are transferred into the contract at creation time
- Withdraw excess: the Owner can withdraw only excess tokens accidentally sent to the contract (not those locked for active schedules)
Supported tokens
- ERC-20 tokens are supported.
Native gas tokens (e.g., using PEAQ as a native currency) are not supported directly by this contract. Wrap native tokens into an ERC-20 representation if needed.
Vesting logic
Vesting follows a simple timeline:- Before cliff: 0 claimable
- After cliff → end: linear unlock
- After end: 100% claimable
VestedAmount = (TotalAmount * (CurrentTime - StartTime)) / Duration
Example:
- Total amount: 1000
- Duration: 1000 seconds
- Cliff: 250 seconds
- At 0s: 0 vested
- At 250s: 250 vested
- At 500s: 500 vested
- At 1000s: 1000 vested
Quickstart (peaq-friendly)
You deployMultiTokenVesting on peaq EVM like any Solidity contract:
- Build and understand the contract: Build Smart Contract
- Deploy it: Deploy Smart Contract
- Interact with it: Interact with Smart Contract
How to use
A) Approve tokens (ERC-20)
Approve the vesting contract to pull tokens from the Owner’s wallet. This call is made on the ERC-20 token contract, not the vesting contract.B) Create vesting schedule (Owner-only)
Create a schedule that starts now, has a 30-day cliff, and vests linearly over 1 year.C) Claim (Beneficiary-only)
Beneficiaries claim byscheduleIndex:
scheduleIndex is emitted by the ScheduleCreated event. In practice, your app should index this event and store schedule indices per beneficiary.
D) Revoke (Owner-only)
The Owner can revoke a schedule:- Beneficiary keeps vested amount up to the revoke time
- Remaining unvested amount returns to the Owner
E) Withdraw excess (Owner-only)
Withdraw tokens that are not locked in active schedules:API reference
VestingSchedule fields
beneficiary(address)start(uint64)revoked(bool)claimed(bool)token(address)duration(uint64)cliff(uint64)totalAmount(uint256)amountClaimed(uint256)
Errors
| Error | Meaning |
|---|---|
InvalidAddress | An address argument is zero or invalid |
InvalidAmount | Amount is zero or invalid |
InvalidDuration | Duration is zero or invalid |
InvalidCliff | Cliff is invalid (e.g., greater than duration) |
Unauthorized | Caller is not allowed to perform this action |
ScheduleClaimed | Schedule was already fully claimed |
NothingToClaim | No tokens are currently claimable |
InvalidIndex | Provided schedule index does not exist |
ScheduleWasRevoked | Schedule was revoked and no longer claimable in the expected way |
InsufficientExcessBalance | Not enough excess balance to withdraw |
Security notes
- Solidity
^0.8.20includes overflow checks by default. - Uses
SafeERC20to safely handle non-standard ERC-20 implementations. - Claim flows should follow Checks-Effects-Interactions.
- Centralization risk: the Owner can revoke schedules (beneficiaries must trust the Owner).
References
- Repository: peaqnetwork/peaq-multitoken-vesting

