# Pascal Pascal is a noncustodial prediction market exchange on Solana. ## Quickstart **Web:** visit [app.pascal.trade](https://app.pascal.trade) and connect your wallet to start trading. **Python Quickstart:** [github.com/pascal-research-inc/pascal-python-quickstart](https://github.com/Pascal-Research-Inc/pascal-python-quickstart#quickstart) includes examples for request signing and order placement, plus a simple market making script you can adapt for custom trading logic. ## Architecture Traders post collateral in a Solana program (smart contract) and submit signed orders to the offchain matching engine. When a trade occurs, the matching engine broadcasts a transaction containing both signed orders to settle the trade onchain. Only the matching engine can broadcast trades onchain, meaning all state transitions occur through the offchain API and trades are guaranteed to execute as soon as they are matched offchain. Practically, this means that after depositing, traders do not need to interact with the chain to trade on Pascal. The program ensures that any trading or movement of funds requires signatures by the trader. For details, see [Program](#program). ## Onboarding Open the [web app](https://app.pascal.trade), connect a Solana wallet (or sign up with email), and deposit USDC. Deposit USDC directly from a wallet, or by withdrawing from Polymarket or another centralized exchange to your generated deposit address. ## Fees Fees are charged per fill and configured per market. Fields for `taker_fee_rate` and `maker_rebate_share` are returned in each market's [MarketSpec](api.txt#marketspec). Today they default to: ```json { "taker_fee_rate": "0.020000", // Takers pay 2% * price * (1 - price) * size "maker_rebate_share": "0.250000" // Makers receive 25% of the taker fee } ``` Fees are denominated in USD and rounded to 6 fractional digits. For a fill of `size` contracts at price `price` ($0.00–$1.00), the taker pays: ``` size × price × (1 - price) × taker_fee_rate ``` ## Weighted Volume Weighted volume measures each fill as `price × (1 - price) × contracts`, where `price` is the contract price in dollars, from $0 to $1. For example, 100 contracts filled at $0.40 contribute: ``` 100 × 0.40 × (1 - 0.40) = 100 × 0.40 × 0.60 = 24 weighted contracts ``` Maker and taker fills count equally; an account's combined weighted volume is the sum of its lifetime maker and taker totals. ## Maker Rebates For a fill of `size` contracts at price `price` ($0.00–$1.00), the maker is paid: ``` size × price × (1 - price) × taker_fee_rate × maker_rebate_share ``` ## Builder Codes A third-party integration, such as a frontend, terminal, or bot, can attach a builder fee to the orders it routes by setting `builder_info` on [Place Order](api.txt#place-and-replace-orders) requests. Builder codes are permissionless: any registered account's wallet public key other than your own is a valid `builder_pubkey`, with no registration or approval step. The builder must hold at least $100.00 of free collateral at the time an order naming it is placed; see the placement rules below. The builder public key and fee rate sit inside the signed order permit, so the order's signer consents to the exact fee on every order. Consent is per order, not a standing approval. To stop paying a builder on future fills, cancel any open orders that name it and omit `builder_info` from future orders. For each fill of `size` contracts at price `price`, the order's owner pays the builder: ``` size × price × (1 - price) × builder_fee_rate ``` For example, a 1% builder fee rate on 100 contracts filled at $0.50 pays the builder $0.25. The fee is debited with the fill and credited to the builder's free collateral in the same settlement step; the builder withdraws the proceeds like any balance. Placement rejects fee rates above the 10% cap (`BUILDER_FEE_RATE_INVALID`), unknown builders and orders naming their own account (`BUILDER_INVALID`), and builders holding less than $100.00 of free collateral (`BUILDER_COLLATERAL_BELOW_MINIMUM`); resting orders are unaffected. Fills expose `builder_pubkey` and `builder_fee_paid_usd`, and lifetime builder totals are served by [Builder Stats](api.txt#builder-stats). ## Referral Program Pascal's referral program rewards you for inviting new traders to Pascal. You earn a share of the fees they generate, while they receive a fee discount. Creating a Generated or Custom Referral Code requires a funded account and at least 2,000 combined lifetime maker and taker [weighted contracts](#weighted-volume). Share your code or referral link with a new trader. When they sign up through the link or enter your code during registration, they become your referral. Referral codes cannot be added or changed after registration. You receive 10% of the exchange fees generated by each trader you refer, calculated after discounts and rebates, up to $10,000.00 in rewards per trader. Your share is credited to your Pascal balance automatically with each eligible trade and is available immediately. There is no separate claim process. A trader who registers with a referral code receives a 5% discount on fees until the discount has saved them $250.00. ## Contracts Pascal offers outcome contracts for trading. Outcome contracts are bilateral, fully collateralized derivative contracts which settle to a price `p` in the interval `[$0, $1]`. Counterparties are either long (receive `p` at settlement) or short (receive `1 - p` at settlement). There is no notion of "yes" or "no" on Pascal. If you are long 5 contracts, you can sell 8 and you will be short 3. ## Resolution Contracts are settled directly by the exchange team. Pascal does not use an onchain oracle to determine outcomes. ### Contracts Referencing Other Venues Some Pascal contracts reference a contract on another venue. Pascal settles these contracts to the resolution published by that venue. Pascal also publishes its own rules for these contracts for convenience, but the referenced venue ultimately controls resolution. Note that this means that even in cases where the referenced venue's resolution is disputed or incorrect, Pascal will follow that resolution. We make this choice to preserve fungibility even in edge cases. Pascal reserves the right to settle a contract differently in exceptional circumstances, especially when following the referenced venue's resolution is impossible because Pascal's technical architecture differs. For example, Pascal cannot rewind trades. Except in those circumstances, the referenced venue's resolution controls settlement. For illustrative purposes here are some scenarios and how Pascal would resolve: - The referenced venue incorrectly resolves its market. Pascal follows the resolution. - The referenced venue unwinds the market by reversing all trades. Reversing trades is technically impossible on Pascal. Pascal will instead follow the resolution rules as written if possible. - The referenced venue initially settles one way and later changes the resolution. Pascal resolutions are immutable. See the [reference attributes](api.txt#referenceattributes) in [`display_attributes`](api.txt#marketdisplayattributes) for details about a contract's reference. ## Collateral Accounts hold USDC collateral in the Pascal program. When entering positions, an account's **Free Collateral** is reduced by enough to cover the worst case loss on the position. For example, if going long `q` contracts at 30c, free collateral is reduced by `q * 0.30` USD. If going short `q` at 30c, free collateral is reduced by `q * (1 - 0.30)` USD. Free collateral is automatically unlocked when a market settles, or after partially or completely trading out of a position. ## Realized and Unrealized PnL Pascal reports realized and unrealized PnL on open positions for display and portfolio tracking. Core exchange accounting is based on collateral locked and unlocked during trading, not on these display fields. For display purposes, positions follow these rules: 1. The lifecycle of a position resets when touching zero. Fields like average entry price accumulate while the position stays open in one direction (long or short) and reset on touching or crossing zero. 2. Average entry price updates only when the magnitude of the position increases (ie longing when already long, shorting when already short). 3. Unrealized PnL is `size * (mark - entry)`, where `size` is signed and `entry` is the average entry price with full precision. The API's `average_entry_price` is floored to six decimal places, so use the separately returned `unrealized_pnl_usd` instead of calculating it from the displayed price. 4. Realized and unrealized PnL do not include fees. At the end of a position's lifecycle, the realized PnL is exactly equal to the account's USDC balance change attributable to that position, excluding fees. See [PnL History](api.txt#pnl-history) for account-level accounting. ## Self-Trade Prevention The matching engine prevents any fill where the same account would be both maker and taker by cancelling the maker order and continuing to match the taker. ## Matching Rounds And Priority The exchange batches incoming orders into rounds and processes them every 50ms. Within a round, orders are processed in three groups, in this order: 1. **Cancels** 2. **Post-only placements**: order place or replace requests with `post_only: true`. 3. **Other orders**: IOC, GTC limits without `post_only`, GTT, market. Requests within the same group are processed first come, first served by the order they were received by the write API. If a cancel references a `client_order_id` whose placement is accepted later in the same round, it is applied immediately after that placement. A non-post-only order may therefore match before its remaining resting size is canceled. If the placement is rejected or leaves no resting order, the cancel is rejected because the target no longer exists. This is comparable to Hyperliquid's matching algorithm. ## Order Book Each market has a single limit order book with bid and ask sides. Within a side, orders are sorted by price, then by order of arrival. Order book insertion happens in the order described in [Matching Rounds and Priority](#matching-rounds-and-priority). ## Tick Sizes Each market is parameterized with a `tick_sig_figs` and `tick_size_min`. Both `tick_size_min` and `tick_sig_figs` are returned in each market's [MarketSpec](api.txt#marketspec) and on [List Markets](api.txt#list-markets). For a market with `tick_size_min = 0.001` and `tick_sig_figs = 2`, the tick size at various prices is: | Price range (`px`) | Tick size | Example valid prices | |---|---|---| | `[0.10, 0.90]` | `0.0100` | `0.50`, `0.51`, `0.85` | | `[0.010, 0.100)` or `(0.900, 0.990]` | `0.0010` | `0.025`, `0.043`, `0.975` | | `< 0.010` or `> 0.990` | `0.0010` (floor) | `0.001`, `0.997` | Specifically, for a given price `p`: ``` p' = min(p, 1 - p) # Symmetrical around 50c p_sigs = floor(log10(p')) + 1 tick_size = max(10^(p_sigs - tick_sig_figs), tick_size_min) ``` The `min(p, 1 - p)` mirror keeps tick precision symmetric around `0.50`, so a market priced near $0.01 has the same precision as one priced near $0.99. The intuition is to use a fixed number of significant figures regardless of how many leading zeros the price has, and the min tick size adds a bound as the price approaches the endpoints. ## Program The following details are provided for informational purposes. None of them are necessary to trade on the exchange. The offchain APIs are the exclusive source of truth for exchange state. ### Guarantees and Non-Guarantees The program enforces the following guarantees: 1. Trader funds cannot move without a trader signature. 2. Trades can only occur at crossing prices and with trader signatures. 3. Once a trading key is revoked, orders placed with it cannot match. The program does not guarantee the following: 1. The program does not enforce the state of the order book. The offchain matching engine enforces matching priority. 2. The program does not provide onchain oracles for market resolution. ### Upgrade authority The program upgrade authority is secured with a Fordefi multisig. Accordingly key material is sharded across hardware secure enclaves. No upgrade keys are stored in AWS. Unlike an onchain multisig (eg Squads) this appears as a standard on-curve wallet onchain. In the future the Pascal program will also include timelocked upgrades. ### State Most exchange state is stored onchain in these large program-owned accounts: - Traders: [`B8FMkiV2fpLrkdHcvejTGaj4gcbYfW2vn5NULvowvCSB`](https://solscan.io/account/B8FMkiV2fpLrkdHcvejTGaj4gcbYfW2vn5NULvowvCSB) - Positions: [`6NGtecwsNdvm3qT1F7ARruQ4eZpbBNfZcn4D33pj3dVv`](https://solscan.io/account/6NGtecwsNdvm3qT1F7ARruQ4eZpbBNfZcn4D33pj3dVv) - Markets: [`8hktgNpvPg72bqbDwNorJhGsz9D1Vo7cHMN9jKei1Cb1`](https://solscan.io/account/8hktgNpvPg72bqbDwNorJhGsz9D1Vo7cHMN9jKei1Cb1) Additional per-trader information, including trading key records, is stored in trader auxiliary PDAs. For example, the trader auxiliary PDA for owner `5Hu8swhmKFK5NG7GWxYsisHfgKzic8WCF2QLGmrDs4Kk` is [`1CforH2A6eXwYpR8z7GFfdt2ikUNYZ5qFeaeNUD1Wc8`](https://solscan.io/account/1CforH2A6eXwYpR8z7GFfdt2ikUNYZ5qFeaeNUD1Wc8). ### Buffers To improve throughput, all state transitions are first buffered before they are applied to exchange state. The buffer accounts are [1](https://solscan.io/account/GDabzYPRoyVz15ZCh4ai9qYVnbLuR4wrLaJpDNKHKmEk), [2](https://solscan.io/account/4BRpDVoYc2C9kJZ1qyE2tZzeK4ziwGNgKfu2y2AkwiWb), [3](https://solscan.io/account/6YRWVZzWEpMTMFW2i7kEsD2dAegLM5zXxPWR6B7SeAw6), [4](https://solscan.io/account/4GeFP93aRsksicm13xqiBSVd2R3DpN1uyrjrGii6BY3L), [5](https://solscan.io/account/Ewfh7fFwhXZB82FFw4mVPc2jKh693nWuhaEaYo9nuHVa), [6](https://solscan.io/account/8yLNgTSTjiH5N11exuKgbUZwQeDrdPhJkWNd7Rfc283C), [7](https://solscan.io/account/9iuHJRvBiB5kLbqQC3vHCgSMETyb1voxbfZWz942ZQop), and [8](https://solscan.io/account/AubVvKS5n3PFVqXhCsehmrSDybTdP2AZdza5qk9G4bED). When a buffer is full, its transitions are applied to exchange state and the buffer is emptied. This is why trades initially appear in transactions targeting one of the buffers rather than the exchange state accounts. ### Deposit Addresses Traders do not deposit directly to exchange state. Instead, they deposit to program-controlled PDAs. The program then moves the funds into exchange state. For example, the deposit PDA for owner `GmaDrppBC7P5ARKV8g3djiwP89vz1jLK23V2GBjuAEGB` is `DtzBRq9hAREJZKj1fuHsgrWrtaeXmbYQdXsmMrd54arG`. To find your registered deposit address, use the [Deposit Address](api.txt#deposit-address) endpoint. Note that the deposit address PDA itself is never created (and thus won't show up on block explorers). Only the associated token account that stores the USDC is created. ## 2026 Midterms Rewards Earn from a pool of 255,000 USDC by trading midterms markets and referring VIP traders. The campaign runs from **September 17, 2026 at 00:00 UTC until November 5, 2026 at 00:00 UTC**, covering September 17 through November 4. It includes seven weekly trading pools totaling 105,000 USDC and up to 150,000 USDC for VIPs and their referrers. Visit the [Rewards page](https://app.pascal.trade/rewards) to see eligible markets, leaderboards, VIP eligibility, and your progress. ### Weekly Trading Rewards Each week, 15,000 USDC is allocated in proportion to participants' scores: ```text Weekly score = weighted volume × multiplier Estimated reward = 15,000 USDC × your score / total participant score ``` Each executed trade contributes: ```text Weighted volume = contracts × price × (1 - price) ``` Price is expressed between 0 and 1. For example, 1,000 contracts traded at $0.50 contribute **250 weighted volume**. The same number traded at $0.10 contributes **90**. Both maker and taker fills in markets marked as eligible for rewards count toward your score. Weeks begin on Thursdays at 00:00 UTC. Volume and scores reset each week. Your score multiplier starts at **1.0×**, or **1.1× if your first deposit was credited before the campaign began**. Each consecutive week with eligible trading adds 0.1× to the following week's multiplier. A week without eligible trading resets the following week's multiplier to your starting value. For example, a trader starting at 1.1× who trades every week reaches 1.7× in week seven. The pool is shared among all participants, including those outside the displayed leaderboard. Before each weekly payout, we review all leaderboard accounts for suspicious trading activity and may adjust scores. Rewards are credited to your Pascal account, normally within 24 hours of the week ending. See [Rewards Conditions](#rewards-conditions) for the review policy and potential penalties. ### VIP Referral Rewards Selected X accounts qualify for rewards for themselves and their eligible referrers. The VIP list can be found on the [VIP rewards page](https://app.pascal.trade/rewards?tab=referral). To earn a bonus for referring VIPs, they must onboard through your referral link. You must either have an active referral code at 00:00 UTC on September 19, 2026, or be a VIP yourself. Each qualifying day pays the following amount to the VIP and the eligible referrer: | VIP tier | Daily weighted volume required | Daily reward per person | Total per person | | --- | ---: | ---: | ---: | | $10,000 VIP | 10,000 | 1,000 USDC | 5,000 USDC | | $1,000 VIP | 1,000 | 100 USDC | 500 USDC | | $100 VIP | Any positive volume | 10 USDC | 50 USDC | The tier's name represents the combined total reward for the VIP and referrer. - **Any Pascal market counts** toward VIP milestones. Trading does not have to be in a midterms market. - Rewards can be earned on **five separate days**, which do not need to be consecutive. Days reset at 00:00 UTC; incomplete daily progress does not carry over. - Trading starts counting once your eligible X account is connected and the campaign has begun. Trades made before connecting your eligible X account do not count toward VIP milestones. - Eligibility stays with the first Pascal account enrolled for that X account. Disconnecting X or connecting it elsewhere does not transfer eligibility. Each Pascal account can enroll as one VIP. VIP rewards are credited automatically to both accounts when the daily requirement is met. These payments are additional to Pascal's [standard referral fee rewards](#referral-program). #### Referrer Eligibility To qualify for a VIP referral bonus, the referrer must either: - have an active referral code as of 00:00 UTC on September 19, 2026, or - be on the VIP list and have connected their eligible X account. ### Rewards Conditions These conditions apply to weekly trading rewards and VIP referral rewards. Participation is subject to Pascal's [Terms of Service](https://app.pascal.trade/terms.pdf), including eligibility and geographic restrictions. Pascal reviews trading activity across all accounts on the campaign leaderboard. After each week ends, scores may be adjusted following review before final weekly rewards are calculated. Reviews may delay payment. Prohibited activity includes self-trading to artificially inflate campaign volume. Self-trading includes trading between accounts controlled by the same person or entity. Pascal may exclude affected activity, reduce scores, disqualify participants, or withhold unpaid rewards based on the findings of the review. Pascal reserves the right to change the scoring formula, including volume weights and multipliers, and update eligible markets or the unclaimed VIP roster. Market eligibility changes apply to future trades; a trade counts only if its market was eligible when it executed. Pascal also reserves the right to modify, suspend, or end the campaign. Material changes will be published on this page. Available reward totals are maximum allocations rather than guaranteed distributions. Normal trading fees and risks apply, and losses may exceed rewards. Participants are responsible for applicable taxes.