Security Considerations¶
Overview¶
Moby Market implements multiple layers of security to protect against various attack vectors common in DeFi and trading systems. This document outlines the security architecture, threat model, and mitigation strategies.
Threat Model¶
Primary Threats¶
- Economic Attacks
- Flash loan attacks
- Oracle manipulation
- MEV (Maximal Extractable Value) exploitation
-
Market manipulation
-
Smart Contract Vulnerabilities
- Reentrancy attacks
- Integer overflow/underflow
- Access control bypass
-
Logic errors in algorithms
-
Privacy Attacks
- Transaction linking
- Timing analysis
- Side-channel attacks on ZK proofs
-
Anonymity set reduction
-
Infrastructure Attacks
- Front-running
- Sandwich attacks
- Denial of service
- Sybil attacks
Security Architecture¶
Defense in Depth¶
┌─────────────────────────────────────────┐
│ Application Layer │
│ • Input Validation │
│ • Authentication & Authorization │
│ • Rate Limiting │
├─────────────────────────────────────────┤
│ Protocol Layer │
│ • Access Control │
│ • State Validation │
│ • Economic Incentives │
├─────────────────────────────────────────┤
│ Cryptographic Layer │
│ • ZK Proof Verification │
│ • Signature Validation │
│ • Commitment Schemes │
├─────────────────────────────────────────┤
│ Infrastructure Layer │
│ • Oracle Security │
│ • Network Security │
│ • Hardware Security │
└─────────────────────────────────────────┘
Smart Contract Security¶
Access Control¶
#[derive(Accounts)]
pub struct RestrictedOperation<'info> {
#[account(mut, has_one = authority)]
pub controller_state: Account<'info, ControllerState>,
pub authority: Signer<'info>,
}
impl<'info> RestrictedOperation<'info> {
fn validate_authority(&self) -> Result<()> {
// Multi-layer authority validation
require!(
self.controller_state.authority == self.authority.key(),
ErrorCode::UnauthorizedAccess
);
// Check if system is paused
require!(
!self.controller_state.paused,
ErrorCode::SystemPaused
);
Ok(())
}
}
Reentrancy Protection¶
pub struct ReentrancyGuard {
pub locked: bool,
}
impl ReentrancyGuard {
pub fn acquire_lock(&mut self) -> Result<()> {
require!(!self.locked, ErrorCode::ReentrancyDetected);
self.locked = true;
Ok(())
}
pub fn release_lock(&mut self) {
self.locked = false;
}
}
#[derive(Accounts)]
pub struct ProtectedOperation<'info> {
#[account(mut)]
pub guard: Account<'info, ReentrancyGuard>,
}
pub fn protected_operation(ctx: Context<ProtectedOperation>) -> Result<()> {
// Acquire reentrancy lock
ctx.accounts.guard.acquire_lock()?;
// Perform operations
execute_critical_logic()?;
// Release lock
ctx.accounts.guard.release_lock();
Ok(())
}
Integer Safety¶
use anchor_lang::prelude::*;
use checked_math::CheckedMath;
pub fn safe_arithmetic_operations(
amount_a: u64,
amount_b: u64,
multiplier: u64,
) -> Result<u64> {
// Use checked arithmetic to prevent overflow
let sum = amount_a
.checked_add(amount_b)
.ok_or(ErrorCode::MathOverflow)?;
let result = sum
.checked_mul(multiplier)
.ok_or(ErrorCode::MathOverflow)?
.checked_div(1000000) // Assuming 6 decimal precision
.ok_or(ErrorCode::MathUnderflow)?;
Ok(result)
}
// Custom error types
#[error_code]
pub enum ErrorCode {
#[msg("Mathematical overflow detected")]
MathOverflow,
#[msg("Mathematical underflow detected")]
MathUnderflow,
#[msg("Division by zero")]
DivisionByZero,
}
State Validation¶
pub fn validate_order_state(order: &OTCOrder) -> Result<()> {
// Validate order amounts
require!(order.amount_a > 0, ErrorCode::InvalidAmount);
require!(order.amount_b > 0, ErrorCode::InvalidAmount);
// Validate expiry
let current_time = Clock::get()?.unix_timestamp;
require!(order.expiry > current_time, ErrorCode::OrderExpired);
// Validate token mints
require!(
order.token_mint_a != order.token_mint_b,
ErrorCode::SameTokenTrade
);
// Validate partial fill configuration
if order.partial_fill_allowed {
require!(
order.min_fill_size <= order.amount_a,
ErrorCode::InvalidMinFillSize
);
}
Ok(())
}
MEV Protection¶
Commit-Reveal Scheme¶
pub struct CommitRevealOrder {
pub commitment: [u8; 32], // Hash of order details + secret
pub reveal_deadline: i64, // When commitment must be revealed
pub execution_deadline: i64, // When order expires
pub committed: bool,
pub revealed: bool,
}
impl CommitRevealOrder {
pub fn commit_order(
&mut self,
order_hash: [u8; 32],
secret: [u8; 32],
reveal_window: i64,
) -> Result<()> {
let current_time = Clock::get()?.unix_timestamp;
// Create commitment
let mut hasher = Hasher::new();
hasher.update(&order_hash);
hasher.update(&secret);
self.commitment = hasher.finalize().into();
// Set deadlines
self.reveal_deadline = current_time + reveal_window;
self.execution_deadline = self.reveal_deadline + reveal_window;
self.committed = true;
Ok(())
}
pub fn reveal_order(
&mut self,
order_details: &OrderDetails,
secret: [u8; 32],
) -> Result<()> {
require!(self.committed, ErrorCode::OrderNotCommitted);
require!(!self.revealed, ErrorCode::OrderAlreadyRevealed);
let current_time = Clock::get()?.unix_timestamp;
require!(
current_time <= self.reveal_deadline,
ErrorCode::RevealDeadlinePassed
);
// Verify commitment
let order_hash = hash_order_details(order_details);
let mut hasher = Hasher::new();
hasher.update(&order_hash);
hasher.update(&secret);
let computed_commitment: [u8; 32] = hasher.finalize().into();
require!(
computed_commitment == self.commitment,
ErrorCode::InvalidReveal
);
self.revealed = true;
Ok(())
}
}
Private Mempool Integration¶
pub struct PrivateMempoolConfig {
pub flashbots_relay: bool,
pub jito_bundle_mode: bool,
pub custom_relayers: Vec<Pubkey>,
pub min_tip_lamports: u64,
}
pub fn submit_private_transaction(
transaction: Transaction,
config: &PrivateMempoolConfig,
) -> Result<()> {
if config.jito_bundle_mode {
submit_jito_bundle(transaction, config.min_tip_lamports)?;
} else if config.flashbots_relay {
submit_flashbots_bundle(transaction)?;
} else {
// Use custom relayers
submit_to_custom_relayers(transaction, &config.custom_relayers)?;
}
Ok(())
}
Oracle Security¶
Multi-Oracle Aggregation¶
pub struct OracleAggregator {
pub pyth_feed: Option<Pubkey>,
pub switchboard_feed: Option<Pubkey>,
pub chainlink_feed: Option<Pubkey>,
pub custom_feeds: Vec<Pubkey>,
pub aggregation_method: AggregationMethod,
pub deviation_threshold: u16, // Basis points
pub staleness_threshold: i64, // Seconds
}
impl OracleAggregator {
pub fn get_secure_price(&self, token: &Pubkey) -> Result<Price> {
let mut prices = Vec::new();
let current_time = Clock::get()?.unix_timestamp;
// Collect prices from all sources
if let Some(pyth_feed) = self.pyth_feed {
if let Ok(price) = self.get_pyth_price(&pyth_feed) {
if current_time - price.timestamp < self.staleness_threshold {
prices.push(price);
}
}
}
if let Some(switchboard_feed) = self.switchboard_feed {
if let Ok(price) = self.get_switchboard_price(&switchboard_feed) {
if current_time - price.timestamp < self.staleness_threshold {
prices.push(price);
}
}
}
// Require minimum number of price sources
require!(prices.len() >= 2, ErrorCode::InsufficientOracleSources);
// Detect and filter outliers
let filtered_prices = self.filter_outliers(prices)?;
require!(!filtered_prices.is_empty(), ErrorCode::NoValidPrices);
// Aggregate using configured method
let aggregated_price = match self.aggregation_method {
AggregationMethod::Median => self.calculate_median(&filtered_prices),
AggregationMethod::Mean => self.calculate_mean(&filtered_prices),
AggregationMethod::TWAP => self.calculate_twap(&filtered_prices),
}?;
Ok(aggregated_price)
}
fn filter_outliers(&self, prices: Vec<Price>) -> Result<Vec<Price>> {
if prices.len() < 3 {
return Ok(prices);
}
let median = self.calculate_median(&prices)?;
let threshold = median.value * self.deviation_threshold as u64 / 10000;
let filtered: Vec<Price> = prices
.into_iter()
.filter(|price| {
let deviation = if price.value > median.value {
price.value - median.value
} else {
median.value - price.value
};
deviation <= threshold
})
.collect();
Ok(filtered)
}
}
Price Manipulation Detection¶
pub struct PriceManipulationDetector {
pub historical_prices: VecDeque<Price>,
pub volatility_threshold: f64,
pub volume_spike_threshold: f64,
pub price_impact_threshold: f64,
}
impl PriceManipulationDetector {
pub fn detect_manipulation(&mut self, new_price: Price) -> ManipulationRisk {
let risk_score = self.calculate_risk_score(&new_price);
// Update historical data
self.historical_prices.push_back(new_price);
if self.historical_prices.len() > 100 {
self.historical_prices.pop_front();
}
match risk_score {
score if score > 0.8 => ManipulationRisk::High,
score if score > 0.5 => ManipulationRisk::Medium,
_ => ManipulationRisk::Low,
}
}
fn calculate_risk_score(&self, new_price: &Price) -> f64 {
let mut risk_factors = Vec::new();
// Check price volatility
if let Some(volatility) = self.calculate_recent_volatility() {
if volatility > self.volatility_threshold {
risk_factors.push(0.3);
}
}
// Check volume spike
if let Some(avg_volume) = self.calculate_average_volume() {
if new_price.volume > avg_volume * self.volume_spike_threshold {
risk_factors.push(0.4);
}
}
// Check price deviation
if let Some(expected_price) = self.calculate_expected_price() {
let deviation = (new_price.value as f64 - expected_price) / expected_price;
if deviation.abs() > self.price_impact_threshold {
risk_factors.push(0.5);
}
}
// Combine risk factors
risk_factors.iter().sum::<f64>().min(1.0)
}
}
Privacy Security¶
ZK Proof Security¶
pub struct ProofVerifier {
pub verification_keys: HashMap<CircuitType, VerificationKey>,
pub trusted_setup_hash: [u8; 32],
pub circuit_constraints: HashMap<CircuitType, u32>,
}
impl ProofVerifier {
pub fn verify_proof_with_security_checks(
&self,
proof: &Proof,
circuit_type: CircuitType,
public_inputs: &[Fr],
) -> Result<bool> {
// Verify trusted setup integrity
self.verify_trusted_setup(circuit_type)?;
// Check proof size and structure
self.validate_proof_structure(proof, circuit_type)?;
// Verify the actual proof
let vk = self.verification_keys.get(&circuit_type)
.ok_or(ErrorCode::VerificationKeyNotFound)?;
let is_valid = match proof.protocol {
ZKProtocol::Groth16 => {
groth16::verify_proof(vk, proof, public_inputs)?
},
ZKProtocol::PLONK => {
plonk::verify_proof(vk, proof, public_inputs)?
},
// ... other protocols
};
// Additional security checks
if is_valid {
self.perform_additional_security_checks(proof, public_inputs)?;
}
Ok(is_valid)
}
fn perform_additional_security_checks(
&self,
proof: &Proof,
public_inputs: &[Fr],
) -> Result<()> {
// Check for proof malleability
self.check_proof_uniqueness(proof)?;
// Validate public input ranges
self.validate_public_input_ranges(public_inputs)?;
// Check for known attack patterns
self.check_known_attack_patterns(proof)?;
Ok(())
}
}
Side-Channel Protection¶
pub struct ConstantTimeOps;
impl ConstantTimeOps {
// Constant-time comparison to prevent timing attacks
pub fn constant_time_compare(a: &[u8], b: &[u8]) -> bool {
if a.len() != b.len() {
return false;
}
let mut result = 0u8;
for i in 0..a.len() {
result |= a[i] ^ b[i];
}
result == 0
}
// Constant-time conditional selection
pub fn constant_time_select(condition: bool, a: &[u8], b: &[u8]) -> Vec<u8> {
let condition_mask = if condition { 0xFF } else { 0x00 };
a.iter()
.zip(b.iter())
.map(|(&a_byte, &b_byte)| {
(a_byte & condition_mask) | (b_byte & !condition_mask)
})
.collect()
}
}
Economic Security¶
Flash Loan Protection¶
pub struct FlashLoanGuard {
pub min_block_delay: u64,
pub max_price_impact: u16, // Basis points
pub required_collateral_ratio: u16,
}
impl FlashLoanGuard {
pub fn validate_transaction(
&self,
ctx: &Context<'_, '_, '_, '_>,
transaction_data: &TransactionData,
) -> Result<()> {
// Check if transaction spans multiple blocks
let current_slot = Clock::get()?.slot;
if let Some(start_slot) = transaction_data.start_slot {
require!(
current_slot >= start_slot + self.min_block_delay,
ErrorCode::FlashLoanDetected
);
}
// Check price impact
let price_impact = self.calculate_price_impact(transaction_data)?;
require!(
price_impact <= self.max_price_impact,
ErrorCode::ExcessivePriceImpact
);
// Verify collateral requirements
if transaction_data.involves_borrowing {
self.verify_collateral_ratio(ctx, transaction_data)?;
}
Ok(())
}
fn verify_collateral_ratio(
&self,
ctx: &Context<'_, '_, '_, '_>,
transaction_data: &TransactionData,
) -> Result<()> {
let collateral_value = self.calculate_collateral_value(ctx)?;
let debt_value = self.calculate_debt_value(transaction_data)?;
let collateral_ratio = if debt_value > 0 {
(collateral_value * 10000) / debt_value
} else {
u64::MAX
};
require!(
collateral_ratio >= self.required_collateral_ratio as u64,
ErrorCode::InsufficientCollateral
);
Ok(())
}
}
Slippage Protection¶
pub struct SlippageProtection {
pub max_slippage_bps: u16,
pub price_impact_threshold: u16,
pub minimum_liquidity: u64,
}
impl SlippageProtection {
pub fn validate_execution(
&self,
expected_output: u64,
actual_output: u64,
market_conditions: &MarketConditions,
) -> Result<()> {
// Calculate actual slippage
let slippage_bps = if expected_output > 0 {
((expected_output - actual_output) * 10000) / expected_output
} else {
0
};
require!(
slippage_bps <= self.max_slippage_bps as u64,
ErrorCode::ExcessiveSlippage
);
// Check market impact
let price_impact = self.calculate_market_impact(
expected_output,
actual_output,
market_conditions
)?;
require!(
price_impact <= self.price_impact_threshold,
ErrorCode::ExcessiveMarketImpact
);
// Verify sufficient liquidity
require!(
market_conditions.available_liquidity >= self.minimum_liquidity,
ErrorCode::InsufficientLiquidity
);
Ok(())
}
}
Emergency Response¶
Circuit Breaker¶
pub struct CircuitBreaker {
pub triggered: bool,
pub trigger_conditions: Vec<TriggerCondition>,
pub emergency_contacts: Vec<Pubkey>,
pub auto_recovery_enabled: bool,
pub recovery_delay: i64,
}
impl CircuitBreaker {
pub fn check_trigger_conditions(&mut self) -> Result<()> {
for condition in &self.trigger_conditions {
if self.evaluate_condition(condition)? {
self.trigger_emergency_stop(condition)?;
break;
}
}
Ok(())
}
pub fn trigger_emergency_stop(&mut self, condition: &TriggerCondition) -> Result<()> {
self.triggered = true;
// Log the incident
emit!(EmergencyStopEvent {
trigger_condition: condition.clone(),
timestamp: Clock::get()?.unix_timestamp,
triggered_by: condition.triggered_by,
});
// Notify emergency contacts
for contact in &self.emergency_contacts {
// Send emergency notification
self.notify_emergency_contact(contact, condition)?;
}
// Pause all operations
self.pause_all_operations()?;
Ok(())
}
pub fn manual_recovery(&mut self, authority: &Signer) -> Result<()> {
// Verify authority
require!(
self.emergency_contacts.contains(&authority.key()),
ErrorCode::UnauthorizedRecovery
);
// Reset circuit breaker
self.triggered = false;
// Resume operations
self.resume_operations()?;
emit!(RecoveryEvent {
timestamp: Clock::get()?.unix_timestamp,
recovered_by: authority.key(),
});
Ok(())
}
}
#[derive(Clone, Debug)]
pub enum TriggerCondition {
PriceDeviation { threshold: u16 },
VolumeSpike { multiplier: u16 },
LiquidityDrop { minimum: u64 },
OracleFailure { max_stale_time: i64 },
ExploitDetection { pattern: ExploitPattern },
}
Incident Response¶
pub struct IncidentResponse {
pub response_team: Vec<Pubkey>,
pub escalation_levels: Vec<EscalationLevel>,
pub communication_channels: Vec<CommunicationChannel>,
pub recovery_procedures: HashMap<IncidentType, RecoveryProcedure>,
}
impl IncidentResponse {
pub fn handle_security_incident(
&self,
incident: SecurityIncident,
) -> Result<IncidentResponse> {
// Assess incident severity
let severity = self.assess_incident_severity(&incident)?;
// Execute immediate response
match severity {
Severity::Critical => {
self.execute_critical_response(&incident)?;
},
Severity::High => {
self.execute_high_priority_response(&incident)?;
},
Severity::Medium => {
self.execute_standard_response(&incident)?;
},
_ => {
self.execute_low_priority_response(&incident)?;
}
}
// Initiate recovery procedures
if let Some(procedure) = self.recovery_procedures.get(&incident.incident_type) {
self.initiate_recovery(procedure)?;
}
Ok(IncidentResponse::InProgress)
}
}
Audit Requirements¶
Smart Contract Audits¶
- Code Review Requirements
- Minimum 3 independent audit firms
- Focus on economic logic and access controls
- Formal verification for critical paths
-
Gas optimization analysis
-
ZK Circuit Audits
- Circuit constraint verification
- Trusted setup validation
- Soundness and completeness proofs
-
Implementation security review
-
Economic Security Audits
- Game theory analysis
- Incentive mechanism review
- Attack vector identification
- Economic model validation
Continuous Security¶
pub struct SecurityMonitoring {
pub anomaly_detector: AnomalyDetector,
pub threat_intelligence: ThreatIntelligence,
pub automated_responses: Vec<AutomatedResponse>,
pub security_metrics: SecurityMetrics,
}
impl SecurityMonitoring {
pub fn monitor_security_continuously(&mut self) -> Result<()> {
// Detect anomalies in real-time
let anomalies = self.anomaly_detector.scan_for_anomalies()?;
for anomaly in anomalies {
// Check against threat intelligence
let threat_level = self.threat_intelligence
.assess_threat_level(&anomaly)?;
// Execute automated response if necessary
if threat_level >= ThreatLevel::Medium {
self.execute_automated_response(&anomaly)?;
}
// Update security metrics
self.security_metrics.record_incident(&anomaly);
}
Ok(())
}
}
Best Practices¶
Development Security¶
- Secure Coding Practices
- Input validation on all user inputs
- Use checked arithmetic operations
- Implement proper access controls
-
Follow the principle of least privilege
-
Testing Requirements
- Unit tests for all security-critical functions
- Integration tests for cross-program interactions
- Fuzz testing for input validation
-
Stress testing for economic attacks
-
Deployment Security
- Use multi-signature wallets for admin functions
- Implement timelock for critical upgrades
- Monitor all deployed contracts continuously
- Maintain incident response procedures
Operational Security¶
- Key Management
- Hardware security modules for critical keys
- Key rotation procedures
- Multi-party computation for sensitive operations
-
Secure key backup and recovery
-
Infrastructure Security
- Network segmentation
- DDoS protection
- Regular security updates
-
Intrusion detection systems
-
Monitoring and Alerting
- Real-time transaction monitoring
- Anomaly detection systems
- Security incident response team
- Regular security assessments