diff --git a/contract/common/src/lib.rs b/contract/common/src/lib.rs index c3ccbdb2..57bb4fec 100644 --- a/contract/common/src/lib.rs +++ b/contract/common/src/lib.rs @@ -37,6 +37,20 @@ pub enum CommonError { /// Common result type for contract operations pub type ContractResult = Result; +/// Fixed-point precision factor used for reward calculations across the workspace. +/// +/// All per-token reward arithmetic must be scaled by this factor to preserve +/// sub-unit precision with integer arithmetic. The value 1_000_000_000 +/// (1e9) provides nanosecond-scale granularity for token amounts expressed +/// in the smallest on-chain unit. +/// +/// # Usage +/// ```rust +/// use gathera_common::PRECISION; +/// let scaled = amount * PRECISION / total; +/// ``` +pub const PRECISION: i128 = 1_000_000_000; + /// Validation utilities pub struct ValidationUtils; impl ValidationUtils { diff --git a/contract/contracts/src/cross_chain.rs b/contract/contracts/src/cross_chain.rs index ee752eb6..d1adacb8 100644 --- a/contract/contracts/src/cross_chain.rs +++ b/contract/contracts/src/cross_chain.rs @@ -6,7 +6,8 @@ use crate::types::{Config, DataKey, Tier, UserInfo, ChainConfig, CrossChainMessa #[contract] pub struct CrossChainStakingContract; -pub(crate) const PRECISION: i128 = 1_000_000_000; +/// Re-exported from `gathera_common` for backward compatibility within this module. +use gathera_common::PRECISION; /// Reentrancy guard key const REENTRANCY_GUARD: Symbol = symbol_short!("reentrant"); diff --git a/contract/contracts/src/storage.rs b/contract/contracts/src/storage.rs index b01035c3..96d47223 100644 --- a/contract/contracts/src/storage.rs +++ b/contract/contracts/src/storage.rs @@ -1,6 +1,6 @@ use crate::types::{Config, DataKey, Tier, UserInfo, ChainConfig, CrossChainMessage}; - +use gathera_common::PRECISION; use soroban_sdk::{Address, Env, Vec, token}; const TTL_INSTANCE: u32 = 17280 * 30; // 30 days @@ -232,14 +232,14 @@ pub fn update_reward(env: &Env, user: Option<&Address>) { let total_shares = read_total_shares(env); if total_shares > 0 { - let reward_per_token = (config.reward_rate * crate::cross_chain::PRECISION) / total_shares; + let reward_per_token = (config.reward_rate * PRECISION) / total_shares; let mut reward_per_token_stored = read_reward_per_token_stored(env); reward_per_token_stored += reward_per_token; write_reward_per_token_stored(env, reward_per_token_stored); if let Some(user_addr) = user { if let Some(mut user_info) = read_user_info(env, user_addr) { - let rewards = (user_info.shares * reward_per_token_stored) / crate::cross_chain::PRECISION + let rewards = (user_info.shares * reward_per_token_stored) / PRECISION - user_info.reward_per_token_paid; user_info.rewards += rewards; user_info.reward_per_token_paid = reward_per_token_stored;