Skip to main content

The Pattern

pragma language_version >= 0.17.0;

import CompactStandardLibrary;

export ledger balance: Uint<128>;
export ledger totalSupply: Uint<128>;

// Maximum value for Uint<128>
const MAX_UINT128 = 340282366920938463463374607431768211455 as Uint<128>;

// Safe addition with overflow check
export circuit safeAdd(a: Uint<128>, b: Uint<128>): Uint<128> {
    assert(a <= MAX_UINT128 - b, "Addition overflow");
    return a + b;
}

// Safe subtraction with underflow check
export circuit safeSub(a: Uint<128>, b: Uint<128>): Uint<128> {
    assert(a >= b, "Subtraction underflow");
    return a - b;
}

// Safe multiplication with overflow check
export circuit safeMul(a: Uint<128>, b: Uint<128>): Uint<128> {
    if (a == 0 || b == 0) {
        return 0;
    }
    assert(a <= MAX_UINT128 / b, "Multiplication overflow");
    return a * b;
}

Overflow Checks

Addition Overflow

const MAX_UINT128 = 340282366920938463463374607431768211455 as Uint<128>;

// Check: a + b won't exceed MAX_UINT128
assert(a <= MAX_UINT128 - b, "Addition overflow");
const result = a + b;
Before adding, verify that a + b won’t exceed the maximum value. Example: Adding balances, increasing supply
// Check total supply won't overflow
assert(totalSupply <= MAX_UINT128 - amount, "Total supply overflow");
totalSupply = disclose(totalSupply + amount);

Subtraction Underflow

// Check: a - b won't go below zero
assert(a >= b, "Subtraction underflow");
const result = a - b;
Before subtracting, verify that a >= b to prevent negative results. Example: Deducting balances, burning tokens
// Check sufficient balance
const currentBalance = getBalance(account);
assert(currentBalance >= amount, "Insufficient balance");
balances.insert(disclose(account), disclose(currentBalance - amount));

Multiplication Overflow

// Check: a * b won't exceed MAX_UINT128
if (a == 0 || b == 0) {
    return 0;
}
assert(a <= MAX_UINT128 / b, "Multiplication overflow");
const result = a * b;
Before multiplying, verify the result won’t overflow.

Type Bounds

Different Uint sizes have different maximum values:
  • Uint<8> max: 255
  • Uint<16> max: 65,535
  • Uint<32> max: 4,294,967,295
  • Uint<64> max: 18,446,744,073,709,551,615
  • Uint<128> max: 340,282,366,920,938,463,463,374,607,431,768,211,455
Always check against the appropriate maximum for your type.

What’s Next