Skip to content

feat(registry): overflow-safe math sweep and hardened error paths - #825

Merged
greatest0fallt1me merged 1 commit into
CalloraOrg:mainfrom
Paranoa-dev:feat/overflow-safe-math-sweep-registry
Jul 28, 2026
Merged

feat(registry): overflow-safe math sweep and hardened error paths#825
greatest0fallt1me merged 1 commit into
CalloraOrg:mainfrom
Paranoa-dev:feat/overflow-safe-math-sweep-registry

Conversation

@Paranoa-dev

Copy link
Copy Markdown
Contributor

Summary

Replaces all raw arithmetic in the Callora Registry contract with overflow-safe checked operations and eliminates unwrap_or() from production code paths.

Changes

contracts/registry/src/lib.rs

  • Replace .unwrap_or(0) with .ok_or(RegistryError::NotInitialized)? on RegisteredCount reads in register_offering(), register_offering_with_gate(), and registered_count(). This removes silent fallback-to-zero that could mask initialization bugs and aligns with the "no unwrap() in production paths" guideline.
  • The existing checked_add(1).ok_or(RegistryError::Overflow)? pattern on the count increment is preserved (was already correct).

contracts/registry/tests/overflow_safe.rs (new � 15 tests)

Test What it verifies
register_offering_count_overflow_returns_error u32::MAX count � RegistryError::Overflow
register_offering_with_gate_count_overflow_returns_error Same overflow on gated path
overflow_does_not_persist_offering_record No partial state after overflow
register_offering_increments_count Count increments 0�1�2
register_offering_with_gate_increments_count Count increments via gated path
balance_gate_exact_match_allows_registration balance == min_balance succeeds
balance_gate_one_below_min_rejects balance < min_balance � InsufficientDeveloperBalance
init_requires_auth init rejects unauthenticated callers
register_offering_requires_caller_auth register_offering rejects unauthenticated callers
register_offering_with_gate_requires_caller_auth register_offering_with_gate rejects unauthenticated callers
registered_count_does_not_require_auth Read-only; no auth needed
is_offering_registered_does_not_require_auth Read-only; no auth needed
registered_count_before_init_returns_not_initialized Pre-init query � NotInitialized
duplicate_offering_registration_rejected Duplicate � OfferingAlreadyRegistered, count unchanged
non_admin_register_offering_returns_unauthorized Non-admin caller � Unauthorized

contracts/registry/tests/xcontract.rs

  • Fix method name try_register_offering_with_balance_gate â�� try_register_offering_with_gate
  • Fix error matching pattern Ok(Err(...)) â�� Err(Ok(...)) to match correct Soroban try_* return type

Cargo.toml

  • Add contracts/registry and contracts/hot to workspace members

Test Results

running 2 unit tests � ok
running 15 overflow_safe tests � ok
running 7 xcontract tests � ok
Total: 24/24 passing

Overflow Safety Audit

Operation Location Safety mechanism
Count increment lib.rs:137,203 checked_add(1).ok_or(RegistryError::Overflow)?
Count read lib.rs:132,198,234 .ok_or(RegistryError::NotInitialized)? (no unwrap_or)
Balance comparison lib.rs:176 i128 comparison, no arithmetic
Length checks lib.rs:77,84 u32 comparison, no arithmetic

Checklist

  • Overflow-safe math; no unwrap() in production paths
  • require_auth on every state-changing entrypoint
  • 24 tests passing (unit + integration)
  • NatSpec-style /// rustdoc on all public functions
  • No new public entrypoints introduced

Closes #746

Replace all raw arithmetic in the Callora Registry contract with
overflow-safe checked operations and eliminate unwrap_or() from
production code paths.

## Changes

### contracts/registry/src/lib.rs
- Replace `.unwrap_or(0)` on RegisteredCount reads in
  register_offering(), register_offering_with_gate(), and
  registered_count() with `.ok_or(RegistryError::NotInitialized)?`.
  This removes silent fallback-to-zero masking of potential
  initialization bugs and aligns with the "no unwrap() in production
  paths" guideline.
- The existing `checked_add(1).ok_or(RegistryError::Overflow)?`
  pattern on the count increment is preserved (was already correct).

### contracts/registry/tests/overflow_safe.rs (new)
Add 15 focused tests covering:
- Overflow at u32::MAX returns RegistryError::Overflow on both
  register_offering and register_offering_with_gate paths
- Overflow does not persist partial offering records
- Count increments correctly through normal registrations
- Balance-gate exact-match and one-below-min boundary tests
- require_auth enforcement on all state-changing entrypoints
  (init, register_offering, register_offering_with_gate)
- Read-only entrypoints (registered_count, is_offering_registered)
  do not require auth
- NotInitialized error when reading count before init
- Duplicate registration rejection (no double count)
- Unauthorized caller rejection

### contracts/registry/tests/xcontract.rs
- Fix method name from try_register_offering_with_balance_gate to
  try_register_offering_with_gate (matches the actual contract method)
- Fix error matching pattern from Ok(Err(...)) to Err(Ok(...))
  to match the correct Soroban try_* return type

### Cargo.toml
- Add contracts/registry and contracts/hot to workspace members
  (hot was already in default-members but missing from members)

Closes CalloraOrg#746
@drips-wave

drips-wave Bot commented Jul 28, 2026

Copy link
Copy Markdown

@Paranoa-dev Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@greatest0fallt1me
greatest0fallt1me merged commit d5cc7d7 into CalloraOrg:main Jul 28, 2026
1 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add overflow-safe math sweep in registry

2 participants