Overview
Manual resolution provides a governance failsafe for resolving markets when the Optimistic Oracle cannot or should not be used. This mechanism includes a mandatory safety period to prevent hasty administrative actions.When to Use Manual Resolution
Manual resolution should be considered in these scenarios:- Oracle Failure: The Optimistic Oracle malfunctions or becomes unavailable
- Incorrect Oracle Price: A clearly wrong price settles despite the dispute mechanism
- Market Emergency: Critical issues require immediate intervention
- Governance Decision: Community votes to override the oracle result
- Multiple Disputes: After repeated disputes, automated resolution is failing
- Ancillary Data Issues: Question was improperly formatted or ambiguous
The Manual Resolution Process
Step 1: Flag the Market
An admin must first flag the market for manual resolution:UmaCtfAdapter.sol:209-218):
- Question must be initialized
- Question must not already be flagged
- Question must not be resolved
- Sets
manualResolutionTimestampto current time + 1 hour (SAFETY_PERIOD) - Automatically pauses the market (
paused = true) - Emits
QuestionFlaggedevent
- Market cannot be resolved via
resolve()(will revert withPaused) - Market is “locked” for the safety period
- Manual resolution becomes possible after the safety period expires
Step 2: Wait for Safety Period
Safety Period Duration:1 hour (defined as SAFETY_PERIOD constant at line 38)
Purpose:
- Prevents immediate manual resolution
- Provides time for community review and discussion
- Allows for unflagging if the flag was applied in error
- Reduces risk of hasty or malicious admin actions
- Market remains paused
- No automatic resolution possible
- Admin can still unflag the market (reverting the flag)
- Users can review the situation and prepare for manual resolution
Step 3: Manual Resolution
After the safety period expires, an admin can manually resolve the market:UmaCtfAdapter.sol:256-262):
- Payouts must be a valid payout array
- Question must be initialized
- Question must be flagged (
manualResolutionTimestamp > 0) - Current time must be after
manualResolutionTimestamp
- Validate payouts: Checks
_isValidPayoutArray(payouts)at line 259 - Mark as resolved: Sets
questionData.resolved = true - Handle refunds: If
refund == true, returns reward to creator - Report payouts: Calls
ctf.reportPayouts(questionID, payouts)to finalize on CTF - Emit event: Emits
QuestionManuallyResolved(questionID, payouts)
Payout Array Validation
Thepayouts parameter must follow specific rules:
Binary Market Payouts (2 outcomes):
- Array length must be exactly 2
- Valid patterns:
[1, 0]- YES outcome (first position pays out)[0, 1]- NO outcome (second position pays out)[1, 1]- TIE/UNKNOWN (both positions pay out 50/50)
NegRiskOperator, tie [1, 1] is not a valid outcome.
Validation is performed by PayoutHelperLib.isValidPayoutArray() - see line 487.
Unflagging (Reverting a Flag)
If a market was flagged in error, it can be unflagged before the safety period expires:UmaCtfAdapter.sol:224-230):
- Question must be initialized
- Question must be flagged (
manualResolutionTimestamp > 0) - Question must not be resolved
- Current time must be before
manualResolutionTimestamp(safety period not passed)
- Clears
manualResolutionTimestamp(sets to 0) - Unpauses the market (
paused = false) - Emits
QuestionUnflaggedevent
Safety Period Mechanics
Constant Definition
UmaCtfAdapter.sol:38. This is a constant and cannot be changed after deployment.
Timestamp Calculation
When a market is flagged:- Market flagged at:
1646064000(Unix timestamp) - Safety period:
3600seconds (1 hour) - Manual resolution allowed at:
1646067600
Enforcement
Before safety period (unflag allowed):
resolveManually allowed):
State Transitions
Events
QuestionFlagged
QuestionUnflagged
QuestionManuallyResolved
Example: Complete Manual Resolution Flow
Scenario
A market has an obviously incorrect oracle price that settled. The community wants manual resolution.Steps
-
Flag the market (timestamp: T+0)
- Market is paused immediately
manualResolutionTimestampset to T+1hQuestionFlaggedevent emitted
-
Community review (T+0 to T+1h)
- Governance discusses correct outcome
- If error detected, admin can
unflag()before T+1h - Prepare correct payout array
-
Safety period expires (T+1h)
unflag()no longer possibleresolveManually()becomes available
-
Manual resolution (T+1h or later)
- Market is marked
resolved = true - Payouts reported to CTF
QuestionManuallyResolvedevent emitted- Users can now redeem positions
- Market is marked
Best Practices
- Document the reason: Always document why manual resolution is needed
- Community consensus: Seek community input during the safety period
- Verify payouts: Triple-check the payout array before calling
resolveManually() - Monitor refunds: Check if
refund == trueto ensure creators get rewards back - Use unflag judiciously: If you flag by mistake, unflag immediately (within 1 hour)
- Consider the safety period: Plan for the 1-hour delay in time-sensitive situations
- Emit reasoning: Consider posting reasoning on-chain or to IPFS for transparency
Security Considerations
Admin Trust
Manual resolution requires trusted admins. Ensure:- Multi-sig or governance-controlled admin keys
- Clear admin action policies and procedures
- Public logging of all manual resolutions
Safety Period Protection
The 1-hour delay protects against:- Hasty decisions
- Single-point-of-failure admin compromise
- Fat-finger errors
Irreversibility
OnceresolveManually() is called:
- Market is permanently resolved
- No way to reverse or correct errors
- Payouts are immediately final on the CTF
Code References
- flag():
UmaCtfAdapter.sol:209 - unflag():
UmaCtfAdapter.sol:224 - resolveManually():
UmaCtfAdapter.sol:256 - SAFETY_PERIOD constant:
UmaCtfAdapter.sol:38 - _isFlagged():
UmaCtfAdapter.sol:451 - Payout validation:
UmaCtfAdapter.sol:486