Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
LABS
Guides

Setting Up a Token Vesting Schedule with Privacy Features

A technical guide for implementing smart contracts that manage token vesting while concealing grant amounts and schedules on-chain. Covers hashed timelocks and zk-SNARKs.
Chainscore © 2026
introduction
GUIDE

Setting Up a Token Vesting Schedule with Privacy Features

This guide explains how to implement a private token vesting contract, detailing the core concepts, privacy mechanisms, and a practical implementation using Solidity and zero-knowledge proofs.

A token vesting contract is a smart contract that releases tokens to beneficiaries, such as team members or investors, according to a predefined schedule. This prevents the immediate sale of large token allocations, which can destabilize a project's tokenomics. Traditional vesting contracts have a significant privacy flaw: the vesting terms and beneficiary addresses are publicly visible on-chain. This exposes sensitive financial agreements and can make recipients targets for phishing or harassment. Adding privacy features to a vesting contract is therefore a critical consideration for many Web3 projects.

Privacy in vesting contracts is typically achieved through cryptographic techniques that hide the link between a beneficiary and their allocation. One common method is to use a commitment scheme. Instead of storing the beneficiary's address directly, the contract stores a cryptographic hash (the commitment) of the address and the vesting amount. Later, the beneficiary can prove they are the rightful recipient by revealing the original data (the pre-image) that hashes to the stored commitment. This allows the contract to verify eligibility without leaking information prematurely.

For stronger privacy, zero-knowledge proofs (ZKPs) can be integrated. A ZKP system like zk-SNARKs allows a user to prove they are eligible to claim tokens without revealing any details about their identity or the vesting schedule. The contract only needs to verify a proof against a public verification key. This approach, while more complex, offers the highest level of privacy. Projects like Aztec Network and Tornado Cash have pioneered the use of ZKPs for private transactions, providing a blueprint for private vesting.

Here is a simplified Solidity example using a commitment scheme for a linear vesting contract. The contract stores a merkleRoot of all commitments. A beneficiary submits a Merkle proof along with their address and vesting details to claim tokens, proving their data is part of the approved set without revealing other beneficiaries.

solidity
// Simplified PrivateVesting contract using Merkle commitments
bytes32 public merkleRoot;
mapping(address => bool) public hasClaimed;

function claimTokens(
    uint256 amount,
    uint256 startTime,
    uint256 cliff,
    uint256 duration,
    bytes32[] calldata merkleProof
) external {
    require(!hasClaimed[msg.sender], "Already claimed");
    // Create leaf from beneficiary's data
    bytes32 leaf = keccak256(abi.encodePacked(msg.sender, amount, startTime, cliff, duration));
    // Verify the proof
    require(MerkleProof.verify(merkleProof, merkleRoot, leaf), "Invalid proof");
    hasClaimed[msg.sender] = true;
    // Calculate vested amount based on schedule and transfer
    _transferVestedTokens(msg.sender, amount, startTime, cliff, duration);
}

When deploying a private vesting contract, key considerations include the privacy-completeness trade-off, gas costs, and key management. Commitment schemes are gas-efficient but may leak information upon claim. ZKPs are fully private but incur higher verification gas fees and require complex trusted setup ceremonies. Developers must also ensure beneficiaries can securely store the private data or keys needed to generate proofs. Auditing these contracts is essential, as flaws in the cryptographic logic can permanently lock funds. Using well-audited libraries from projects like OpenZeppelin for Merkle proofs is highly recommended.

The primary use cases for private vesting are team allocations, investor rounds, and advisor grants where disclosure terms are confidential. It aligns with the financial privacy norms of traditional finance while operating on a transparent blockchain. As regulatory scrutiny increases, projects must balance transparency requirements with the legitimate need for privacy. Implementing these features correctly protects stakeholders and contributes to a more mature and professional Web3 ecosystem. For further reading, consult the EIP-712 standard for structured data hashing and documentation for ZKP frameworks like Circom and snarkjs.

prerequisites
GETTING STARTED

Prerequisites

Before implementing a private token vesting schedule, you need to establish the foundational technical environment and understand the core concepts involved.

To follow this guide, you will need a basic understanding of Ethereum and smart contract development. Familiarity with Solidity, the Hardhat or Foundry development frameworks, and the concept of ERC-20 tokens is essential. You should also have Node.js (v18 or later) and npm/yarn installed on your system. This tutorial assumes you are building on a testnet like Sepolia or Goerli, so you'll need test ETH from a faucet and a wallet such as MetaMask configured for development.

The core concept of a vesting schedule is the linear or cliff-based release of tokens to beneficiaries over time. A privacy-preserving vesting contract adds a layer of confidentiality to these transactions. Instead of publicly linking beneficiary addresses to vesting amounts on-chain, the contract uses cryptographic commitments (like zk-SNARKs or Merkle trees) to hide this mapping. Only the contract owner and the beneficiary can prove and claim the vested tokens, preventing competitors or speculators from inferring team allocation sizes or investor details.

You will need to choose a privacy primitive. A common approach is to use a Merkle tree where each leaf is a hash of (beneficiaryAddress, vestedAmount). The contract stores only the Merkle root. To claim, a beneficiary provides a Merkle proof. For stronger privacy, you might integrate a zero-knowledge proof system like zk-SNARKs using a library such as circom and snarkjs, where a user proves they own a valid commitment without revealing its contents. Decide on your schedule parameters: total allocation, cliff duration (e.g., 12 months), vesting period (e.g., 48 months), and release interval (e.g., monthly).

Set up your development environment. Initialize a Hardhat project with npx hardhat init or a Foundry project with forge init. Install necessary dependencies: for Merkle trees, @openzeppelin/contracts for the MerkleProof library; for zk-SNARKs, you'll need circom and snarkjs. Configure your hardhat.config.js or foundry.toml to connect to your chosen Ethereum testnet RPC URL. Ensure you have a .env file to securely manage your deployer wallet's private key using dotenv.

Finally, plan your contract architecture. A typical private vesting contract will have functions to: 1) initialize with the Merkle root or zk-SNARK verification key, 2) allow beneficiaries to claim tokens with a proof, and 3) allow the owner to recover unclaimed tokens after vesting ends. You must also write thorough tests that simulate the full vesting lifecycle with multiple beneficiaries to ensure the privacy mechanism and fund release logic work correctly under various conditions before proceeding to deployment.

key-concepts
IMPLEMENTATION GUIDE

Core Privacy Techniques for Vesting

Designing a token vesting schedule requires balancing transparency with privacy. This guide covers key cryptographic and architectural methods to protect sensitive allocation data while maintaining necessary on-chain verification.

06

Auditing Privacy-Preserving Vesting

Privacy adds complexity. Ensure your implementation is secure and functional with these steps:

  • Circuit Audits: For ZK-based systems, have the proof circuit (e.g., written in Circom or Halo2) reviewed by specialists.
  • State Consistency: Verify that hidden commitments or encrypted states cannot lead to double-spends or inconsistent global supply.
  • Gas Analysis: Privacy mechanisms like ZK proof verification have high gas costs; model this for users.
  • Recovery Mechanisms: Implement secure, multi-sig admin functions to recover funds in case of bugs in private logic, without compromising privacy for other users.

Always disclose the privacy guarantees and limitations clearly in documentation.

explanation
TOKEN DISTRIBUTION

How Private Vesting Works

Private vesting schedules allow teams to distribute tokens to investors and employees while keeping the details confidential on-chain. This guide explains the mechanics and setup process.

A private vesting schedule is a smart contract that releases tokens to beneficiaries over time, but unlike public vesting, it obscures key details from public blockchain explorers. This is crucial for startups to protect sensitive information like individual grant sizes, investor allocations, and internal team structures. Privacy is achieved by using cryptographic commitments, zero-knowledge proofs, or storing only hashed data on-chain, with the actual schedule details managed off-chain or revealed later.

The core components of a private vesting contract include a commitment scheme (like a Merkle tree root stored on-chain), a claim function that requires a cryptographic proof, and a release schedule defined by cliffs and linear vesting. For example, a contract might store a single bytes32 merkleRoot representing all vesting agreements. To claim tokens, a beneficiary submits a proof (a Merkle proof) that validates their specific allocation and vesting curve against this root, without revealing other participants' data.

Setting up a private vesting schedule involves several off-chain and on-chain steps. First, the admin generates the vesting data for each beneficiary: wallet address, total amount, cliff duration, vesting period, and start time. This data is hashed and organized into a Merkle tree. The root of this tree is then deployed to the smart contract as the single source of truth. Tools like the OpenZeppelin VestingWallet can be adapted, or specialized protocols like Sablier (for streams) or Superfluid can be integrated for more complex logic.

Here is a simplified code snippet for a basic private claim function using a Merkle proof:

solidity
function claimTokens(
    uint256 amount,
    uint256 cliff,
    uint256 duration,
    bytes32[] calldata merkleProof
) external {
    bytes32 leaf = keccak256(abi.encodePacked(msg.sender, amount, cliff, duration));
    require(MerkleProof.verify(merkleProof, merkleRoot, leaf), "Invalid proof");
    // Logic to transfer vested amount based on block.timestamp, cliff, and duration
}

The contract verifies the proof without storing individual beneficiary details on-chain.

Key considerations for implementation include revocability (admin ability to cancel future vesting), gas efficiency for proof verification, and secure off-chain data management. Privacy can be enhanced by using stealth addresses or integrating with privacy-focused networks like Aztec or zkSync. It's critical to audit the vesting contract thoroughly, as flaws in the proof logic or timing calculations can lead to lost funds or leaked information. Always test with tools like Foundry or Hardhat across multiple vesting scenarios.

Private vesting is essential for compliant fundraising (SAFTs) and competitive hiring. It balances transparency for token holders, who can verify the total locked supply, with necessary confidentiality for business operations. For teams, using audited solutions from providers like CoinList, Assure, or OtterSec reduces development risk. The final step is a clear off-chain communication plan for beneficiaries, explaining how to generate their proof and claim tokens when they become eligible.

IMPLEMENTATION APPROACHES

Privacy Vesting Method Comparison

A comparison of technical methods for implementing private token vesting schedules, detailing trade-offs in privacy, cost, and complexity.

Feature / MetricZero-Knowledge ProofsPrivate State ChannelsTrusted Execution Environments (TEEs)

Privacy Guarantee

Cryptographic (on-chain)

Off-chain with settlement

Hardware-based isolation

On-Chain Data Leakage

Only proof & commitment

Final net transfers only

Encrypted state hashes

Typical Gas Cost per Action

$50-200

$5-15

$20-80

Developer Complexity

High (circuit design)

Medium (state management)

Medium (enclave programming)

Trust Assumptions

Trustless (math)

Counterparty + watchtower

Hardware manufacturer + remote attestation

Time to Finality

~5 min (block confirm)

Instant (off-chain), ~10 min (on-chain dispute)

~5 min (block confirm)

Example Protocols

zkSync, Aztec, Mina

Connext, State Channels

Oasis Network, Secret Network, Phala

hashed-timelock-walkthrough
PRIVACY-FOCUSED IMPLEMENTATION

Step-by-Step: Hashed Timelock Contract

This guide details how to implement a token vesting schedule using a Hashed Timelock Contract (HTLC) to add privacy by concealing beneficiary details until claim time.

A Hashed Timelock Contract (HTLC) is a smart contract that locks funds until a recipient provides a cryptographic proof (a preimage) that matches a predefined hash, within a specified time window. For vesting, this mechanism can obscure the beneficiary's identity on-chain until they are ready to claim. Instead of storing a public address, the contract only stores a hash of a secret and the beneficiary's address. This adds a layer of privacy, as on-chain observers cannot link the locked funds to a specific wallet until the claim transaction is broadcast, revealing the preimage.

To set up a private vesting schedule, you first define the vesting parameters: the total token amount, the timelock duration (e.g., 365 days), and a claimDeadline that provides a buffer after the lock expires. The core privacy element is generating a 32-byte cryptographic secret (the preimage) and computing its keccak256 hash. This hash, along with the token amount and timelock, is stored in the contract. The beneficiary's address is never stored; they must provide it along with the secret when claiming. This design ensures the vesting allocation is not publicly attributable until the claim.

Here is a simplified Solidity code snippet for the lock function, using OpenZeppelin's IERC20 interface for safety:

solidity
function createVestingSchedule(
    bytes32 _hash,
    uint256 _amount,
    uint256 _timelock
) external {
    require(_timelock > block.timestamp, "Timelock must be in future");
    token.transferFrom(msg.sender, address(this), _amount);
    
    schedules[_hash] = VestingSchedule({
        amount: _amount,
        timelock: _timelock,
        claimed: false
    });
    emit ScheduleCreated(_hash, _amount, _timelock);
}

The _hash parameter is the commitment to the secret, serving as the contract's primary identifier for the vesting slot.

The claim function is where privacy is selectively removed. To claim, the beneficiary calls the contract with the secret preimage and their address. The contract hashes the provided preimage; if it matches the stored _hash and the timelock has expired, it transfers the tokens. Crucially, the beneficiary's address is only revealed in this transaction's msg.sender parameter and any emitted event. This method is trust-minimized: the contract logic guarantees payment to whoever first supplies the correct proof, aligning with HTLC's atomic swap heritage.

Key operational considerations include managing the claim window and secret security. The contract should include a claimDeadline (e.g., timelock + 30 days) after which unclaimed funds can be recovered by the grantor, preventing permanent locking. The secret must be shared with the beneficiary off-chain via a secure channel. For enhanced privacy, use a commit-reveal scheme or zero-knowledge proofs. Always audit the contract, especially the hash verification and state update logic, to prevent reentrancy or front-running attacks common in conditional payment schemes.

This HTLC pattern is applicable beyond simple vesting. It can be adapted for privacy-preserving airdrops, where claim eligibility is hidden, or for cross-chain vesting bridges that use hashed timelocks on both chains. When implementing, consider gas costs for hash operations and use established libraries like OpenZeppelin for token interactions. For production, integrate with a relayer or meta-transaction system to allow beneficiaries to claim without holding native gas tokens, completing a fully private vesting workflow.

zk-vesting-walkthrough
PRIVACY-PRESERVING DEFI

Step-by-Step: zk-SNARK Vesting Contract

This guide details how to implement a token vesting contract that uses zk-SNARKs to conceal beneficiary addresses and claim amounts, providing privacy for team allocations and investor unlocks.

A zk-SNARK vesting contract allows a beneficiary to prove they are eligible to claim tokens without revealing their identity on-chain. Traditional vesting contracts publicly map Ethereum addresses to vesting schedules, exposing sensitive financial data. By using a zero-knowledge proof, a user can generate a cryptographic proof that they possess a valid nullifier and secret for an unspent commitment in the contract's Merkle tree, then submit this proof to claim tokens to a fresh address. This breaks the on-chain link between the original allocation and the final recipient.

The system relies on a commitment scheme. When the vesting schedule is created, the contract owner generates a commitment C = hash(nullifier, secret, amount) and inserts it into an incremental Merkle tree, storing only the tree's root on-chain. The nullifier is a unique identifier that will later be revealed to prevent double-spending, while the secret remains known only to the beneficiary. The amount and beneficiary's address are kept off-chain, known only to the contract deployer and the recipient via a secure channel.

To claim tokens, the beneficiary uses a zk-SNARK circuit. This circuit, written in a language like Circom, takes private inputs (the nullifier, secret, and a Merkle tree path) and public inputs (the Merkle root and the nullifierHash). It proves: 1) The commitment C exists in the tree with the given root. 2) The provided nullifier and secret correctly hash to C. 3) The hashed nullifier (the nullifierHash) is computed correctly. The circuit output is a proof that is verified by a Solidity verifier contract.

The Solidity contract has two main functions. The addCommitment function allows the owner to insert new commitments by updating the Merkle root. The claim function accepts the zk-SNARK proof, the current Merkle root, and the nullifierHash. It verifies the proof against a pre-deployed verifier contract, checks that the nullifierHash hasn't been used before (to prevent replay), and then transfers the vested amount to msg.sender. The actual token amount is either embedded in the circuit logic or managed off-chain by the contract owner who releases the correct amount upon a valid proof.

Key privacy considerations include secure initial distribution of secrets, the need for a trusted setup for the zk-SNARK circuit, and managing the relationship between the off-chain data (the list of commitments with amounts) and the on-chain contract. Tools like the Semaphore framework or zk-kit can provide foundational libraries for Merkle trees and proof generation. This pattern is applicable for private airdrops, confidential employee compensation, and discreet investor distributions without leaking allocation sizes on public ledgers.

TOKEN VESTING

Frequently Asked Questions

Common technical questions and troubleshooting for implementing secure, private token vesting schedules using smart contracts.

The fundamental difference is on-chain data visibility. A standard, public vesting contract stores all schedule parameters—beneficiary addresses, total allocation amounts, cliff periods, and vesting durations—in plain view on the blockchain. Anyone can query this data.

A privacy-enhanced vesting contract uses cryptographic commitments (like zk-SNARKs or Merkle trees) to hide these details. Only the hash of the schedule parameters is stored on-chain. The actual data is kept off-chain, and a zero-knowledge proof is submitted to claim tokens, verifying eligibility without revealing the underlying information. This is crucial for projects that need to keep employee or investor allocations confidential.

TOKEN VESTING

Common Implementation Mistakes

Avoid critical errors when deploying private vesting schedules. These mistakes can lead to locked funds, privacy leaks, or exploitable contracts.

A common mistake is storing beneficiary addresses in public state variables or emitting them in events before the cliff period ends. This defeats the privacy goal. For true privacy, you must use a commit-reveal scheme or store only a hash of the beneficiary address until the reveal phase.

Key Fixes:

  • Store keccak256(abi.encodePacked(beneficiary, salt)) instead of the address.
  • Emit events with the hash, not the plain address.
  • Allow the beneficiary to "reveal" themselves later by providing the original address and salt, which the contract verifies against the stored hash.
  • Use a merkle tree design where only the root is stored on-chain, and beneficiaries prove inclusion with a merkle proof.
conclusion
IMPLEMENTATION SUMMARY

Conclusion and Next Steps

You have successfully set up a token vesting schedule with privacy features. This guide covered the core concepts, smart contract design, and deployment steps.

Implementing a private vesting schedule involves balancing transparency with confidentiality. Key design choices include using a commit-reveal scheme for beneficiary addresses, employing zk-SNARKs or zk-STARKs for proof of eligibility, and leveraging privacy-focused Layer 2 solutions like Aztec or Mina Protocol. The core contract must manage state commitments, verify zero-knowledge proofs, and execute token releases only to authorized, revealed addresses. Always audit the logic for front-running vulnerabilities during the reveal phase.

For production deployment, consider these next steps. First, thoroughly test your contracts using frameworks like Foundry or Hardhat, simulating edge cases in the reveal process. Second, use a verifier contract from a trusted library like circom or snarkjs for proof validation. Third, integrate an off-chain relayer or privacy middleware (e.g., Tornado Cash Nova's architecture) to handle proof generation without exposing user details. Finally, deploy on a testnet like Sepolia or zkSync Era Testnet before mainnet launch.

Explore advanced features to enhance your system. You can implement gradual privacy where vesting terms become public after cliffs. Consider transferable vesting rights using privacy-preserving NFTs. For multi-token support, design a factory contract that deploys separate vesting contracts for different ERC-20 tokens. Monitor emerging standards like EIP-7504 for on-chain privacy. Always document the privacy guarantees and limitations for your users, as regulatory compliance (like Travel Rule solutions) may require optional disclosure mechanisms.