TokenDistributionV2
Multi-tier token vesting and distribution contract for PRIV Protocol allocations.
TokenDistributionV2
The TokenDistributionV2 contract manages PRIV token allocations and vesting schedules for the Founder, Treasury, and Ecosystem Rewards allocations.
Overview
Token Allocation (100M Total Supply)
| Allocation | Amount | TGE Unlock | Cliff | Vesting |
|---|---|---|---|---|
| Founder | 30M (30%) | 3M (10%) | 6 months | 24 months linear |
| Treasury | 13M (13%) | 6.5M (50%) | None | 12 months linear |
| Ecosystem Rewards | 25M (25%) | 0 | None | Released via rewards |
| Presale | 15M (15%) | 20% (3M) | - | 6 months linear (via PrivPresale contract) |
| Liquidity | 10M (10%) | 100% | - | Not in this contract |
| Reserve | 5M (5%) | - | - | Not in this contract |
This contract manages 70M tokens. The remaining 30M (15M Presale + 10M Liquidity + 5M Reserve) are handled separately.
Allocation Types
enum AllocationType {
Founder, // 30M: 3M TGE, 6mo cliff, 24mo vest
Treasury, // 13M: 6.5M TGE, 12mo vest
EcosystemRewards // 25M: Released via rewards contracts
}Constants
Founder Allocation
| Constant | Value | Description |
|---|---|---|
FOUNDER_TOTAL | 30,000,000 PRIV | Total founder allocation |
FOUNDER_TGE | 3,000,000 PRIV | TGE unlock (10%) |
FOUNDER_CLIFF | 6 months | Cliff duration |
FOUNDER_VESTING_DURATION | 24 months | Linear vesting after cliff |
Treasury Allocation
| Constant | Value | Description |
|---|---|---|
TREASURY_TOTAL | 13,000,000 PRIV | Total treasury allocation |
TREASURY_TGE | 6,500,000 PRIV | TGE unlock (50%) |
TREASURY_CLIFF | 0 | No cliff |
TREASURY_VESTING_DURATION | 12 months | Linear vesting |
Ecosystem Rewards
| Constant | Value | Description |
|---|---|---|
ECOSYSTEM_TOTAL | 25,000,000 PRIV | Total ecosystem allocation |
ECOSYSTEM_TGE | 0 | No TGE unlock |
ECOSYSTEM_VESTING_DURATION | 0 | Released via rewards |
General
| Constant | Value | Description |
|---|---|---|
TOTAL_DISTRIBUTION | 70,000,000 PRIV | Total managed by contract |
BENEFICIARY_TIMELOCK | 2 days | Timelock for beneficiary changes |
Functions
Initialization
initializeAllocations
Initializes all token allocations. Can only be called once.
function initializeAllocations() external onlyOwnerRequirements:
- Contract must not be already initialized
- Contract must hold at least 70M PRIV tokens
Events:
event AllocationsInitialized(uint256 tgeTimestamp);Beneficiary Management
setBeneficiary
Sets the initial beneficiary for an allocation (one-time only).
function setBeneficiary(
AllocationType allocationType,
address beneficiary
) external onlyOwnerRequirements:
- Beneficiary must not already be set
- Address must not be zero
proposeBeneficiaryChange
Proposes changing a beneficiary (with 2-day timelock).
function proposeBeneficiaryChange(
AllocationType allocationType,
address newBeneficiary
) externalRequirements:
- Caller must be current beneficiary or owner
- New beneficiary must not be zero address
Events:
event BeneficiaryChangeProposed(
AllocationType indexed allocationType,
address indexed currentBeneficiary,
address indexed newBeneficiary,
uint256 effectiveTime
);executeBeneficiaryChange
Executes a pending beneficiary change after timelock.
function executeBeneficiaryChange(AllocationType allocationType) externalcancelBeneficiaryChange
Cancels a pending beneficiary change.
function cancelBeneficiaryChange(AllocationType allocationType) externalClaiming
claim
Claims all currently vested tokens for an allocation.
function claim(AllocationType allocationType) external nonReentrantRequirements:
- Contract must be initialized
- Caller must be the beneficiary
- Must have claimable tokens
Events:
event TokensClaimed(
AllocationType indexed allocationType,
address indexed beneficiary,
uint256 amount
);View Functions
getClaimable
Returns the amount currently claimable for an allocation.
function getClaimable(AllocationType allocationType) public view returns (uint256)getAllocationStatus
Returns comprehensive status for an allocation.
function getAllocationStatus(AllocationType allocationType) external view returns (
uint256 totalAmount,
uint256 vestedAmount,
uint256 claimedAmount,
uint256 claimableAmount,
uint256 vestingStart,
uint256 cliffEnd,
uint256 vestingEnd,
address beneficiary
)getPendingBeneficiaryChange
Returns pending beneficiary change details.
function getPendingBeneficiaryChange(AllocationType allocationType) external view returns (
address newBeneficiary,
uint256 effectiveTime,
uint256 timeRemaining
)getAllAllocations
Returns all three allocation structs.
function getAllAllocations() external view returns (Allocation[3] memory)getTotalClaimed / getTotalRemaining
Returns aggregate claiming statistics.
function getTotalClaimed() external view returns (uint256)
function getTotalRemaining() external view returns (uint256)Vesting Schedule Visualization
Founder (30M)
TGE 6 months 30 months
| | |
v v v
[3M TGE]---[CLIFF]---[===== 27M LINEAR =====]
At TGE: 3M unlocked
Month 6: 3M (cliff ends, vesting begins)
Month 12: 3M + 6.75M = 9.75M
Month 18: 3M + 13.5M = 16.5M
Month 24: 3M + 20.25M = 23.25M
Month 30: 30M (fully vested)Treasury (13M)
TGE 12 months
| |
v v
[6.5M TGE]---[======= 6.5M LINEAR =======]
At TGE: 6.5M unlocked
Month 6: 6.5M + 3.25M = 9.75M
Month 12: 13M (fully vested)Ecosystem (25M)
TGE
|
v
[========= 25M AVAILABLE FOR REWARDS =========]
All 25M available immediately for rewards distribution.Integration Example
import { ethers } from 'ethers';
const distribution = new ethers.Contract(address, abi, signer);
// Check allocation status
const status = await distribution.getAllocationStatus(0); // Founder
console.log('Total:', ethers.formatEther(status.totalAmount));
console.log('Vested:', ethers.formatEther(status.vestedAmount));
console.log('Claimed:', ethers.formatEther(status.claimedAmount));
console.log('Claimable:', ethers.formatEther(status.claimableAmount));
// Claim tokens (as beneficiary)
const claimable = await distribution.getClaimable(0); // Founder
if (claimable > 0) {
const tx = await distribution.claim(0);
await tx.wait();
}
// Propose beneficiary change (2-day timelock)
const tx = await distribution.proposeBeneficiaryChange(
0, // Founder allocation
newBeneficiaryAddress
);
await tx.wait();
// After 2 days, execute the change
await distribution.executeBeneficiaryChange(0);Security Features
| Feature | Description |
|---|---|
| ReentrancyGuard | Protection against reentrancy attacks |
| Beneficiary Timelock | 2-day delay for beneficiary changes |
| One-Time Init | Allocations can only be initialized once |
| SafeERC20 | Safe token transfer handling |
| Balance Check | Requires full balance before initialization |
Events Reference
| Event | Description |
|---|---|
AllocationsInitialized | Contract initialized with TGE timestamp |
TokensClaimed | Tokens claimed by beneficiary |
BeneficiarySet | Initial beneficiary set |
BeneficiaryChangeProposed | Beneficiary change proposed |
BeneficiaryChangeCancelled | Pending change cancelled |
BeneficiaryChanged | Beneficiary change executed |