The Last Markdown Editor, Ever

Preliminary Repository's https://cantina.xyz/code/8b94fd62-eea5-46fb-bed6-36ec5adf36af/README.mdhttps://github.com/cantina-forks/thala-modules/tree/mai

Summary

Formal verification of key modules within the Aave V3 codebase was conducted using an aggressive threat modeling approach with the prover. The process rigorously tested abort conditions, state consistency, authorization checks, and asset conservation to ensure secure and correct operation under all scenarios. This verification focused on mitigating potential threats and maintaining protocol integrity, ensuring the reliability of staking and reward mechanisms.

Modules include:

Spec Overview for aave_math::wad_ray_math.move

Functionality Details Verification Status
function wade_to_ray
Preconditions Input a must be non-negative (a >= 0).
Preconditions Input a must not cause overflow when multiplied by WAD_RAY_RATIO (a <= U256_MAX / WAD_RAY_RATIO).
Postconditions Result is a * WAD_RAY_RATIO.
Postconditions Result is non-negative (result >= 0).
Verification Consistency Overflow check: Ensure multiplication does not exceed u256 max value.
Verification Consistency Non-negative input: Validate inout non-negative.
Verification Consistency Non-negative input: Guarantees the result is non-negative.
function wade_mul
Preconditions Inputs a and b must be non-negative (a >= 0, b >= 0).
Preconditions The multiplication of a and b must not cause overflow (a <= (U256_MAX - HALF_WAD) / b).
Postconditions Result is the product of a and b, rounded half up to the nearest Wad.
Postconditions Result is non-negative (result >= 0).
Verification Conditions Overflow Check: Ensures the product of a and b does not exceed u256 max value.
Verification Conditions Non-Negative Inputs: Validates both inputs are non-negative.
Verification Conditions Non-Negative Result: Guarantees the result is non-negative.
function wade_mul
Preconditions Denominator b must be non-zero (b > 0).
Preconditions Inputs a and b must be non-negative (a >= 0, b >= 0).
Preconditions The division must not cause overflow (a <= (U256_MAX - b / 2) / WAD).
Postconditions Result is the division of a by b, rounded half up to the nearest Wad.
Postconditions Result is non-negative (result >= 0).
Postconditions Result is non-negative (result >= 0).
Verification conditions Division by Zero Check: Ensures denominator is not zero.
Verification conditions Non-Negative Inputs: Validates both inputs are non-negative.
Verification conditions Overflow Check: Ensures the division does not exceed u256 max value.
Verification conditions Non-Negative Result: Guarantees the result is non-negative.
function ray_div
Preconditions Denominator b must be non-zero (b > 0).
Preconditions Inputs a and b must be non-negative (a >= 0, b >= 0).
Preconditions The division must not cause overflow (a <= (U256_MAX - b / 2) / RAY).
Postconditions Result is the division of a by b, rounded half up to the nearest Ray.
Postconditions Result is non-negative (result >= 0).
Verification conditions Division by Zero Check: Ensures denominator is not zero.
Verification conditions Non-Negative Inputs: Validates both inputs are non-negative.
Verification conditions Overflow Check: Ensures the division does not exceed u256 max value.
Verification conditions Non-Negative Result: Guarantees the result is non-negative.
function ray_mul
Preconditions Inputs a and b must be non-negative (a >= 0, b >= 0)
Postconditions Result is the product of a and b, rounded half up to the nearest Ray.
Postconditions Result is non-negative (result >= 0).
Verification conditions Non-Negative Result: Guarantees the result is non-negative.
Verification conditions Non-Negative Inputs: Validates both inputs are non-negative.
function ray_to_wad
Processes stake actions, ensuring the resources and conditions are correct before accepting any stake. Verification is enabled to maintain consistency with the protocol rules.
Preconditions nput a must be non-negative (a >= 0).
Postconditions Result is the input a divided by WAD_RAY_RATIO, rounded half up to the nearest Wad.
Postconditions Result is non-negative (result >= 0).
Verification conditions Non-Negative Result: Guarantees the result is non-negative.
Verification conditions Non-Negative Inputs: Validates both inputs are non-negative.
  // Specification for wad_to_ray
    spec wad_to_ray {
        // Preconditions
        requires a >= 0; // Ensure non-negative input
        requires a <= U256_MAX / WAD_RAY_RATIO; // Ensure no overflow

        // Postconditions
        ensures result == a * WAD_RAY_RATIO;
        ensures result >= 0; // Result should be non-negative
    }

    // Attach the specification directly to the function
    spec wad_mul {
        // Preconditions
        requires a <= (U256_MAX - HALF_WAD) / b; // Ensure no overflow
        requires a >= 0; // Ensure non-negative input
        requires b >= 0; // Ensure non-negative input

        // Postconditions
        ensures result == if (a == 0 || b == 0) { 0 } else { (a * b + HALF_WAD) / WAD };
        ensures result >= 0; // Result should be non-negative
    }

      // Specification for wad_div
    spec wad_div {
        // Preconditions
        requires b > 0; // Denominator must be non-zero
        requires a <= (U256_MAX - b / 2) / WAD; // Ensure no overflow
        requires a >= 0; // Ensure non-negative input
        requires b >= 0; // Ensure non-negative input

        // Postconditions
        ensures result == if (a == 0) { 0 } else { (a * WAD + b / 2) / b };
        ensures result >= 0; // Result should be non-negative
    }

        // Specification for ray_div
    spec ray_div {
        // Preconditions
        requires b > 0; // Denominator must be non-zero
        requires a <= (U256_MAX - b / 2) / RAY; // Ensure no overflow
        requires a >= 0; // Ensure non-negative input
        requires b >= 0; // Ensure non-negative input

        // Postconditions
        ensures result == if (a == 0) { 0 } else { (a * RAY + b / 2) / b };
        ensures result >= 0; // Result should be non-negative
    }

        // Specification for ray_mul
    spec ray_mul {
        // Preconditions
        //this does not hold true here 
       // requires a <= (U256_MAX - HALF_RAY) / b; // Ensure no overflow
        requires a >= 0; // Ensure non-negative input
        requires b >= 0; // Ensure non-negative input

        // Postconditions
        ensures result == if (a == 0 || b == 0) { 0 } else { (a * b + HALF_RAY) / RAY };
        ensures result >= 0; // Result should be non-negative
    }

    // Specification for ray_to_wad
    spec ray_to_wad {
        // Preconditions
        requires a >= 0; // Ensure non-negative input

        // Postconditions
        ensures result == if (a % WAD_RAY_RATIO >= WAD_RAY_RATIO / 2) { a / WAD_RAY_RATIO + 1 } else { a / WAD_RAY_RATIO };
        ensures result >= 0; // Result should be non-negative
    }

}

Spec Overview for aave_math::math_utilis.move

Functionality Details Verification Status
function calculate_compounded_interest
Preconditions The interest rate must be non-negative.
Preconditions The timestamps must be in chronological order (last update timestamp cannot be in the future)
Preconditions Input a must not cause overflow when multiplied by WAD_RAY_RATIO (a <= U256_MAX / WAD_RAY_RATIO).
Postconditions The result is guaranteed to be at least equal to the base ray value(1.0 in ray format) ensures result >= wad_ray_math::ray();
Postconditions When no time has passed, the result equals exactly the base ray (no interest) ensures exp == 0 ==> result == wad_ray_math::ray();
Postconditions When no time has passed, the result equals exactly the base ray (no interest) ensures rate == 0 ==> result == wad_ray_math::ray()
Postconditions When the interest rate is zero, the result equals exactly the base ray (no interest)
Postconditions When time has passed and the rate is significant, interest will accrue (result > ray)
Verification Consistency For special case of exactly 1 time unit passing: Either the result is exactly as calculated by the formula or for very small rates that would round to zero, a minimum interest of 1 is applied.
function pow
Preconditions The base must be non-negative.
Preconditions The exponent must be non-negative.
Verification Conditions base == 0 && exponent > 0 ==> result == 0 should be true mathematically (0 raised to any positive power should be 0) ❌Acknowledged (Ideal fail)
Verification conditions base > 0 ==> result > 0 should also be true mathematically (any positive number raised to any power should be positive) ❌Acknowledged (Ideal fail)
function calculate_linear_interest
Preconditions requires rate >= 0. Ensures non-negative interest rate
Preconditions equires last_update_timestamp <= timestamp::now_seconds() . Validates timestamp ordering.
Postconditions ensures result >= wad_ray_math::ray()
Guarantees minimum interest result
Postconditions ensures last_update_timestamp == timestamp::now_seconds() ==> result == wad_ray_math::ray(). Validates no interest accrual when no time has pass
Postconditions ensures rate == 0 ==> result == wad_ray_math::ray()
Validates zero rate case
Verification conditions ensures rate > 0 && last_update_timestamp < timestamp::now_seconds() ==> result …
Verifies correct interest calculation formula
function percent_mul
Preconditions The value input must be non-negative.
Preconditions The percentage input must be non-negative.
Postconditions The result is guaranteed to be non-negative.
Postconditions If either value or percentage is zero, the result must be zero.
function percent_div
Preconditions Prevents division by zero by requiring percentage > 0.
Preconditions Checks for overflow: value > (U256_MAX - HALF_PERCENTAGE_FACTOR) / PERCENTAGE_FACTOR. ❌ Fixed https://cantina.xyz/code/b6dada12-d99d-4710-b1d3-e8a69b9af616/findings?created_by=movejay&finding=82
Postconditions Guarantees non-negative output: result >= 0.
Postconditions Validates zero input case: value == 0 ==> result == 0.
Postconditions Verifies correct calculation with proper rounding: result == (value * PERCENTAGE_FACTOR + percentage / 2) / percentage.
Postconditions Ensures upper bound of result: result <= (value * PERCENTAGE_FACTOR) / percentage + 1.
 // Specification for percent_div
    spec percent_div {
        // Preconditions
        requires value >= 0; // Ensure non-negative value
        requires percentage > 0; // Ensure non-zero percentage

        // Postconditions
        ensures result >= 0; // Result should be non-negative
        
        // Special cases
        ensures value == 0 ==> result == 0; // Zero value yields zero
        
        // Rounding behavior
        ensures value > 0 ==> 
            result == (value * PERCENTAGE_FACTOR + percentage / 2) / percentage;
        
        // Bounds checking
        ensures value > 0 ==> 
            result <= (value * PERCENTAGE_FACTOR) / percentage + 1;
        ensures result >= (value * PERCENTAGE_FACTOR) / percentage;
     
       
    }
    // Specification for percent_mul
    spec percent_mul {
        // Preconditions
        requires value >= 0; // Ensure non-negative value
        requires percentage >= 0; // Ensure non-negative percentage

        // Postconditions
        ensures result >= 0; // Result should be non-negative
        
        // Special cases
        ensures value == 0 || percentage == 0 ==> result == 0; // Zero inputs yield zero
        
        // Rounding behavior
        ensures value > 0 && percentage > 0 ==> 
            result == (value * percentage + HALF_PERCENTAGE_FACTOR) / PERCENTAGE_FACTOR;
        
        // Bounds checking
        ensures value > 0 && percentage > 0 ==> 
            result <= (value * percentage) / PERCENTAGE_FACTOR + 1;
        ensures result >= (value * percentage) / PERCENTAGE_FACTOR;
        
        // Overflow protection
        aborts_if value > 0 && percentage > 0 && 
            value > (U256_MAX - HALF_PERCENTAGE_FACTOR) / percentage
            with error_config::get_eoverflow();
    }
       // Specification for calculate_compounded_interest
    spec calculate_compounded_interest {
        // Preconditions
        requires rate >= 0; // Ensure non-negative rate
        requires last_update_timestamp <= current_timestamp; // Ensure valid timestamps

        // Postconditions
        ensures result >= wad_ray_math::ray(); // Result should be at least the base ray
        
        // Additional postconditions for specific cases
        ensures exp == 0 ==> result == wad_ray_math::ray(); // No time passed means no interest
        ensures rate == 0 ==> result == wad_ray_math::ray(); // Zero rate means no interest
        
        // Define exp for clarity in the specification
        let exp = ((current_timestamp - last_update_timestamp) as u256);
        
        // For the case where time has passed and rate is positive and significant
        // Only guarantee interest accrual when the rate is significant enough
        ensures exp > 0 && rate > SECONDS_PER_YEAR / exp ==> result > wad_ray_math::ray();
        
        // For the case where exp == 1, we need to account for our minimum interest guarantee
        ensures exp == 1 ==> (
            result == wad_ray_math::ray() + (rate / SECONDS_PER_YEAR) || 
            (rate > 0 && rate / SECONDS_PER_YEAR == 0 && result == wad_ray_math::ray() + 1)
        );
    }

    // Enhanced specification for calculate_linear_interest
    spec calculate_linear_interest {
        // Preconditions
        requires rate >= 0; // Ensure non-negative rate
        requires last_update_timestamp <= timestamp::now_seconds(); // Ensure valid timestamp

        // Postconditions
        ensures result >= wad_ray_math::ray(); // Result should be at least the base ray
        
        // Additional postconditions for specific cases
        ensures last_update_timestamp == timestamp::now_seconds() ==> result == wad_ray_math::ray(); // No time passed means no interest
        
        // Relationship between rate and result
        ensures rate > 0 && last_update_timestamp < timestamp::now_seconds() ==> 
            result == wad_ray_math::ray() + (rate * ((timestamp::now_seconds() - last_update_timestamp) as u256)) / SECONDS_PER_YEAR;
        
        // Remove the problematic forall expression for now
        // We'll add a simpler property instead
        ensures rate == 0 ==> result == wad_ray_math::ray(); // Zero rate means no interest
    }

    // Specification for calculate_compounded_interest_now
    spec calculate_compounded_interest_now {
        // Preconditions
        requires rate >= 0; // Ensure non-negative rate
        requires last_update_timestamp <= timestamp::now_seconds(); // Ensure valid timestamp

        // Postconditions
        ensures result >= wad_ray_math::ray(); // Result should be at least the base ray
    }

    // Enhanced specification for pow
    spec pow {
        // Preconditions
        requires base >= 0; // Ensure non-negative base
        requires exponent >= 0; // Ensure non-negative exponent
        
     //@audit -- does not hold -- Overflow risk 
        ///aborts_if value > 0 && percentage > 0 && 
		    ///(value * PERCENTAGE_FACTOR + percentage / 2) > U256_MAX
		    ///with error_config::get_eoverflow();
        
        
        // Additional postconditions for specific cases
   //@audit does not hold true here --Looks to be ideal 
        //ensures base == 0 && exponent > 0 ==> result == 0; // 0^n = 0 for n > 0
   //@audit does not hold true here --Looks to be ideal 
        //ensures base > 0 ==> result > 0; // If base is positive, result is positive
    }

    // Additional specification for the module constants
    spec module {
        // Ensure constants are properly defined
        invariant SECONDS_PER_YEAR == 365 * 24 * 3600;
        invariant PERCENTAGE_FACTOR == 10000;
        invariant HALF_PERCENTAGE_FACTOR == 5000;
    }

    // Specification for u256_max
    spec u256_max {
        // Postconditions
        ensures result == U256_MAX;
    }

    // Specification for get_percentage_factor
    spec get_percentage_factor {
        
       ensures result == PERCENTAGE_FACTOR;
    }

}