Market Resolution
Every Polymarket market eventually reaches a conclusion — the event either happens or it doesn't, and the market "resolves." When this occurs, the outcome shares that were used as collateral on PredMart must be processed. Winning shares can be redeemed for $1.00 USDC each, while losing shares become worthless. PredMart handles both scenarios automatically through its market resolution system.
This page explains the complete resolution process: how PredMart detects resolved markets, what happens to positions backed by winning and losing shares, how redemption works, and how bad debt from losing positions is managed.
How Markets Resolve on Polymarket
The Resolution Process
When a real-world event occurs (or fails to occur by its deadline), Polymarket's resolution committee determines the outcome. This is done through Polymarket's oracle system — typically involving UMA's optimistic oracle or a designated resolution source.
Once the outcome is determined:
- Polymarket marks the market as "resolved" in its API
- The winning outcome's shares become redeemable for $1.00 each through the CTF contract
- The losing outcome's shares become worthless ($0.00)
Binary Markets
For binary markets (Yes/No), exactly one outcome wins. If "Yes" wins, Yes shares are redeemable for $1.00 and No shares are worth $0.00, and vice versa.
Multi-Outcome Markets
For multi-outcome markets (e.g., "Which team will win?"), the winning outcome's shares are redeemable for $1.00, and all other outcomes' shares become worthless.
How PredMart Detects Resolutions
PredMart uses two complementary systems to detect market resolutions:
1. WebSocket Detection (Primary)
PredMart's WebSocket connection to Polymarket's CLOB can detect resolution-related price changes. When a market resolves, the price typically jumps to $1.00 (winning) or $0.00 (losing). The resolution monitor watches for these extreme price movements and flags them.
2. Gamma API Polling (Fallback)
A Celery task (resolution_fallback) runs every 60 seconds and polls Polymarket's Gamma API to check for newly resolved markets. When a resolved market is detected that has active PredMart positions, the system initiates the resolution flow.
Oracle-Signed Resolution Data
To process a resolution on-chain, PredMart's backend provides oracle-signed resolution data to the smart contract. This data includes:
- The token ID
- Whether the token won or lost
- A timestamp
- The oracle's cryptographic signature
The contract verifies that the resolution data is valid, signed by the authorized oracle, and not older than 1 hour (MAX_RESOLUTION_AGE = 3600 seconds).
Resolving a Market On-Chain
Anyone can call the resolveMarket(tokenId, resolutionData) function on the smart contract to formally register that a market has resolved. The function:
- Verifies the oracle's signature on the resolution data
- Verifies the resolution data is fresh (within 1 hour)
- Records whether the token won or lost in the contract's storage
- Emits a
MarketResolvedEvent(tokenId, won)event
Once a market is resolved on-chain, the contract knows whether each token is a winner or loser, and the appropriate position handling can proceed.
Won Markets: Redemption Flow
When a market resolves in favor of the collateral token (the outcome occurred), the shares are "winners" and can be redeemed for $1.00 USDC each through Polymarket's CTF contract.
Step 1: Redeem Collateral
Anyone can call redeemWonCollateral(tokenId, conditionId, indexSet) on PredMart's contract. This function:
- Verifies the token has been marked as a winner via
resolveMarket() - Calculates the total collateral held for this token across all borrowers
- Calls
CTF.redeemPositions()to convert the ERC-1155 shares into USDC - The USDC received is held in the contract's balance
- Emits a
CollateralRedeemed(tokenId, sharesRedeemed, usdcReceived)event
Step 2: Settle Individual Positions
After the collateral is redeemed, each borrower's position must be individually settled. Anyone can call settleRedemption(borrower, tokenId) for each affected borrower. This function:
- Calculates the USDC proceeds for this specific borrower based on their share of the total collateral
- Repays the borrower's outstanding debt (principal + accrued interest) from the proceeds
- Sends any surplus USDC to the borrower
- Deletes the position from the contract's storage
- Emits a
RedemptionSettled(borrower, tokenId, debtRepaid, surplusToUser)event
Example: Winning Market Resolution
Before resolution:
- Alice has 5,000 shares of Token X deposited as collateral
- Alice's outstanding debt: $2,500 (including accrued interest)
- Token X resolves as the winning outcome
After redemption and settlement:
- 5,000 shares are redeemed for 5,000 × $1.00 = $5,000 USDC
- Alice's debt of $2,500 is repaid to the pool
- Alice receives the surplus: $5,000 - $2,500 = $2,500 USDC
- Alice's position is closed
This is a positive outcome for Alice — her collateral was worth $5,000, her debt was only $2,500, and she receives the $2,500 difference.
What If the Borrower Has No Debt?
If a borrower deposited collateral but never borrowed (or already repaid all their debt), the entire redemption proceeds go to the borrower:
- 5,000 shares redeemed for $5,000 USDC
- Debt: $0
- Surplus to borrower: $5,000
Lost Markets: Bad Debt Handling
When a market resolves against the collateral token (the outcome did not occur), the shares become worthless — $0.00. This is the most significant risk in PredMart's system.
Closing Lost Positions
For positions backed by losing tokens, the function closeResolvedPosition(borrower, tokenId) is called. This function:
- Verifies the token has been marked as a loser via
resolveMarket() - Calculates the borrower's outstanding debt
- Since the collateral is worthless, the entire debt becomes bad debt
- The bad debt is absorbed by the lending pool (reducing
totalBorrowAssetswithout a corresponding USDC inflow) - The position is deleted
- Emits a
PositionClosed(borrower, tokenId, badDebt)event
Impact of Bad Debt on Lenders
When bad debt is absorbed:
Total Borrow Assets -= Debt Amount (debt is written off)
(but no USDC is added to the pool)
This means totalAssets decreases by the bad debt amount. Since pUSDC share value is based on totalAssets / totalPUSDCSupply, all pUSDC shares lose a proportional amount of value.
Example:
- Pool has $1,000,000 in total assets
- A market resolution creates $10,000 in bad debt
- Total assets drop to $990,000
- All lenders experience a 1% loss on their position value
Mitigating Bad Debt Risk
PredMart employs several mechanisms to minimize bad debt from market resolutions:
-
Low LTV for low-probability outcomes: Shares trading at low prices (indicating the market considers the outcome unlikely) have very low LTVs. A share at $0.10 only has an 8% LTV, meaning very little can be borrowed against it.
-
Real-time liquidation: As a market's price crashes toward $0 (indicating resolution against the outcome), PredMart's liquidation engine intervenes. The liquidation happens before the official resolution, recovering most of the debt through collateral seizure while the shares still have some value.
-
Depth-gated borrow caps: Limits total borrowing against any single token, capping the maximum bad debt exposure from any one market.
-
Pool cap diversification: The 5% per-token cap ensures that even complete loss of one token's value can't destroy more than 5% of the pool.
The Race Between Liquidation and Resolution
In practice, market resolution rarely causes sudden bad debt because the price typically drops to $0 gradually over minutes or hours as news spreads. During this decline:
- The price starts dropping (e.g., from $0.60 to $0.40)
- PredMart's liquidation engine triggers at each position's liquidation threshold
- Collateral is seized and sold while it still has value
- By the time the market formally resolves, most positions have already been liquidated
The risk of bad debt from resolution is highest when:
- The price drops extremely rapidly (within seconds)
- The market is illiquid (making it hard to sell seized collateral)
- Multiple large positions in the same token reach their liquidation threshold simultaneously
Resolution Monitor
PredMart's resolution monitor (resolution_monitor.py) is a dedicated service that manages the resolution process:
Responsibilities
- Detection: Identifies resolved markets through WebSocket events and REST polling
- Immediate token freeze: As the very first action, the monitor calls
setTokenFrozen(tokenId, true)to immediately block any new deposits or borrows against the resolved token. This is the cheapest and fastest defense — it prevents new exposure before the resolution is fully processed on-chain. - On-chain resolution: Calls
resolveMarket()to register the resolution on the contract - Winner processing: Calls
redeemWonCollateral()andsettleRedemption()for winning tokens - Loser processing: Calls
closeResolvedPosition()for losing tokens - Tracking: Records resolved markets in the
ResolvedMarketdatabase table
Resolved Market Database
The ResolvedMarket table tracks:
- Token ID
- Whether the token won or lost
- The condition ID (for redemption)
- The timestamp of resolution
- Whether all positions have been settled
Positions Without Debt on Losing Markets
If a borrower deposited collateral but never borrowed against it, and the market resolves as a loss, the closeResolvedPosition() function still needs to be called to clean up the position. However, since there's no debt, there's no bad debt — the position is simply deleted, and the worthless collateral is discarded.
The borrower loses their shares (which are worth $0 anyway), but no impact on the pool occurs.
Timeline: Market Resolution Processing
| Step | When | What Happens |
|---|---|---|
| 1 | Market resolves | Polymarket determines the outcome |
| 2 | Within 60s | PredMart detects the resolution via WebSocket or REST polling |
| 3 | Within 2 min | Backend calls resolveMarket() on-chain with oracle-signed data |
| 4 | Within 5 min | For winners: redeemWonCollateral() is called to convert shares to USDC |
| 5 | Within 5 min | For each winner: settleRedemption() repays debt and sends surplus |
| 6 | Within 5 min | For each loser: closeResolvedPosition() writes off bad debt |
| 7 | Ongoing | LendingEvent records created for each affected position |
Resolution Events
The following on-chain events are emitted during resolution:
// When a market is formally resolved on the contract
event MarketResolvedEvent(uint256 indexed tokenId, bool won);
// When a losing position is closed and debt written off
event PositionClosed(address indexed borrower, uint256 indexed tokenId, uint256 badDebt);
// When winning collateral is redeemed for USDC
event CollateralRedeemed(uint256 indexed tokenId, uint256 sharesRedeemed, uint256 usdcReceived);
// When a winning position is settled (debt repaid, surplus sent to user)
event RedemptionSettled(
address indexed borrower,
uint256 indexed tokenId,
uint256 debtRepaid,
uint256 surplusToUser
);
Key Takeaways
-
Winning markets are profitable for borrowers: If your collateral wins, you get back $1.00 per share minus your outstanding debt. This is usually a very positive outcome.
-
Losing markets create bad debt: If your collateral loses, your shares are worth $0 and your debt is written off. Lenders absorb the loss proportionally.
-
Liquidation usually happens before resolution: In most cases, the price drops gradually enough that positions are liquidated before formal resolution, minimizing bad debt.
-
PredMart processes everything automatically: You don't need to manually redeem winning shares or close losing positions — the resolution monitor handles it.
-
The pool cap limits worst-case damage: Even if an entire token's borrowers default, the 5% pool cap limits the total bad debt to 5% of pool assets.
Next Steps
- Liquidation — How positions are liquidated before resolution
- Risk Parameters — The LTV curve and health factor system
- Lending — Understanding bad debt risk as a lender
- Protocol Constants — Resolution-related parameters