True Vesting is a pet project for creating decentralized vesting of an ERC-20 token. The decentralization lies in the fact that, after the token is created, its entire supply is transferred to a dedicated contract responsible for distribution. The token cannot be withdrawn by the owner or any other party. The token can only be sent to specific contracts that handle its distribution according to predefined rules.
Currently, only one type of distribution has been implemented—vesting. Other types can be successfully added later.
The project does not implement full-fledged tokenomics and serves only as an example for two allocation groups: team and liquidity. Any coincidences are purely accidental.
Important! The project is not designed to support vesting for rebase tokens or tokens with dynamically changing quantities.
The following smart contracts have been implemented:
- MetaToken.sol. The ERC-20 token contract, which we will distribute through the contract
MetaTokenDistributor.sol. - MetaTokenDistributor.sol. A contract that will initiate various types of vesting. It can be upgraded to handle token locking, adding liquidity, sending tokens to mentors, and so on.
- VestingParams.sol. A contract that stores parameters for all types of vesting (in our case, two types: team and liquidity). It includes the description of allocations, a list of beneficiary addresses, and the token unlock schedule.
- Vesting.sol. Implementation of the vesting contract. A new instance is created for each type of vesting. It organizes the token unlock process according to the established schedule.
The smart contract architecture outlines the process of creating new vesting instances.To create a new vesting, the following deployment and smart contract call process must be executed:
- Deploy the
VestingParams.solsmart contract, which defines all vesting rules for all vesting types. - Deploy the
MetaTokenDistributor.solsmart contract. The distribution contract accepts and stores the address ofVestingParams.sol. - Under the hood, a
MetaToken.solcontract for distribution will be deployed. - At the time of
MetaToken.soldeployment, its entire supply will be sent to theMetaTokenDistributor.solcontract. - To initiate vesting, the
startVesting()function must be called on theMetaTokenDistributor.solcontract. - The
MetaTokenDistributor.solcontract will request vesting parameters from theVestingParams.solcontract. - Deploy a
Vesting.solcontract using the minimal clone pattern.
Important! Each type of vesting can only be initiated once and by anyone after the vesting start time has been reached.
The list of beneficiaries is determined at the moment of deploying the smart contract VestingParams.sol in the constructor. Therefore, it is important to understand the maximum number of beneficiaries that can be set in this way without exceeding the block gas limit.
As of 2025, the block gas limit in the Ethereum network is 36 million. In the Arbitrum network, it is significantly higher, but according to the documentation, the practical working limit is 32 million.
To determine the actual gas consumption, you can refer to the load test MaxBeneficiaries.t.sol. Run the test with gas profiling using forge test -vvv --mt test_deploy_moreBeneficiaries --gas-report.
The resulting table shows that for 401 beneficiaries, 19_448_973 gas will be consumed, which is optimal and will occupy approximately half of the block gas limit in Ethereum.
Important! For deployment on other networks, it is necessary to check the documentation and review the block and transaction gas limits.
The project is written using a Foundry framework.
Build
$ forge buildTest
$ forge testTest coverage
$ forge coverageFormat
$ forge fmtDeploy VestingParams.sol, MetaToken.sol, MetaTokenDistributor.sol. Project realize deploy to BNB Smart Chain testnet and mainnet.
- Create
.envand edit args according to .env.example. - Open DeployAll script and edit params to deploy
- Run script
forge script script/DeployAll.s.sol:DeployAllScript --rpc-url bnb-testnet --broadcast --slow --verify -vvvv --interactives 1- Enter deployer private key. You need to hold native currency for pay gas.
Important! Change --rpc-url on bnb-mainnet for deploy to mainnet.
You need MetaTokenDistributor address for start vestings. Use DeployAll for first deploy.
- Run script
forge script script/StartVestings.s.sol:StartVestingsScript --rpc-url bnb-testnet --broadcast --sig "run(address)" "<MetaTokenDistributor address>" --slow -vvvv --interactives 1- Enter deployer private key. You need to hold native currency for pay gas.
Important! Change --rpc-url on bnb-mainnet for deploy to mainnet.

