fix: add settlement timeout and emergency refund for stuck directional positions#4
Open
pplmaverick wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
EventBasedPredictionMarketresolves via UMA's Optimistic Oracle V2, which is a realimprovement over a single-admin-key oracle — anyone can permissionlessly call
proposePrice(), and disputes escalate to the DVM. That part works well.However, there's no fallback if nobody ever proposes a price (e.g. a low-interest
market where the
proposerRewarddoesn't attract a proposer, or the underlying questionbecomes unresolvable). In that case:
receivedSettlementPricestaysfalseforever.settle()reverts indefinitely (require(receivedSettlementPrice, ...)).redeem()only works for holders of matched Long+Short pairs (1:1 burn). Anyoneholding a one-sided directional position — which is the normal outcome of trading
through the AMM — has no exit path at all.
I ran into this while building a live weather prediction market on Arc Testnet
(~55 Arc Testnet transactions across create/lock/settle/claim flows) using a simpler
onlyOracle-gated design, and traced the same failure mode back to this referenceimplementation while evaluating a migration to it.
Fix
settlementDeadline, set toblock timestamp of initializeMarket() + SETTLEMENT_TIMEOUT(
72 hours, currently a fixed constant — open to making this configurable per-market).emergencyRefund(longTokensToRedeem, shortTokensToRedeem): callable by any tokenholder once
settlementDeadlinehas passed with no settlement price received. Pays outat a neutral 0.5/0.5 split per token — the same math the contract already uses for the
OO's "Undetermined" (
5e17) outcome — since the true result was never established.Known limitation / open question for maintainers
priceDisputed()re-requests a price with a fresh timestamp but does not resetsettlementDeadline. If a dispute lands close to the original deadline,emergencyRefund()could theoretically become callable while a legitimate DVM arbitration is still in flight.
I left this as-is and flagged it with a code comment rather than guessing at the right
behavior (extend the deadline on every dispute? cap the number of extensions?) — wanted to
raise it for discussion rather than bake in an assumption.
Also not included yet: unit tests for the new function and the timeout boundary. Happy to
add a test file (mirroring the existing Hardhat/UMA test setup) if the general approach
looks right to maintainers before I invest in test scaffolding.
Testing
Not yet covered by automated tests — see note above. Manually reasoned through the
solvency invariant: before any settlement,
longToken.totalSupply() == shortToken.totalSupply() == collateralToken.balanceOf(address(this))(sincecreate()/redeem()always move bothsides in lockstep), so the 0.5/0.5 split in
emergencyRefund()can't be under-collateralizedin the no-dispute case.