Claiming Winnings
Guide for claiming winnings from resolved prediction markets using the Python SDK. All claiming operations are gasless — no native tokens required.
Prerequisites
You need a Level 2 client (private key + API credentials):
import os
from dotenv import load_dotenv
from turbine_client import TurbineClient
load_dotenv()
client = TurbineClient(
host=os.environ["TURBINE_HOST"],
chain_id=int(os.environ.get("CHAIN_ID", "137")),
private_key=os.environ["TURBINE_PRIVATE_KEY"],
api_key_id=os.environ["TURBINE_API_KEY_ID"],
api_private_key=os.environ["TURBINE_API_PRIVATE_KEY"],
)How Claiming Works
- Market resolution — When a market resolves, the winning outcome (YES or NO) is determined by the UMA oracle.
- Redeem winning tokens — Holders of the winning token can redeem each token for $1 USDC. Losing tokens become worthless.
- Gasless claim via SDK — The SDK signs an EIP-712 RedeemPositions permit and submits it to the relayer. No native gas is needed.
Check Resolution Status
Before claiming, verify the market is resolved:
market_id = "0x..."
resolution = client.get_resolution(market_id)
print(f"Resolved: {resolution.resolved}")
if resolution.resolved:
outcome = "YES" if resolution.outcome == 0 else "NO"
print(f"Winner: {outcome}")
print(f"Assertion ID: {resolution.assertion_id}")Claim from a Single Market
claim_winnings() takes the market's contract address (not the market ID). You can find it from the Market object:
# Get the market to find the contract address
markets = client.get_markets()
market = next(m for m in markets if m.id == market_id)
# Claim winnings
try:
result = client.claim_winnings(
market_contract_address=market.contract_address
)
print(f"Claim submitted: {result}")
except ValueError as e:
print(f"Cannot claim: {e}")The method performs these steps internally:
- Query on-chain — Queries the market contract on-chain for resolution status and condition data.
- Check balance — Checks your balance of the winning token.
- Sign permit — Signs an EIP-712 RedeemPositions permit.
- Submit to relayer — Submits to the relayer for gasless execution.
It raises ValueError if:
- The market is not resolved yet
- You hold no winning tokens
Batch Claim from Multiple Markets
Claim winnings from several resolved markets in a single batch transaction:
contract_addresses = [
"0xMarket1ContractAddress...",
"0xMarket2ContractAddress...",
"0xMarket3ContractAddress...",
]
try:
result = client.batch_claim_winnings(contract_addresses)
print(f"Batch claim submitted: {result}")
except ValueError as e:
print(f"No markets to claim: {e}")Markets that are not resolved or where you have no winning tokens are skipped automatically. The method only raises ValueError if none of the markets have claimable winnings.
Find Markets with Claimable Winnings
Scan your positions for resolved markets you can claim from:
# Get all your positions
positions = client.get_user_positions(
address=client.address,
chain_id=client.chain_id,
)
# Get markets and check which are resolved
markets = client.get_markets(chain_id=client.chain_id)
market_map = {m.id: m for m in markets}
claimable = []
for pos in positions:
market = market_map.get(pos.market_id)
if not market or not market.resolved:
continue
# Check if we hold winning tokens
if market.winning_outcome == 0 and pos.yes_shares > 0:
claimable.append(market)
print(f"Claimable: {market.question}")
print(f" YES shares: {pos.yes_shares / 1e6:.2f} (payout: ${pos.yes_shares / 1e6:.2f} USDC)")
elif market.winning_outcome == 1 and pos.no_shares > 0:
claimable.append(market)
print(f"Claimable: {market.question}")
print(f" NO shares: {pos.no_shares / 1e6:.2f} (payout: ${pos.no_shares / 1e6:.2f} USDC)")
# Batch claim all
if claimable:
addresses = [m.contract_address for m in claimable]
result = client.batch_claim_winnings(addresses)
print(f"\nBatch claim submitted: {result}")
else:
print("No claimable winnings found.")Monitor Claim Status
After submitting a claim, track its progress:
# Check pending claims
pending = client.get_pending_claims()
for c in pending:
print(f"Pending: market={c.market_address} payout={c.payout / 1e6:.2f} USDC tx={c.tx_hash}")
# Check failed claims
failed = client.get_failed_claims()
for c in failed:
print(f"Failed: market={c.market_address} payout={c.payout / 1e6:.2f} USDC tx={c.tx_hash}")CLAIM_ONLY_MODE
The reference bot (examples/price_action_bot.py) supports a claim-only mode that disables trading and only claims winnings from previously traded markets:
CLAIM_ONLY_MODE=true TURBINE_PRIVATE_KEY=0x... python examples/price_action_bot.pyThis is useful when you want to:
- Claim winnings without placing new orders
- Clean up positions from a previous trading session
- Run a background process that periodically claims resolved markets
Complete Example
A standalone script that discovers and claims all available winnings:
import os
import time
from dotenv import load_dotenv
from turbine_client import TurbineClient
load_dotenv()
client = TurbineClient(
host=os.environ.get("TURBINE_HOST", "https://api.turbinefi.com"),
chain_id=int(os.environ.get("CHAIN_ID", "137")),
private_key=os.environ["TURBINE_PRIVATE_KEY"],
api_key_id=os.environ["TURBINE_API_KEY_ID"],
api_private_key=os.environ["TURBINE_API_PRIVATE_KEY"],
)
print(f"Wallet: {client.address}")
print(f"Chain: {client.chain_id}")
# Get positions and markets
positions = client.get_user_positions(address=client.address, chain_id=client.chain_id)
markets = client.get_markets(chain_id=client.chain_id)
market_map = {m.id: m for m in markets}
print(f"Found {len(positions)} positions across {len(markets)} markets\n")
# Find claimable markets
to_claim = []
total_payout = 0
for pos in positions:
market = market_map.get(pos.market_id)
if not market or not market.resolved:
continue
winning_shares = 0
if market.winning_outcome == 0:
winning_shares = pos.yes_shares
elif market.winning_outcome == 1:
winning_shares = pos.no_shares
if winning_shares > 0:
to_claim.append(market.contract_address)
total_payout += winning_shares
outcome = "YES" if market.winning_outcome == 0 else "NO"
print(f" {market.question}")
print(f" Winner: {outcome} | Your payout: ${winning_shares / 1e6:.2f} USDC")
if not to_claim:
print("No claimable winnings found.")
exit(0)
print(f"\nTotal payout: ${total_payout / 1e6:.2f} USDC from {len(to_claim)} markets")
# Claim all
if len(to_claim) == 1:
result = client.claim_winnings(to_claim[0])
else:
result = client.batch_claim_winnings(to_claim)
print(f"Claim submitted: {result}")
# Wait for confirmation
print("Checking claim status...")
time.sleep(10)
pending = client.get_pending_claims()
failed = client.get_failed_claims()
print(f"Pending: {len(pending)}")
print(f"Failed: {len(failed)}")
for f in failed:
print(f" FAILED: {f.market_address} — tx={f.tx_hash}")