Arithmetic Overflow - Building Secure Contracts (original) (raw)

Building Secure Contracts

Arithmetic Overflow with Felt Type

The default primitive type, the field element (felt), behaves much like an integer in other languages, but there are a few important differences to keep in mind. A felt can be interpreted as an unsigned integer in the range [0, P], where P, a 252 bit prime, represents the order of the field used by Cairo. Arithmetic operations using felts are unchecked for overflow or underflow, which can lead to unexpected results if not properly accounted for. Do note that Cairo's builtin primitives for unsigned integers are overflow/underflow safe and will revert.

Example

The following simplified code highlights the risk of felt underflow. The check_balance function is used to validate if a user has a large enough balance. However, the check is faulty because passing an amount such that amt > balance will underflow and the check will be true.


struct Storage {
    balances: LegacyMap<ContractAddress, felt252>
}

fn check_balance(self: @ContractState, amt: felt252) {
    let caller = get_caller_address();
    let balance = self.balances.read(caller);
    assert(balance - amt >= 0);
}

Mitigations