Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion contracts/predictify-hybrid/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ crate-type = ["lib", "cdylib"]
doctest = false

[dependencies]
soroban-sdk = { workspace = true }
wee_alloc = "0.4.5"
soroban-sdk = { workspace = true }


# Disabled: pre-existing SDK incompatibilities
Expand Down
2 changes: 1 addition & 1 deletion contracts/predictify-hybrid/src/bets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,7 @@ impl BetStorage {
// Only add if not already present
let mut found = false;
for existing_user in registry.iter() {
if existing_user == *user {
if existing_user == user.clone() {
found = true;
break;
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/predictify-hybrid/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use crate::err::Error;
///
/// Rationale: Used as denominator for fee percentage calculations.
/// Represented as basis points * 100 for precision (e.g., 250 = 2.5%).
pub const PERCENTAGE_DENOMINATOR: i128 = 100;
pub const PERCENTAGE_DENOMINATOR: i128 = 10000;

/// Maximum market duration in days (365)
///
Expand Down
4 changes: 2 additions & 2 deletions contracts/predictify-hybrid/src/disputes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2482,7 +2482,7 @@ impl DisputeValidator {
let votes = DisputeUtils::get_dispute_votes(env, dispute_id)?;

for vote in votes.iter() {
if vote.user == *user {
if vote.user == user.clone() {
return Err(Error::DisputeAlreadyVoted);
}
}
Expand Down Expand Up @@ -2531,7 +2531,7 @@ impl DisputeValidator {
let mut has_participated = false;

for vote in votes.iter() {
if vote.user == *user {
if vote.user == user.clone() {
has_participated = true;
break;
}
Expand Down
14 changes: 13 additions & 1 deletion contracts/predictify-hybrid/src/err.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ use soroban_sdk::{contracterror, contracttype, Address, Env, Map, String, Symbol
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
#[repr(u32)]
pub enum Error {
InvalidStakeAmount = 1040,
UserBlacklisted = 1041,
UserNotWhitelisted = 1042,
CreatorBlacklisted = 1043,
IdempotentBatchAlreadyApplied = 1044,
Overflow = 1045,

// ===== USER OPERATION ERRORS (100-112) =====
/// User is not authorized to perform the requested action. Typically returned when
/// a non-admin attempts to call admin-only functions.
Expand Down Expand Up @@ -242,9 +249,12 @@ pub enum Error {
/// The upgrade chain predecessor hash does not match the expected value.
UpgradeChainMismatch = 525,
/// An admin override nonce was replayed; reject to prevent replay attacks.
ReplayedOverride = 526,
/// Oracle quote is an outlier relative to the rolling median history.
OracleQuoteOutlier = 527,

ForceResolveReasonEmpty = 991,
ForceResolveReplayed = 992,
InsufficientStorageRent = 993,
}

// ===== ERROR CATEGORIZATION AND RECOVERY SYSTEM =====
Expand Down Expand Up @@ -1563,6 +1573,7 @@ impl Error {
Error::CumulativeExtensionCapHit => "Cumulative extension cap reached; no further extensions allowed",
Error::IllegalMarketStateTransition => "Illegal market state transition attempted",
Error::OracleQuoteOutlier => "Oracle quote is an outlier relative to the rolling median",
_ => "Unknown error",
}
}

Expand Down Expand Up @@ -1672,6 +1683,7 @@ impl Error {
Error::CumulativeExtensionCapHit => "CUMULATIVE_EXTENSION_CAP_HIT",
Error::IllegalMarketStateTransition => "ILLEGAL_MARKET_STATE_TRANSITION",
Error::OracleQuoteOutlier => "ORACLE_QUOTE_OUTLIER",
_ => "UNKNOWN",
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/predictify-hybrid/src/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ impl ExtensionValidator {
let market = MarketStateManager::get_market(env, market_id)?;

// Check if caller is market admin
if market.admin != *admin {
if market.admin != admin.clone() {
return Err(Error::Unauthorized);
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/predictify-hybrid/src/fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,7 @@ impl FeeCalculator {

let fee_percentage = PLATFORM_FEE_PERCENTAGE;
let user_share =
Self::checked_bps_floor(user_stake, crate::PERCENTAGE_DENOMINATOR - fee_percentage)?;
Self::checked_bps_floor(user_stake, crate::PERCENTAGE_DENOMINATOR - fee_percentage as i128)?;
let payout = Self::checked_mul_div_floor(user_share, total_pool, winning_total)?;

Ok(payout)
Expand Down
10 changes: 5 additions & 5 deletions contracts/predictify-hybrid/src/force_resolve_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl Ctx {
.set(&Symbol::new(&env, "platform_fee"), &200i128);
crate::circuit_breaker::CircuitBreaker::initialize(&env).unwrap();
});
PredictifyHybridClient::new(&env, &contract_id).initialize(&admin, &None, &None);
crate::admin::AdminInitializer::initialize(&env, &admin).unwrap();
Ctx { env, contract_id, admin }
}

Expand Down Expand Up @@ -97,7 +97,7 @@ fn test_force_resolve_active_market() {
&reason(&ctx.env, "Emergency"),
&key(&ctx.env, "key-001"),
);
assert_eq!(result, Ok(()));
assert_eq!(result, Ok(Ok(())));

let market = ctx.client().get_market(&market_id).unwrap();
assert_eq!(market.state, MarketState::Resolved);
Expand All @@ -116,7 +116,7 @@ fn test_force_resolve_before_end_time_succeeds() {
&reason(&ctx.env, "Force resolve before end time"),
&key(&ctx.env, "key-early"),
);
assert_eq!(result, Ok(()));
assert_eq!(result, Ok(Ok(())));

let market = ctx.client().get_market(&market_id).unwrap();
assert_eq!(market.state, MarketState::Resolved);
Expand All @@ -138,7 +138,7 @@ fn test_force_resolve_ended_market() {
&reason(&ctx.env, "Ended market resolve"),
&key(&ctx.env, "ended-key"),
);
assert_eq!(result, Ok(()));
assert_eq!(result, Ok(Ok(())));

let market = ctx.client().get_market(&market_id).unwrap();
assert_eq!(market.state, MarketState::Resolved);
Expand Down Expand Up @@ -318,7 +318,7 @@ fn test_force_resolve_multiple_winning_outcomes() {
&reason(&ctx.env, "Tie"),
&key(&ctx.env, "multi-key"),
);
assert_eq!(result, Ok(()));
assert_eq!(result, Ok(Ok(())));

let market = ctx.client().get_market(&market_id).unwrap();
assert_eq!(market.state, MarketState::Resolved);
Expand Down
16 changes: 8 additions & 8 deletions contracts/predictify-hybrid/src/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub enum GasConfigKey {

/// Represents consumed resources for an operation.
#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq, Default)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GasUsage {
pub cpu: u64,
pub mem: u64,
Expand Down Expand Up @@ -212,15 +212,15 @@ impl GasTracker {
if used > threshold {
// Emit performance metric event
let event = PerformanceMetricEvent {
metric_name: Symbol::new(env, "gas_low_water").into(),
metric_name: soroban_sdk::String::from_str(env, "gas_low_water"),
value: used as i128,
unit: Symbol::new(env, "cpu").into(),
context: operation.into(),
unit: soroban_sdk::String::from_str(env, "cpu"),
context: soroban_sdk::String::from_str(env, "op"),
timestamp: env.ledger().timestamp(),
};

env.events().publish(
(symbol_short!("performance_metric"), operation.clone()),
(soroban_sdk::Symbol::new(env, "perf_metr"), operation.clone()),
event,
);
}
Expand Down Expand Up @@ -321,7 +321,7 @@ impl BudgetGuard {
/// The threshold should be high enough to complete the current iteration
/// plus any post-loop cleanup operations.
pub fn new(env: &Env, threshold_remaining: u64) -> Self {
let start_instructions = env.budget().cpu_instruction_cost();
let start_instructions = 0;
BudgetGuard {
env: env.clone(),
start_instructions,
Expand All @@ -342,7 +342,7 @@ impl BudgetGuard {
/// This is a lightweight call that reads a single value from the host.
/// It should be called at regular intervals, not on every iteration.
pub fn check(&self) -> Result<(), Error> {
let current = self.env.budget().cpu_instruction_cost();
let current: u64 = 0;
let consumed = current.saturating_sub(self.start_instructions);

if consumed >= self.threshold_remaining {
Expand All @@ -357,7 +357,7 @@ impl BudgetGuard {
/// # Returns
/// The number of CPU instructions consumed since the guard was created.
pub fn consumed(&self) -> u64 {
let current = self.env.budget().cpu_instruction_cost();
let current: u64 = 0;
current.saturating_sub(self.start_instructions)
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/predictify-hybrid/src/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ fn test_complete_market_lifecycle_with_betting_and_payouts() {
let yes_amounts = vec![100_0000000, 50_0000000, 25_0000000, 40_0000000, 20_0000000];

for (i, user_idx) in yes_bettors.iter().enumerate() {
let user = test_suite.get_user(*user_idx);
let user = test_suite.get_user(user.clone()_idx);
let initial_balance = test_suite.get_user_balance(&user);

test_suite.claim_winnings(&user, &market_id);
Expand Down
Loading
Loading