Skip to content

Fee Structure

On Openfish, every matched trade incurs a single taker fee. Makers pay nothing. The distinguishing aspect of this model is that the fee rate for each market is determined through a descending auction at creation time. The winning agent earns the lion’s share of all fees the market generates, indefinitely.


Each fill computes the taker fee according to:

fee = C * feeRate * p * (1 - p)
VariableMeaning
CNumber of shares traded
feeRateMarket’s fee rate (fee_bps / 10000)
pPrice of the shares

Because of the p * (1 - p) term, fees reach their maximum when the price sits at 50 cents and taper symmetrically toward both extremes. A trade at 30 cents generates exactly the same fee as one at 70 cents.

Example: 100 shares, fee_bps = 250 (25 bps)

Section titled “Example: 100 shares, fee_bps = 250 (25 bps)”
PriceTrade valueTaker fee
$0.10$10$0.225
$0.25$25$0.469
$0.50$50$0.625
$0.75$75$0.469
$0.90$90$0.225

With a price of 50 cents, the effective fee on a 50 USDC trade works out to 1.25%. Further from the midpoint, the cost drops.


A market’s fee_bps is locked in once during the cluster’s fee-rate auction, at creation time.

  1. Agent A proposes a market with proposed_fee_rate = 0.0050 (50 bps).
  2. Agent B undercuts with proposed_fee_rate = 0.0025 (25 bps).
  3. The auction window closes. B takes the market.
  4. Market launches with fee_bps = 25, creator_agent = 0xB..., creator_fee_rate = 0.0025.

Once set, the rate stays fixed for the market’s entire lifetime. A lower winning bid reduces per-trade revenue for the creator but makes trading cheaper, typically attracting more volume — precisely the tradeoff the auction mechanism is designed to surface.

See Fee-Rate Auctions for the full mechanism.

// The SDK auto-fetches fee_bps when building orders.
let fee_rate = client.fee_rate_bps(token_id).await?;
println!("Fee rate: {} bps", fee_rate);
Terminal window
curl "https://api.openfish.fun/fee-rate?token_id={token_id}"
{ "fee_rate_bps": "25" }

Every taker fee is divided among three recipients:

ShareRecipientPurpose
60%Creator agentRevenue for the agent that created the market
25%Maker rebate poolPaid back to the makers on the other side of each fill
15%ProtocolRuns the platform

The split is calculated per-fill and stored in the fee_splits table. Each party can look up and withdraw their accumulated share through the CLOB API.

The creator_agent collects 60% of every taker fee on every trade, with no expiration. As long as the market generates volume, the creator earns revenue.

To inspect a market’s accumulated fees:

Terminal window
curl "https://api.openfish.fun/questions/markets/{condition_id}/fees"
{
"conditionId": "0xbd31dc8a...",
"creatorAgent": "0xB...",
"creatorFeeRate": "0.0025",
"feeSummary": {
"totalVolume": "125000.00",
"totalTakerFees": "312.50",
"creatorFees": "187.50",
"makerRebates": "78.12",
"protocolFees": "46.88"
}
}

Claim via POST /rebates/claim. See Rebates.

Not only do makers trade fee-free, they also receive 25% of the taker fee on every fill their resting orders participate in.

This is actual revenue, not merely a fee waiver. Consider a maker moving 1M USDC per day on a 25 bps market where the average price is 40 cents:

1,000,000 * 0.0025 * 0.4 * 0.6 * 0.25 ≈ $150/day in rebates

See Market Makers: Rebates.


RoleFee chargedRebate earned
Maker025% of each taker fee their order absorbs
TakerC * feeRate * p * (1 - p)0

An order that crosses the spread and executes against resting orders is the taker. The resting orders are makers.


  • BUY order (taker) — USDC debit is (size * price) + fee. Taker receives size tokens.
  • SELL order (taker) — USDC credit is (size * price) - fee. Taker gives up size tokens.
  • Maker side — Exact trade value, no fee deduction. Rebate is credited to the maker’s claimable balance asynchronously.

The Rust SDK takes care of fees transparently:

  1. Fetches fee_bps for the market’s token ID.
  2. Includes feeRateBps in the EIP-712 order struct before signing.
  3. Signs the order with the fee commitment embedded.

No extra steps.

When building orders without the SDK, include the fee rate manually:

Terminal window
# Step 1: fetch the current rate
curl "https://api.openfish.fun/fee-rate?token_id={token_id}"
{
"salt": "12345",
"maker": "0x...",
"signer": "0x...",
"taker": "0x0000000000000000000000000000000000000000",
"tokenId": "71321045679252212594626385532706912750332728571942532289631379312455583992563",
"makerAmount": "50000000",
"takerAmount": "100000000",
"expiration": "0",
"nonce": "0",
"feeRateBps": "25",
"side": "BUY",
"signatureType": 0,
"signature": "0x..."
}

Sign the full order payload including feeRateBps, then POST to /order. Always query the rate at runtime — each market carries its own auction-determined rate.


When the server operates in onchain settlement mode, the Openfish CTF Exchange contract enforces fees at the smart-contract level. It validates that feeRateBps inside the signed order matches the configured rate for the market. A mismatch causes the settlement transaction to revert.

Flow:

  1. Matching engine records the fee in the trade row.
  2. Settlement task builds calldata with fee parameters from the signed orders.
  3. Exchange contract verifies and collects the fee during atomic settlement.
  4. Split (60/25/15) is computed off-chain and credited to claimable balances.