Skip to main content
Perpetra charges two kinds of fees: trading fees, taken when you open or close a position, and liquidation fees, taken when a position gets liquidated. Both are set per-market and both flow through the same contract, FeeCollector.
Funding is not a fee. Funding payments move directly between longs and shorts and never touch FeeCollector, see Funding rate for that.

Trading fees

Every order pays either a taker fee or a maker fee, depending on whether it took liquidity or provided it: Maker fees are always less than or equal to taker fees. The contract enforces this at config time, since makers are the ones providing liquidity to the book. Each market has its own rate, expressed in basis points (1 bps = 0.01%):
The fee itself is a flat percentage of the order’s notional size:
Example: opening a $10,000 position on a market with a 5 bps taker fee:
This is calculated by the Engine before settlement (calcTradingFee) and deducted from your collateral as part of opening or closing the trade.

Liquidation fees

When a position is liquidated, a fee is taken from the position’s remaining collateral and paid out to the keeper who triggered the liquidation:
This is credited directly to the keeper’s account, not into the general fee pool. It’s the incentive for keepers to monitor and liquidate underwater positions promptly. Cross-margin liquidations that close several positions in one batch pay a single aggregate fee to the keeper, with every closed position recorded against that one payment for accurate indexing.
The keeper’s fee comes out of the trader’s collateral, same as any other liquidation cost. It doesn’t add to what a liquidated trader loses beyond the fee amount itself.

Where trading fees go

Trading fees (taker + maker) accumulate in FeeCollector and are periodically distributed to two destinations, split by a configurable ratio that defaults to:
  • 20% → Insurance Fund
  • 80% → Treasury
Distribution can be triggered by anyone. There’s no access restriction on the distribute() call, since the destination addresses (Insurance Fund and Treasury) are fixed by the protocol, not chosen by the caller. In practice this runs on a keeper schedule. Liquidation fees don’t go through this split. As noted above, they’re paid straight to the liquidating keeper.

Checking fees before they hit

Two read-only helpers let you see fee math without waiting for a transaction:
  • getMarketFeeConfig(marketId): current taker/maker/liquidation rates for a market
  • previewDistribution(token): what the next distribute() call would send to Insurance Fund vs. Treasury, based on fees currently pending