Skip to content
Open
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
59 changes: 54 additions & 5 deletions bindings/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,10 @@ export const ContractError = {
* No pending oracle rotation proposal to accept or cancel
*/
54: {message:"NoPendingRotation"},
/**
* Oracle rotation delay has not elapsed yet (must wait MIN_ROTATION_DELAY_SECONDS)
*/
55: {message:"RotationDelayNotElapsed"},
/**
* Invalid archive retention limit
*/
Expand All @@ -548,20 +552,65 @@ export const ContractError = {
*/
64: {message:"InvalidSalt"},
/**
* Epoch mint budget has been fully consumed
*/
66: {message:"EpochBudgetExceeded"}
* create_next_from_template called with no round template configured
*/
65: {message:"NoRoundTemplate"},
/**
* Oracle payload timestamp is outside the round-relative economic window
*/
66: {message:"OracleTimestampOutsideWindow"},
/**
* Epoch mint budget has been fully consumed
*/
67: {message:"EpochBudgetExceeded"},
/**
* Oracle heartbeat is not live and strict mode blocks settlement (Issue #264)
*/
66: {message:"OracleNotLive"},
68: {message:"OracleNotLive"},
/**
* Invalid precision payout policy
*/
67: {message:"InvalidPayoutPolicy"}
69: {message:"InvalidPayoutPolicy"},
/**
* Stake amount is below the configured minimum bet (dust protection, Issue #269)
*/
70: {message:"BelowMinBet"},
/**
* Multi-feed resolution: fewer observations survived outlier rejection than the configured quorum threshold
*/
71: {message:"InsufficientOracleQuorum"},
/**
* Multi-feed resolution: payload contains fewer observations than the configured minimum
*/
72: {message:"TooFewObservations"},
/**
* Multi-feed resolution: outlier observations would dominate the result
*/
73: {message:"OracleOutlierRejected"},
/**
* Multi-feed payload contains duplicate source identifiers
*/
74: {message:"DuplicateOracleSource"},
/**
* Multi-feed payload has observations that are not sorted or sources are out of expected range
*/
75: {message:"InvalidObservationOrder"},
/**
* The requested data key is not allowed for batch TTL touch operations
*/
76: {message:"UnsupportedDataKeyForTtlTouch"},
/**
* Pending winnings entry does not exist
*/
77: {message:"PendingWinningsNotFound"},
/**
* Pending winnings expiry is not configured (value is 0)
*/
78: {message:"ExpiryNotConfigured"},
/**
* Pending winnings entry exists but has not yet reached the configured expiry threshold
*/
79: {message:"PendingWinningsNotExpired"}
}

/**
Expand Down
7 changes: 5 additions & 2 deletions contracts/src/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1174,9 +1174,9 @@ pub fn _require_supported_schema(env: &Env) -> Result<u32, ContractError> {
/// # Errors
/// - `AdminNotSet` — contract not initialized.
/// - `ContractPaused` — contract is fully paused.
/// - `ExpiryNotConfigured` — pending winnings expiry is disabled (0 or absent).
/// - `PendingWinningsNotFound` — no pending winnings entry for this user.
/// - `PendingWinningsNotExpired` — entry exists but hasn't reached the expiry threshold.
/// - `NoActiveRound` — used as a generic "no pending winnings" signal when
/// the entry doesn't exist or expiry is disabled (0).
pub fn reclaim_expired_pending_winnings(env: Env, user: Address) -> Result<i128, ContractError> {
_require_supported_schema(&env)?;
let admin: Address = env
Expand All @@ -1191,6 +1191,7 @@ pub fn reclaim_expired_pending_winnings(env: Env, user: Address) -> Result<i128,

// Read the expiry config. 0 or absent means expiry is disabled.
let expiry_key = PENDING_WINNINGS_EXPIRY_KEY;
_extend_persistent_ttl(&env, &expiry_key);
let expiry_ledgers: u32 = env
.storage()
.persistent()
Expand All @@ -1208,6 +1209,7 @@ pub fn reclaim_expired_pending_winnings(env: Env, user: Address) -> Result<i128,

// Read pending winnings.
let pending_key = DataKey::PendingWinnings(user.clone());
_extend_persistent_ttl(&env, &pending_key);
let pending: i128 = env.storage().persistent().get(&pending_key).unwrap_or(0);
if pending == 0 {
_emit_action_rejected(
Expand All @@ -1221,6 +1223,7 @@ pub fn reclaim_expired_pending_winnings(env: Env, user: Address) -> Result<i128,

// Read the ledger when this entry was last updated.
let updated_key = PendingWinningsUpdatedAtKey(user.clone());
_extend_persistent_ttl(&env, &updated_key);
let updated_at: u32 = env
.storage()
.persistent()
Expand Down
6 changes: 3 additions & 3 deletions contracts/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@ pub enum ContractError {
NoRoundTemplate = 65,
/// Oracle payload timestamp is outside the round-relative economic window
OracleTimestampOutsideWindow = 66,
/// Pending winnings entry exists but has not yet reached the configured
/// expiry threshold — caller must wait before reclaiming.
PendingWinningsNotExpired = 66,
/// Epoch mint budget has been fully consumed
EpochBudgetExceeded = 67,
/// Oracle heartbeat is not live and strict mode blocks settlement (Issue #264)
Expand Down Expand Up @@ -89,4 +86,7 @@ pub enum ContractError {
PendingWinningsNotFound = 77,
/// Pending winnings expiry is not configured (value is 0).
ExpiryNotConfigured = 78,
/// Pending winnings entry exists but has not yet reached the configured
/// expiry threshold — caller must wait before reclaiming.
PendingWinningsNotExpired = 79,
}
Loading