feat(registry): overflow-safe math sweep and hardened error paths - #825
Merged
greatest0fallt1me merged 1 commit intoJul 28, 2026
Conversation
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
|
@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! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.unwrap_or(0)with.ok_or(RegistryError::NotInitialized)?onRegisteredCountreads inregister_offering(),register_offering_with_gate(), andregistered_count(). This removes silent fallback-to-zero that could mask initialization bugs and aligns with the "no unwrap() in production paths" guideline.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)register_offering_count_overflow_returns_erroru32::MAXcount �RegistryError::Overflowregister_offering_with_gate_count_overflow_returns_erroroverflow_does_not_persist_offering_recordregister_offering_increments_countregister_offering_with_gate_increments_countbalance_gate_exact_match_allows_registrationbalance == min_balancesucceedsbalance_gate_one_below_min_rejectsbalance < min_balance�InsufficientDeveloperBalanceinit_requires_authinitrejects unauthenticated callersregister_offering_requires_caller_authregister_offeringrejects unauthenticated callersregister_offering_with_gate_requires_caller_authregister_offering_with_gaterejects unauthenticated callersregistered_count_does_not_require_authis_offering_registered_does_not_require_authregistered_count_before_init_returns_not_initializedNotInitializedduplicate_offering_registration_rejectedOfferingAlreadyRegistered, count unchangednon_admin_register_offering_returns_unauthorizedUnauthorizedcontracts/registry/tests/xcontract.rstry_register_offering_with_balance_gate�try_register_offering_with_gateOk(Err(...))�Err(Ok(...))to match correct Sorobantry_*return typeCargo.tomlcontracts/registryandcontracts/hotto workspace membersTest Results
Overflow Safety Audit
lib.rs:137,203checked_add(1).ok_or(RegistryError::Overflow)?lib.rs:132,198,234.ok_or(RegistryError::NotInitialized)?(no unwrap_or)lib.rs:176i128comparison, no arithmeticlib.rs:77,84u32comparison, no arithmeticChecklist
unwrap()in production pathsrequire_authon every state-changing entrypoint///rustdoc on all public functionsCloses #746