From 98783aa34e977ca783df9d6429080c5fa424fc33 Mon Sep 17 00:00:00 2001 From: bamiebot Date: Fri, 24 Apr 2026 22:42:02 +0100 Subject: [PATCH] refactor: extract shared authorization and storage helpers across onchain contracts --- .../contracts/auction_contract/src/indexed.rs | 6 +- onchain/shared/src/lib.rs | 82 ++++++++++++++++++- 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/onchain/contracts/auction_contract/src/indexed.rs b/onchain/contracts/auction_contract/src/indexed.rs index 9b13e6ce..96f5e7d6 100644 --- a/onchain/contracts/auction_contract/src/indexed.rs +++ b/onchain/contracts/auction_contract/src/indexed.rs @@ -69,10 +69,8 @@ pub fn place_bid( if amount < min_bid { return Err(errors::AuctionError::BidTooLow); } - } else { - if amount < highest_bid + min_increment { - return Err(errors::AuctionError::BidTooLow); - } + } else if amount < highest_bid + min_increment { + return Err(errors::AuctionError::BidTooLow); } let asset = storage::auction_get_asset(env, id)?; let token = soroban_sdk::token::Client::new(env, &asset); diff --git a/onchain/shared/src/lib.rs b/onchain/shared/src/lib.rs index bdd6dc13..ee6496c5 100644 --- a/onchain/shared/src/lib.rs +++ b/onchain/shared/src/lib.rs @@ -1,3 +1,79 @@ -#![no_std] - -pub mod errors; +#![no_std] + +pub mod errors; + +use soroban_sdk::{panic_with_error, Env}; + +// ─── Authorization Helpers ────────────────────────────────────────────────── + +/// Unwraps an `Option` stored in contract storage, panicking with a contract +/// error if the value is absent. +/// +/// # Arguments +/// * `env` – The current Soroban environment. +/// * `opt` – The `Option` to unwrap. +/// * `error` – A `#[contracterror]` value to panic with if `opt` is `None`. +/// +/// # Example +/// ```ignore +/// let addr = get_or_panic(&env, get_auction_contract(&env), FactoryError::Unauthorized); +/// ``` +#[inline] +pub fn get_or_panic(env: &Env, opt: Option, error: E) -> T +where + E: Into + Copy, +{ + match opt { + Some(v) => v, + None => panic_with_error!(env, error), + } +} + +/// Asserts an `Option` is `None`, panicking with a contract error if a value +/// already exists. Useful for "must not already be registered" guards. +/// +/// # Arguments +/// * `env` – The current Soroban environment. +/// * `opt` – The `Option` to check. +/// * `error` – A `#[contracterror]` value to panic with if `opt` is `Some`. +#[inline] +pub fn assert_none_or_panic(env: &Env, opt: Option, error: E) +where + E: Into + Copy, +{ + if opt.is_some() { + panic_with_error!(env, error); + } +} + +// ─── TTL / Timestamp Helpers ───────────────────────────────────────────────── + +/// Returns `true` if `release_at` is strictly in the future relative to the +/// current ledger timestamp. +#[inline] +pub fn is_future_timestamp(env: &Env, release_at: u64) -> bool { + release_at > env.ledger().timestamp() +} + +// ─── Counter Helpers ───────────────────────────────────────────────────────── + +/// Reads the current `u32` value at `key` from instance storage (defaulting to +/// 0), increments it by 1, stores the new value, and **returns the old value** +/// as the allocated ID. +/// +/// Returns `Err(overflow_error)` if the counter would overflow `u32::MAX`. +/// +/// Callers supply a concrete `#[contracterror]` variant so the helper stays +/// generic and avoids coupling to any particular contract's error enum. +#[inline] +pub fn increment_instance_counter(env: &Env, key: &K, overflow_error: E) -> Result +where + K: soroban_sdk::TryFromVal + + soroban_sdk::IntoVal, + E: Copy, +{ + let id: u32 = env.storage().instance().get(key).unwrap_or(0); + let next = id.checked_add(1).ok_or(overflow_error)?; + env.storage().instance().set(key, &next); + Ok(id) +}