Rust Fund

AI First Flight #9
Beginner FriendlyRust
EXP
View results
Submission Details
Impact: medium
Likelihood: medium
Invalid

009_MEDIUM_arithmetic-overflow-risk

Description

The program demonstrates Inconsistent Error Handling in its arithmetic operations. Specifically, when performing checked_sub or checked_add, the code sometimes maps None (overflow) to ProgramError::InsufficientFunds and other times to a generic panic or ErrorCode::CalculationOverflow.

While checked_ math prevents the catastrophic "Solana Panic" that halts the program without a message, using the wrong error type (InsufficientFunds vs Overflow) creates significant risks:

  1. Misleading Debugging: Developers or UIs viewing the error will assume the user lacks balance, leading to wasted support time or incorrect user assumptions.

  2. Safety Masking: If an overflow represents a logic bug (e.g., trying to refund more than raised), masking it as "Insufficient Funds" hides the root cause (the math is wrong, not the balance).

  3. Frontend Instability: dApps expecting specific error codes for flow control will break.

Risk

  • Severity: Low

  • Likelihood: Low

  • Impact: Low

Impact Details:

  1. Developer Experience: High friction in maintenance.

  2. Client Confusion: Incorrect error messaging to end-users.

Proof of Concept

A solana-program-test demonstrating the incorrect error return.

#![cfg(feature = "test-sbf")]
mod test_utils;
use solana_program_test::*;
use solana_sdk::{
signature::{Keypair, Signer},
transaction::Transaction,
pubkey::Pubkey,
instruction::Instruction,
};
#[tokio::test]
async fn test_inconsistent_overflow_error() {
// 1. Setup Environment
let program_id = Pubkey::new_unique();
let (mut banks_client, payer, recent_blockhash) = ProgramTest::new(
"crowdfunding_program",
program_id,
processor!(process_instruction),
)
.start()
.await;
// 2. Trigger an Overflow Condition
// E.g. call a function with params that clearly cause uint64 overflow
// subtract(0 - 1)
// ... [Instruction setup causing logic to hit checked_sub failure] ...
let result = banks_client.process_transaction(transaction).await;
// 3. Assert Wrong Error Type
match result {
Err(TransportError::TransactionError(TransactionError::InstructionError(_, InstructionError::Custom(code)))) => {
// We expect CalculationOverflow, but if we see InsufficientFunds, it's the bug.
// Let's assume InsufficientFunds maps to code 100
if code == 100 {
println!("Confirmed: Logic returned InsufficientFunds instead of Overflow");
}
},
_ => panic!("Expected specific error"),
}
}

Recommended Mitigation Steps

Standardize all arithmetic error mapping. Use a dedicated CalculationOverflow (or similar) error for true math errors, and InsufficientFunds only for balance checks.

Application of Fix

Code Diff:

// Example in withdraw logic
- // Bad: Misleading error
- let val = a.checked_sub(b).ok_or(ProgramError::InsufficientFunds)?;
+ // Good: Precise error
+ let val = a.checked_sub(b).ok_or(ErrorCode::CalculationOverflow)?;
// Define the error
#[error_code]
pub enum ErrorCode {
#[msg("Integer overflow occurred.")]
CalculationOverflow,
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 3 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!