{"record":{"id":"28102a2735cf85e7","repo":"nautechsystems/nautilus_trader","slug":"polymarketfeemodel-requires-a-taker-only-fee-sched","errorCode":null,"errorMessage":"PolymarketFeeModel requires a taker-only fee schedule","messagePattern":"PolymarketFeeModel requires a taker-only fee schedule","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/models.rs","lineNumber":126,"sourceCode":"\nfn validate_schedule(schedule: &FeeSchedule) -> anyhow::Result<()> {\n    if schedule.exponent != Decimal::ONE {\n        anyhow::bail!(\n            \"PolymarketFeeModel requires fee schedule exponent 1, was {}\",\n            schedule.exponent\n        );\n    }\n\n    if schedule.rate < Decimal::ZERO {\n        anyhow::bail!(\"Polymarket fee rate must be greater than or equal to zero\");\n    }\n\n    if !(Decimal::ZERO..=Decimal::ONE).contains(&schedule.rebate_rate) {\n        anyhow::bail!(\"Polymarket rebate rate must be in [0, 1]\");\n    }\n\n    if !schedule.taker_only {\n        anyhow::bail!(\"PolymarketFeeModel requires a taker-only fee schedule\");\n    }\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use nautilus_core::UnixNanos;\n    use nautilus_execution::models::fee::{FeeModel, FeeModelHandle};\n    use nautilus_model::{\n        enums::{LiquiditySide, OrderSide, OrderType},\n        instruments::{Instrument, InstrumentAny, stubs::audusd_sim},\n        orders::{OrderAny, builder::OrderTestBuilder, stubs::TestOrderStubs},\n        types::{Price, Quantity},\n    };\n    use rstest::rstest;\n    use rust_decimal::Decimal;\n    use rust_decimal_macros::dec;\n","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/models.rs#L108-L144","documentation":"PolymarketFeeModel only supports taker-only fee schedules. During commission calculation, validate_schedule rejects any schedule where taker_only is false, because Polymarket fee logic cannot model maker rebates correctly. This is a fail-fast invariant to prevent silently wrong commission math.","triggerScenarios":"Constructing a PolymarketFeeModel (or calling get_commission) with a FeeModel whose taker_only flag is false, e.g. reusing a schedule copied from another venue that includes maker/rebate tiers.","commonSituations":"Reusing a generic fee schedule across adapters; building a schedule from config where a maker rebate rate was set; copying a CEX fee schedule that supports maker rebates.","solutions":["Set taker_only=true on the FeeModel schedule before passing it to PolymarketFeeModel","Remove any maker/rebate fields and construct the schedule via the Polymarket-specific constructor that defaults to taker_only","If maker fees are genuinely needed, use a different fee model — PolymarketFeeModel intentionally does not support them"],"exampleFix":"// before\nlet schedule = FeeModel::new(rebate_rate, false /* taker_only */);\nPolymarketFeeModel::new(schedule)?;\n// after\nlet schedule = FeeModel::new(Decimal::ZERO, true /* taker_only */);\nPolymarketFeeModel::new(schedule)?;","handlingStrategy":"validation","validationCode":"if !schedule.taker_only {\n    return Err(anyhow!(\"schedule must be taker_only for Polymarket\"));\n}\nlet fee_model = PolymarketFeeModel::new(schedule)?;","typeGuard":"fn is_taker_only(s: &FeeModel) -> bool { s.taker_only }","tryCatchPattern":null,"preventionTips":["Always construct Polymarket fee schedules via the Polymarket-specific constructor","Never reuse fee schedules across venue adapters","Assert taker_only in config loading tests"],"tags":["rust","fees","validation","config"],"backgroundTag":"invalid-config-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}