This implementation introduces Performance-Based Cliff Vesting to the Divine vesting system, replacing traditional time-based cliffs with dynamic conditions that depend on real-world project metrics. This aligns investor interests with project growth by ensuring exit liquidity is only provided once the team delivers verifiable value to the ecosystem.
-
Oracle Module (
oracle.rs)OracleCondition: Defines a single performance conditionPerformanceCliff: Groups multiple conditions with AND/OR logicOracleClient: Handles oracle queries and condition evaluation
-
Enhanced Vesting Contract (
lib.rs)- Modified
calculate_claimable()to check performance cliffs first - New functions for cliff management
- Integration with existing milestone system
- Modified
pub enum OracleType {
TVL, // Total Value Locked targets
Price, // Token price targets
Custom, // Custom project metrics
}pub enum ComparisonOperator {
GreaterThan, // Current > Target
LessThan, // Current < Target
GreaterThanOrEqual, // Current >= Target
LessThanOrEqual, // Current <= Target
Equal, // Current == Target
}pub struct PerformanceCliff {
pub conditions: Vec<OracleCondition>, // Multiple conditions
pub require_all: bool, // true = AND, false = OR logic
pub fallback_time: u64, // Fallback timestamp if oracle fails
}The is_cliff_passed() function follows this priority:
- Oracle Conditions: Query external contracts for real-time metrics
- Fallback Time: If oracle fails, use timestamp as backup
- No Cliff Set: Default to time-based vesting (start_time check)
The modified calculate_claimable() function:
fn calculate_claimable(env: &Env, id: u64, vault: &Vault) -> i128 {
// 1. Check performance cliff first
if let Some(cliff) = env.storage().instance().get(&DataKey::VaultPerformanceCliff(id)) {
if !OracleClient::is_cliff_passed(env, &cliff, id) {
return 0; // Cliff not passed, no vesting
}
}
// 2. Continue with existing milestone or linear vesting logic
// ...
}// Create condition: TVL >= $1M
let tvl_condition = OracleClient::create_tvl_condition(
oracle_address,
1000000, // $1M target
ComparisonOperator::GreaterThanOrEqual,
);
let cliff = PerformanceCliff {
conditions: vec![tvl_condition],
require_all: true,
fallback_time: 1640995200, // Jan 1, 2022
};
// Create vault with performance cliff
let vault_id = VestingContract::create_vault_with_cliff(
env,
beneficiary,
amount,
start_time,
end_time,
keeper_fee,
is_revocable,
is_transferable,
step_duration,
cliff,
);// Condition 1: TVL >= $1M
let tvl_condition = OracleClient::create_tvl_condition(
tvl_oracle,
1000000,
ComparisonOperator::GreaterThanOrEqual,
);
// Condition 2: Token price >= $100
let price_condition = OracleClient::create_price_condition(
price_oracle,
100,
ComparisonOperator::GreaterThan,
Some(Symbol::new(env, "TOKEN")),
);
let cliff = PerformanceCliff {
conditions: vec![tvl_condition, price_condition],
require_all: false, // OR logic - any condition passes
fallback_time: 1640995200,
};set_performance_cliff(vault_id, cliff)- Admin-only cliff settingget_performance_cliff(vault_id)- Retrieve cliff configurationis_cliff_passed(vault_id)- Check if cliff conditions are met
create_vault_with_cliff()- Create vault with performance cliff- Existing
create_vault_full/lazy()functions remain unchanged
get_claimable_amount(vault_id)- Returns 0 if cliff not passedclaim_tokens(vault_id, amount)- Respects cliff conditions
- Fallback timestamp ensures vesting isn't permanently blocked
- Oracle failures don't prevent eventual token release
- Only admins can set performance cliffs
- Cliff changes affect future vesting calculations only
- Short-circuit evaluation for OR logic
- Cached results where possible
Performance cliffs work seamlessly with existing milestone vesting:
// Cliff must pass BEFORE milestone vesting is considered
if cliff_not_passed -> 0 tokens claimable
else if milestones_set -> milestone-based vesting
else -> linear vesting- Existing vaults without performance cliffs work unchanged
- Time-based vesting remains the default behavior
The implementation includes comprehensive tests in performance_cliff_test.rs:
- Basic Cliff Creation - Single condition setup
- Multiple Conditions - AND/OR logic testing
- Fallback Behavior - Oracle failure scenarios
- Milestone Integration - Combined cliff + milestone vesting
Replace placeholder oracle calls with actual cross-contract calls:
let oracle_client = OracleContractClient::new(env, &oracle_address);
let current_value = oracle_client.get_value(oracle_type, parameter);Allow cliff conditions to be updated (with proper governance).
Different vesting curves based on which conditions are met.
This implementation successfully introduces performance-based cliff vesting while maintaining full backward compatibility and security. The modular design allows for easy extension and integration with various oracle types, providing a robust foundation for milestone-first vesting that aligns investor and team incentives.