Overview
Pokeliquid is the first on-chain perpetual futures DEX for Pokémon TCG products. Built on Solana using the Anchor framework, it offers 67+ markets letting traders go long or short on sealed products and single cards with up to 25x leverage. Prices are sourced from TCGPlayer market data via an automated Playwright scraper with adaptive EWMA smoothing.
Live on Solana Mainnet with real USDC.
Current Markets
| Market | Card | Set | Card # | Live |
|---|---|---|---|---|
| PL500-PERP | PL500 Index | Index | — | Yes |
| PRISMATIC-ETB-PERP | Prismatic Evolutions ETB | Sealed Product | — | Yes |
| CHARIZARD-125/094-PFL-PERP | Mega Charizard X ex | Phantasmal Flames | 125/094 | Yes |
| CHARMANDER-038-MEP-PERP | Charmander | Mega Evolution Promo | 038 | Yes |
| PIKACHU-276/217-AH-PERP | Pikachu ex | Ascended Heroes | 276/217 | Yes |
| GRENINJA-116/086-CR-PERP | Mega Greninja ex | Chaos Rising | 116/086 | Yes |
| ASCENDED-HEROES-ETB-PERP | Ascended Heroes ETB | Sealed Product | — | Yes |
| PSYDUCK-226/217-AH-PERP | Psyduck | Ascended Heroes | 226/217 | Yes |
| MEOWTH-106/094-PFL-PERP | Meowth | Phantasmal Flames | 106/094 | Yes |
| BLACK-BOLT-ETB-PERP | Black Bolt ETB | Sealed Product | — | Yes |
| MAGNETON-159-PROMO-PERP | Magneton | SV Promo | 159 | Yes |
| CHARIZARD-199/165-151-PERP | Charizard ex | SV 151 | 199/165 | Yes |
| MISTYS-PSYDUCK-193/182-DR-PERP | Misty's Psyduck | Destined Rivals | 193/182 | Yes |
| UMBREON-161/131-PE-PERP | Umbreon ex | Prismatic Evolutions | 161/131 | Yes |
| MEW-232/091-PF-PERP | Mew ex | Paldean Fates | 232/091 | Yes |
| PIKACHU-238/191-SS-PERP | Pikachu ex | Surging Sparks | 238/191 | Yes |
| GIRATINA-GG69/GG70-CZ-PERP | Giratina VSTAR | Crown Zenith | GG69/GG70 | Yes |
| CHAOS-RISING-BB-PERP | Chaos Rising Booster Box | Sealed Product | — | Yes |
| KABUTO-FOSSIL-1E-PERP | Kabuto | Fossil 1st Edition | — | Yes |
| GENGAR-284/217-AH-PERP | Mega Gengar ex | Ascended Heroes | 284/217 | Yes |
| DRAGONITE-290/217-AH-PERP | Mega Dragonite ex | Ascended Heroes | 290/217 | Yes |
| CLEFAIRY-094/088-PO-PERP | Clefairy | Perfect Order | 094/088 | Yes |
Network
Solana Mainnet. All addresses are mainnet PDAs derived from the program.
Getting Started
1. Visit the app
Go to pokeliquid.xyz.
2. Create an account
Click “Start Trading” on the landing page. You can create an account with email and password, or continue as a guest with no account.
3. Session Wallet
No browser wallet extension (Phantom, Solflare) is required. Pokeliquid automatically generates a Solana keypair stored in your browser’s localStorage. This “session wallet” signs all transactions locally. If you create an account, your encrypted private key is stored server-side for email recovery (AES-256-GCM encryption).
4. Deposit Collateral
Click “DEPOSIT/WITHDRAW” and deposit USDC into your margin account. Your margin account is a PDA derived from your wallet address with the seed margin.
5. Open a Position
Select a market, choose Long or Short, set your collateral amount and leverage (1-25x), optionally set Stop Loss and Take Profit prices, then click to open your position.
6. Password Reset
If you forget your password, click “Forgot password?” on the login screen. Enter your email and you’ll receive a reset link via email. The link expires in 1 hour and is single-use.
Trading
Opening a Position
The open_position instruction accepts:
| Parameter | Type | Description |
|---|---|---|
| direction | Long | Short | Trade direction |
| collateral | u64 | USDC collateral amount (6 decimals, e.g. 10_000_000 = $10) |
| leverage | u8 | Leverage multiplier (1–25) |
| sl_price | Option<u64> | Optional stop-loss price (6 decimal scale) |
| tp_price | Option<u64> | Optional take-profit price (6 decimal scale) |
Notional value = collateral \u00D7 leverage. A 0.5% fee (50 bps) is deducted from collateral on open. The position is stored in your MarginAccount which supports up to 5 simultaneous positions.
Order Types
Currently only Market orders are supported on-chain. The frontend also shows Limit and Stop order UI, but these are executed as market orders when the price condition is met by the keeper.
Closing a Position
Call close_position with the position slot index (0\u20134). PnL is calculated as:
Long PnL = notional * (exit_price - entry_price) / entry_price Short PnL = notional * (entry_price - exit_price) / entry_price
A 0.5% close fee is deducted. There is no profit cap — winning positions pay their full PnL. The settlement amount (collateral + PnL - fees) is transferred from/to the fee vault. There is no collateral cap per position — size is only bounded by the per-market OI limit.
FIFO Payout Queue
If a winning trade exceeds the LP vault's available balance, the trader still closes their position. They receive whatever USDC the LP vault can cover immediately, and the remaining amount is logged on-chain as a shortfall. A permissionless process_payouts instruction processes the queue in FIFO order as fees and liquidations replenish the LP vault. Traders always get paid — the only variable is timing.
Stop Loss / Take Profit
Set SL/TP on any open position via set_sl_tp. The keeper monitors prices and calls execute_sl_tp permissionlessly when conditions are met. The executor receives a 0.1% reward (10 bps of position collateral) for executing the order.
Multiple Positions
Each MarginAccount supports up to 5 simultaneous positions across any market. Positions are stored in a fixed-size array. MarginAccount size = 546 bytes.
Fees & Costs
| Fee | Rate | Notes |
|---|---|---|
| Open Fee | 0.5% (50 bps) | Deducted from collateral when opening |
| Close Fee | 0.5% (50 bps) | Deducted from settlement when closing |
| Profit Cap | None (uncapped) | Full PnL paid out |
| Min Position Size | $1.00 (1,000,000 raw) | Minimum collateral |
Trading Fee Distribution
Trading fees collected on open and close are distributed:
| Destination | Share | Description |
|---|---|---|
| LP Pool | 50% (5,000 bps) | Distributed to liquidity providers |
| Insurance Fund | 25% (2,500 bps) | Bad debt coverage |
| Platform | 25% | Protocol revenue (stays in fee vault) |
Funding Rate
Funding is calculated per-second and settled by the keeper via settle_funding (permissionless crank). Funding accrues continuously based on elapsed seconds, not in discrete hourly increments. Only the majority side pays funding — the minority side pays nothing. The funding rate has two components:
Base Rate: 30 / 100,000 per hour = 0.03%/hr = 0.72%/day
Skew Rate: skew_factor * (long_OI - short_OI) / (long_OI + short_OI)
where skew_factor = 1,000 / 100,000 = 1%
Majority side pays: base_rate + skew_rate (per hour)
Minority side pays: 0 (benefits from being on the less crowded side)Funding Fee Distribution
Funding fees collected from the majority side are distributed:
| Destination | Share | Description |
|---|---|---|
| LP Pool | 70% (7,000 bps) | Distributed to liquidity providers |
| Insurance Fund | 20% (2,000 bps) | Bad debt coverage |
| Platform | 10% | Protocol revenue (stays in fee vault) |
Risk Management
Liquidation
A position is liquidatable when its margin ratio falls below 5% (500 bps).
Margin Ratio = (collateral + unrealized_PnL) / notional Liquidation Price (Long): entry_price * (1 - (collateral - notional * 0.05) / notional) Liquidation Price (Short): entry_price * (1 + (collateral - notional * 0.05) / notional)
Liquidation is permissionless — anyone can call liquidate. The keeper checks every 10 seconds and liquidates undercollateralized positions.
Liquidation Distribution
| Recipient | Share | Description |
|---|---|---|
| Liquidator | 2% (200 bps) | Reward for calling liquidate |
| LP Pool | 44% (4,400 bps) | Distributed to liquidity providers |
| Insurance Fund | 44% (4,400 bps) | Bad debt reserve |
| Platform | 10% | Protocol revenue (stays in fee vault) |
Add / Remove Margin
Use add_margin to move free collateral into a position (lowering liquidation price). Use remove_margin to withdraw margin back to free collateral (health-checked — cannot reduce margin ratio below the liquidation threshold).
Oracle
Price Source
Prices are scraped from TCGPlayer product pages using Playwright (headless Chromium). The keeper runs a browser instance, navigates to each product page, and extracts the current market price. All 22 live markets are scraped in parallel.
Each market has its own oracle PDA. See the Protocol section below for key addresses. All oracle PDAs are derived from seeds ["oracle", market_id].
Update Frequency
The oracle updates every 5 minutes (300,000ms). Each market has its own on-chain oracle account (PDA seeded with ["oracle", market_id]).
Adaptive EWMA Smoothing
Raw scraped prices are smoothed using an Adaptive Exponential Weighted Moving Average (EWMA) with 4 tiers based on price deviation from the current EWMA:
| Deviation | Alpha | Mode | Behavior |
|---|---|---|---|
| < 3% | 1.0 | Direct | Price passes through unchanged |
| 3–5% | 0.3 | Moderate | Moderate smoothing applied |
| 5–15% | 0.1 | Heavy | Heavy smoothing, slow convergence |
| > 15% | 0.01 | Spike | Near-total rejection, spike protection |
EWMA formula: new_ewma = alpha * raw_price + (1 - alpha) * prev_ewma Price floor protection: if candidate < floor, update is rejected entirely. Each market has a configurable price floor to reject invalid data.
Staleness Protection
On-chain, the oracle has a staleness threshold of 30 minutes (1,800 seconds). Anyone can call check_and_pause (permissionless) to automatically pause the protocol if the oracle is stale beyond the auto-pause threshold of 1 hour.
Secondary Authority
The oracle accepts updates from either the admin wallet or a secondary authority keypair. The keeper automatically fails over to the secondary keypair after 3 consecutive primary failures, and sends Telegram alerts when failover occurs.
Liquidity Pool
How It Works
Liquidity providers deposit USDC into the pool via lp_deposit and receive LP shares. Shares represent proportional ownership of the pool. The share price = total_usdc / total_shares.
Earning Fees
LPs earn fees from three sources:
| Source | LP Share | Description |
|---|---|---|
| Trading Fees | 50% | From position open and close fees |
| Funding Fees | 70% | From majority-side funding payments |
| Liquidations | 44% | From liquidated position collateral |
All LP fees accumulate in the fee vault and are claimable proportionally via claim_fees at any time.
Withdrawing
Call lp_withdraw with the number of shares to burn. USDC is returned proportionally. There is no lockup period — withdraw anytime.
Referral Program
Pokeliquid has an on-chain referral system. Register a unique username, share your referral link, and earn a percentage of trading fees from users who sign up through your link.
How It Works
1. Go to the Referral page and register a username (stored on-chain as a ReferralAccount PDA).
2. Share your link: pokeliquid.xyz/ref/your-username
3. When someone signs up through your link, their trades attribute fees to your referral account.
4. Claim accumulated referral fees anytime from the Referral page.
Protocol
Program Details
| Property | Value |
|---|---|
| Program ID | 5C1cz4kCA8DcD2zjhBphuK86vAjdoCnichK1kdLHPMt6 |
| Network | Solana Mainnet |
| Framework | Anchor 1.0.2 |
| Frontend | pokeliquid.xyz |
Deployed Addresses
All Instructions
| Instruction | Auth | Description |
|---|---|---|
| initialize | Admin | One-time protocol setup, creates all PDAs |
| initialize_pool | Admin | One-time LP pool setup |
| deposit_collateral | User | Deposit USDC into margin account |
| withdraw_collateral | User | Withdraw free collateral |
| close_margin_account | User | Close margin account, return rent |
| realloc_margin | User | Resize margin account (migration helper) |
| open_position | User | Open a leveraged perpetual position |
| close_position | User | Close a position, settle PnL |
| add_margin | User | Add collateral to an open position |
| remove_margin | User | Remove margin (health-checked) |
| set_sl_tp | User | Set stop-loss / take-profit prices |
| execute_sl_tp | Permissionless | Execute triggered SL/TP orders |
| liquidate | Permissionless | Liquidate undercollateralized position |
| settle_funding | Permissionless | Settle accrued funding on all positions (seconds-based) |
| check_and_pause | Permissionless | Pause protocol if oracle stale > 1hr |
| lp_deposit | User | Deposit USDC into LP pool for shares |
| lp_withdraw | User | Burn shares to withdraw USDC |
| claim_fees | User | Claim accumulated LP fee share |
| update_oracle | Admin/Secondary | Push price to default oracle |
| init_market_oracle | Admin | Create a market-specific oracle PDA |
| init_market_state | Admin | Create per-market OI tracking state |
| update_market_oracle | Admin/Secondary | Push price to market oracle |
| update_params | Admin | Update protocol parameters |
| withdraw_fees | Admin | Withdraw from fee vault |
| withdraw_insurance | Admin | Withdraw from insurance fund |
| register_referral | User | Register a referral username (on-chain) |
| claim_referral | User | Claim accumulated referral fees |
API Reference
The keeper exposes an HTTP API on port 3001. On the frontend, endpoints are proxied via Vercel rewrites at /api/keeper/*.
GET /ping
Health check. Returns {"ok":true,"timestamp":"..."}
GET /health
Comprehensive system health including oracle status, liquidation stats, funding stats, Solana RPC health, and per-market oracle data.
GET /prices
Historical price data for charting.
| Param | Type | Default | Description |
|---|---|---|---|
| market | string | ETB | Market ID (e.g. ETB, CHARIZARD-X, GRENINJA, UMBREON — see /prices endpoint) |
| limit | number | 50 | Number of rows (max 500) |
| from | number | — | Unix timestamp range start |
| to | number | — | Unix timestamp range end |
Response: [
{ "id": 1, "timestamp": 1717401600, "raw_price": 161.5, "ewma": 161.6, "deviation": 0.001, "alpha": 1, "tx_signature": "..." },
...
]GET /candles
OHLC candle data aggregated from raw 5-minute price records. Used for charting.
| Param | Type | Default | Description |
|---|---|---|---|
| market | string | ETB | Market ID (ETB, CHARIZARD-X, CHARMANDER, PIKACHU) |
| resolution | string | 1h | Candle resolution: 1h (hourly) or 1d (daily) |
| limit | number | 100 | Max candles returned |
Response: [
{ "time": 1717401600, "open": 161.5, "high": 162.0, "low": 160.8, "close": 161.9 },
...
]GET /trades/recent
Recent trades across all users.
| Param | Type | Default | Description |
|---|---|---|---|
| limit | number | 50 | Number of trades (max 200) |
Response: {
"trades": [
{ "id": 1, "timestamp": ..., "user_pubkey": "...", "direction": "long", "notional": 100, "entry_price": 156.19, ... },
...
]
}GET /trades
Trades for a specific user. Requires user parameter.
GET /stats
Protocol statistics (24h/7d volume, trades, liquidations, fees, unique traders).
