Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 63 additions & 6 deletions contract/contracts/predifi-contract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1523,6 +1523,66 @@ impl PredifiContract {
}
}

/// Validate stake limit modifications to ensure consistency and safety.
/// This function performs comprehensive checks before applying new stake limits to a pool.
///
/// # Validation Checks:
/// 1. min_stake must be positive (> 0)
/// 2. If max_stake is set (> 0), it must not be less than min_stake
/// 3. New min_stake must not exceed the pool's total_stake (existing liability check)
/// 4. New min_stake must not exceed the pool's max_total_stake limit (future capacity check)
/// 5. If max_stake is set, verify it allows room for at least one prediction at max level
/// 6. Prevent sudden reduction that would violate existing predictions (if applicable)
///
/// # Returns:
/// - Ok(()) if all validation checks pass
/// - Err(PredifiError::StakeBelowMinimum) if min_stake <= 0
/// - Err(PredifiError::StakeAboveMaximum) if constraints are violated
/// - Err(PredifiError::InvalidAmount) if amounts are invalid
fn validate_stake_limits(
env: &Env,
pool: &Pool,
new_min_stake: i128,
new_max_stake: i128,
) -> Result<(), PredifiError> {
// Check 1: min_stake must be positive
if new_min_stake <= 0 {
return Err(PredifiError::StakeBelowMinimum);
}

// Check 2: If max_stake is set, ensure min_stake <= max_stake
if new_max_stake > 0 && new_min_stake > new_max_stake {
return Err(PredifiError::InvalidAmount);
}

// Check 3: Ensure new min_stake doesn't exceed current total_stake
// This prevents setting a minimum that would retroactively invalidate existing bets
if new_min_stake > pool.total_stake {
return Err(PredifiError::StakeAboveMaximum);
}

// Check 4: If pool has a max_total_stake limit, new min_stake should be reasonable
if pool.max_total_stake > 0 && new_min_stake > pool.max_total_stake {
return Err(PredifiError::StakeAboveMaximum);
}

// Check 5: If max_stake is set, ensure it's reasonable relative to pool capacity
if new_max_stake > 0 && pool.max_total_stake > 0 && new_max_stake > pool.max_total_stake {
return Err(PredifiError::StakeAboveMaximum);
}

// Check 6: Prevent extreme ratio between min and max (prevent usability issues)
if new_max_stake > 0 {
// Ensure max is at least 10x min to allow reasonable participation range
let min_reasonable_ratio = new_min_stake.checked_mul(10).ok_or(PredifiError::ArithmeticError)?;
if new_max_stake < min_reasonable_ratio {
return Err(PredifiError::InvalidAmount);
}
}

Ok(())
}

/// Pure: Initialize outcome stakes vector with zeros.
/// Used for markets with many outcomes (e.g., 32+ teams tournament).
#[allow(dead_code)]
Expand All @@ -1534,6 +1594,7 @@ impl PredifiContract {
stakes
}


/// Get outcome stakes for a pool using optimized batch storage.
/// Falls back to individual storage keys for backward compatibility.
fn get_outcome_stakes(env: &Env, pool_id: u64, options_count: u32) -> Vec<i128> {
Expand Down Expand Up @@ -4299,12 +4360,8 @@ pub fn pause(env: Env, admin: Address) {
return Err(PredifiError::InvalidPoolState);
}

if min_stake <= 0 {
return Err(PredifiError::StakeBelowMinimum);
}
if max_stake > 0 && min_stake > max_stake {
return Err(PredifiError::InvalidAmount);
}
// Validate new stake limits before applying
Self::validate_stake_limits(&env, &pool, min_stake, max_stake)?;

pool.min_stake = min_stake;
pool.max_stake = max_stake;
Expand Down
Loading
Loading