Skip to content

fix(contracts): enforce terminal-state invariants in resolve_market and unlock_tokens, remove fee-admin key landmine - #1244

Open
vitalis200 wants to merge 1 commit into
solutions-plug:mainfrom
vitalis200:clippy
Open

fix(contracts): enforce terminal-state invariants in resolve_market and unlock_tokens, remove fee-admin key landmine#1244
vitalis200 wants to merge 1 commit into
solutions-plug:mainfrom
vitalis200:clippy

Conversation

@vitalis200

Copy link
Copy Markdown
Contributor

Body:

Summary

Fixes three related contract-safety issues in contracts/predict-iq:

closes #1186disputes::resolve_market (the admin override, called from lib.rs::resolve_market) had no guard against re-resolving an already-Resolved or Cancelled market. Per INVARIANTS.md §3, those states are terminal "at all times"; without the guard, an admin could call this path twice with different outcomes after bettors had already claimed under the first outcome, allowing overpayment against an unchanged total_staked/outcome_stakes.
closes #1192voting::unlock_tokens hard-required MarketStatus::Resolved, but a Disputed market can also terminate via community-voted cancel_market_voteCancelled. Voters who locked governance tokens through cast_vote's fallback path (used when the governance token doesn't support balance_at) had no way to recover them if the market was later cancelled instead of resolved.
closes #1195** — admin::set_fee_admin/get_fee_admin read and wrote ConfigKey::GuardianAccount — the same key set_guardian/get_guardian use — instead of the dedicated ConfigKey::FeeAdmin that the real, wired-up flow (fees::set_fee_admin/get_fee_admin) correctly uses. The functions were dead code with no callers, but calling them would have silently overwritten the guardian address that gates pause/unpause/emergency governance. Removed rather than repointed, since fees::set_fee_admin already implements this correctly and is the one exposed via lib.rs.
closes #1193

Changes

  • modules/disputes.rs: resolve_market now rejects with ErrorCode::CannotChangeOutcome if market.status is Resolved or Cancelled, matching the identical guard already used in cancellation::cancel_market_admin and resolution::finalize_resolution.
  • modules/voting.rs: unlock_tokens now accepts Resolved or Cancelled as valid terminal states.
  • modules/admin.rs: removed the dead, miskeyed set_fee_admin/get_fee_admin functions.
  • test.rs / modules/voting.rs / modules/admin.rs: added regression tests for all three fixes.

Test plan

  • cd contracts/predict-iq && cargo test disputes
  • cd contracts/predict-iq && cargo test voting
  • cd contracts/predict-iq && cargo test admin
  • cd contracts/predict-iq && cargo clippy --all-targets --all-features -- -D warnings
  • cd contracts/predict-iq && cargo build --release

Note: these commands could not be run to completion in the dev environment used to prepare this PR — main currently has ~27 pre-existing compile errors in unrelated production code (e.g. a missing `CANCEL_OUTCOME_INDEX

@drips-wave

drips-wave Bot commented Jul 27, 2026

Copy link
Copy Markdown

@vitalis200 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! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment