Skip to main content

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:

  1. Polymarket marks the market as "resolved" in its API
  2. The winning outcome's shares become redeemable for $1.00 each through the CTF contract
  3. 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:

  1. Verifies the oracle's signature on the resolution data
  2. Verifies the resolution data is fresh (within 1 hour)
  3. Records whether the token won or lost in the contract's storage
  4. 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:

  1. Verifies the token has been marked as a winner via resolveMarket()
  2. Calculates the total collateral held for this token across all borrowers
  3. Calls CTF.redeemPositions() to convert the ERC-1155 shares into USDC
  4. The USDC received is held in the contract's balance
  5. 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:

  1. Calculates the USDC proceeds for this specific borrower based on their share of the total collateral
  2. Repays the borrower's outstanding debt (principal + accrued interest) from the proceeds
  3. Sends any surplus USDC to the borrower
  4. Deletes the position from the contract's storage
  5. 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:

  1. Verifies the token has been marked as a loser via resolveMarket()
  2. Calculates the borrower's outstanding debt
  3. Since the collateral is worthless, the entire debt becomes bad debt
  4. The bad debt is absorbed by the lending pool (reducing totalBorrowAssets without a corresponding USDC inflow)
  5. The position is deleted
  6. 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:

  1. 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.

  2. 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.

  3. Depth-gated borrow caps: Limits total borrowing against any single token, capping the maximum bad debt exposure from any one market.

  4. 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:

  1. The price starts dropping (e.g., from $0.60 to $0.40)
  2. PredMart's liquidation engine triggers at each position's liquidation threshold
  3. Collateral is seized and sold while it still has value
  4. 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

  1. Detection: Identifies resolved markets through WebSocket events and REST polling
  2. 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.
  3. On-chain resolution: Calls resolveMarket() to register the resolution on the contract
  4. Winner processing: Calls redeemWonCollateral() and settleRedemption() for winning tokens
  5. Loser processing: Calls closeResolvedPosition() for losing tokens
  6. Tracking: Records resolved markets in the ResolvedMarket database 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

StepWhenWhat Happens
1Market resolvesPolymarket determines the outcome
2Within 60sPredMart detects the resolution via WebSocket or REST polling
3Within 2 minBackend calls resolveMarket() on-chain with oracle-signed data
4Within 5 minFor winners: redeemWonCollateral() is called to convert shares to USDC
5Within 5 minFor each winner: settleRedemption() repays debt and sends surplus
6Within 5 minFor each loser: closeResolvedPosition() writes off bad debt
7OngoingLendingEvent 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

  1. 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.

  2. 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.

  3. Liquidation usually happens before resolution: In most cases, the price drops gradually enough that positions are liquidated before formal resolution, minimizing bad debt.

  4. PredMart processes everything automatically: You don't need to manually redeem winning shares or close losing positions — the resolution monitor handles it.

  5. 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