Automated DeFi swaps triggered by prediction market outcomes on Polygon
PolySwap is a decentralized application that enables users to create conditional swap orders that execute automatically when specific prediction market outcomes are resolved. Built on top of CoW Swap's conditional order framework, PolySwap bridges the gap between prediction markets and DeFi trading.
PolySwap allows you to:
- π² Create Conditional Orders: Set up token swaps that only execute when your predicted market outcome occurs
- π Browse Markets: Explore Polymarket prediction markets directly in the interface
- β‘ Automatic Execution: Orders execute automatically when market conditions resolve in your favor
- π Trustless: Built on CoW Swap's proven conditional order infrastructure
- πΈ Gas Efficient: Leverages batch auctions and off-chain order matching
- π Safe Wallet Integration: Secure multi-signature wallet support for institutional users
"I believe if Trump wins the 2024 election, crypto market will go up. If my Polymarket bet gets filled, I want to automatically swap 1000 USDC for ETH at current market rates."
With PolySwap, you can create this conditional order that will only execute if the condition is met, eliminating the need to manually monitor the prediction market outcome and execute the trade yourself.
PolySwap consists of integrated frontend and backend components:
- Modern React Interface: Built with Next.js 15 and React 19
- Market Browser: Search and explore Polymarket prediction markets
- Order Creation Flow: Intuitive interface for setting up conditional swaps with Polymarket integration
- Order Management: Track and manage your active conditional orders
- Safe Wallet Integration: Gnosis Safe support with WalletConnect for secure transactions
- Real-time Updates: Live order status and market data synchronization
- Next.js API Routes: Integrated API serving market data and order information
- Blockchain Listener: Monitors Polygon for PolySwap order events and trade executions
- PostgreSQL Database: Stores market data, order history, and order UIDs
- Real-time Processing: Indexes and processes orders as they're created
- Order UID Calculation: Automatic calculation and storage of CoW Protocol order UIDs
π View Detailed Backend Documentation with API endpoints β
- Node.js 18+ and pnpm (preferred package manager)
- Docker and Docker Compose (for the database)
# Install dependencies
pnpm install
# Set up environment variables
cp .env.sample .env
# Edit .env with your configuration-
Start the database:
pnpm db:up
-
Start the backend services:
# Start blockchain listener + market updater pnpm start:listener -
Start the frontend:
pnpm dev
-
Access the application:
- Frontend:
http://localhost:3000
- Frontend:
pnpm dev # Start Next.js development server (port 3000)
pnpm build # Build production frontend
pnpm start # Start production frontend
pnpm lint # Run ESLintpnpm start:listener # Start blockchain listener + market updater
pnpm start:listener-only # Start only blockchain listener
pnpm start:market-updater # Start only market updater (via listener)
pnpm start:market-updater-standalone # Start standalone market updaterpnpm saveMarkets # Fetch markets from Polymarket API to data.json
pnpm db:import # Import markets from data.json to databasepnpm db:up # Start PostgreSQL container
pnpm db:down # Stop PostgreSQL container
pnpm db:logs # View database logspnpm get-polymarket-creds # Get Polymarket credentials
pnpm cancel-polymarket-orders # Cancel all Polymarket orders
pnpm sell-polymarket-positions # Sell all Polymarket positionsPolySwap includes an automatic market update service that keeps your database synchronized with the latest Polymarket data.
Set the update interval in your .env file:
MARKET_UPDATE_INTERVAL_MINUTES=5 # Update every 5 minutes (default)
AUTO_REMOVE_CLOSED_MARKETS=true # Remove closed markets automaticallyTo prevent the system from holding risk after Polymarket BUY orders are executed, PolySwap includes an automatic position selling service. When a user creates a PolySwap limit order, the backend creates a corresponding Polymarket BUY order. Once this order is filled, the system holds a position that could gain or lose value. The position seller service automatically sells these positions to maintain solvency.
- The service runs every X minutes (default: 5 minutes)
- It fetches all current positions from the Polymarket API
- For each position found, it creates a SELL order at 95% of current price for faster execution
- All sales are logged to the database for auditing
Set the sell interval in your .env file:
POSITION_SELL_INTERVAL_MINUTES=5 # Check and sell positions every 5 minutes (default)The position seller runs automatically with the main listener:
pnpm start:listener # Runs blockchain listener, market updater, AND position seller-
Full Service (Recommended for production):
pnpm start:listener # Runs both blockchain listener and market updater -
Market Updater Only:
pnpm start:market-updater # Market updates via listener with --market-update-only flag # OR pnpm start:market-updater-standalone # Standalone market updater script
-
Blockchain Listener Only:
pnpm start:listener-only # Only listens for on-chain events
- Fetches active markets from Polymarket API every X minutes
- Updates existing markets and adds new ones to the database
- Uses optimized batching to avoid overwhelming the API/database
- Automatically handles errors and retries
- Provides detailed logging for monitoring
Key environment variables (see .env.sample):
DB_HOST=localhost
DB_PORT=5432
DB_NAME=polyswap
DB_USER=postgres
DB_PASSWORD=your_passwordCLOB_API_KEY=your_api_key
CLOB_SECRET=your_secret
CLOB_PASS_PHRASE=your_passphraseβΉοΈ Info: You can generate these Polymarket API credentials with the script:
pnpm get-polymarket-creds
RPC_URL=https://polygon-rpc.com/
STARTING_BLOCK=76437998
COMPOSABLE_COW=0xfdaFc9d1902f4e0b84f65F49f244b32b31013b74
NEXT_PUBLIC_POLYSWAP_HANDLER=0x65a5B712F34d8219A4c70451353D2F6A80e6703c
EXTENSIBLE_FALLBACK_HANDLER=0x2f55e8b20D0B9FEFA187AA7d00B6Cbe563605bF5MARKET_UPDATE_INTERVAL_MINUTES=60 # Market data sync interval (default: 60)
POSITION_SELL_INTERVAL_MINUTES=5 # Position auto-sell check interval (default: 5)
AUTO_REMOVE_CLOSED_MARKETS=true # Clean up closed markets automaticallyThe following diagram illustrates how funds move through the PolySwap system during a conditional order lifecycle:
sequenceDiagram
Actor User
participant Dapp as Polyswap dApp
participant PO as Polymarket OrderBook
participant Safe as Safe Wallet (Fund Custody)
box onchain
participant SellToken as Sell Token Contract (USDC)
participant CC as ComposableCoW Contract
participant PH as Polyswap Handler
participant Polymarket as Polymarket Contract
participant BuyToken as Buy Token Contract (COW)
end
participant CS as CoW Settlement Contract
participant WT as Watch Tower
participant CP as CoW Protocol
Note over User, Safe: Phase 1: Order Setup & Fund Preparation
User->>Dapp: Choose market & configure order (sellAmount, buyAmount)
Dapp->>User: Check wallet balance for sellAmount
alt Insufficient Balance
Dapp-->>User: Error: Insufficient funds
else Sufficient Balance
Dapp-->>PO: Create Polymarket limit order (condition trigger)
PO-->>Dapp: Return polymarket order hash
Note over Safe, SellToken: Phase 2: Token Approval & Transaction Batch
Dapp->>Safe: Check current token allowance for ComposableCoW
alt Insufficient Allowance
Dapp->>Safe: Prepare batch: [Approval TX, CreateOrder TX]
Safe->>SellToken: approve(ComposableCoW, MAX_UINT256)
Note over Safe: Funds remain in Safe, only approval granted
else Sufficient Allowance
Dapp->>Safe: Prepare single TX: [CreateOrder TX]
end
User->>Safe: Sign transaction batch
Safe->>CC: createWithContext(orderParams, valueFactory, data)
Note over Safe: β
Funds still remain in user's Safe wallet
CC->>CC: Store conditional order parameters
CC-->>WT: Emit ConditionalOrderCreated(owner, params)
WT-->>CP: Register conditional order in orderbook
end
Note over CP, CS: Phase 3: Continuous Order Monitoring (Every Block)
loop Every Block Until Condition Met or Expiry
CS->>Safe: Call isValidSignature(orderHash, signature)
Safe->>CC: Delegate to isValidSafeSignature()
CC->>PH: Call verify(order) to check condition
PH->>Polymarket: getOrderStatus(polymarket_order_hash)
Polymarket-->>PH: Return order status (filled/remaining)
alt Polymarket Order Not Filled
PH-->>CC: Condition NOT met - revert with POLL_TRY_NEXT_BLOCK
CC-->>Safe: Order invalid (condition not met)
Safe-->>CS: Invalid signature
Note over CS: Skip execution, try next block
else Polymarket Order Filled
PH-->>CC: β
Condition MET - order valid
CC-->>Safe: Order valid
Safe-->>CS: Valid signature
Note over CS: Proceed to execution
end
end
Note over CS, BuyToken: Phase 4: Order Execution & Fund Transfer
alt Condition Met
Note over CS: Settlement begins - funds will move
CS->>Safe: Execute delegatecall for fund transfer
Safe->>SellToken: transfer(CoW Settlement, sellAmount)
Note over SellToken: π° User funds leave Safe wallet
CS->>CS: Execute swap logic internally
CS->>BuyToken: transfer(Safe, buyAmount)
Note over BuyToken: π° User receives buy tokens in Safe
CS->>CS: Emit Trade(owner, sellToken, buyToken, sellAmount, buyAmount, feeAmount, orderUid)
CS-->>Dapp: Trade event notification
Dapp->>Dapp: Update order status to "executed"
Note over User: β
Swap completed: User exchanged sellAmount for buyAmount
else Condition Never Met (Order Expires)
Note over Safe: π° Funds remain safely in user's Safe wallet
CS-->>Dapp: Order expired
Dapp->>Dapp: Update order status to "expired"
end
Note over User, Dapp: Phase 5: Final State
alt Order Executed
Note over User: Final State: User has buyTokens, spent sellTokens + fees
else Order Expired/Cancelled
Note over User: Final State: User retains original sellTokens (no loss)
end
Note: If the diagram does not display correctly, here is the diagram as a PNG:
polyswap_mermaid.png
PolySwap is designed to work exclusively with Gnosis Safe wallets for enhanced security:
- Safe Apps (TODO): Run PolySwap directly inside the Safe interface
- WalletConnect: Connect external Safe wallets via WalletConnect protocol
![]() Lucas Leclerc |
![]() Baptiste Florentin |
|---|

