{"record":{"id":"9ec57c3b381208ba","repo":"nautechsystems/nautilus_trader","slug":"outcome-side-token-fee-token-carried-a-non-zer","errorCode":null,"errorMessage":"Outcome side token '{fee_token}' carried a non-zero fee {fee_amount}; venue does not denominate fees in side tokens","messagePattern":"Outcome side token '(.+?)' carried a non-zero fee (.+?); venue does not denominate fees in side tokens","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/hyperliquid/src/http/parse.rs","lineNumber":726,"sourceCode":"/// the commission currency would leak into `OrderFilled` events and persistence;\n/// for outcome side tokens the instrument's quote currency is always used, even\n/// when another adapter path (such as spot-balance parsing) has registered the\n/// side token in the global registry. Non-zero side-token fees error: the venue\n/// does not denominate fees in side tokens. Other unknown tokens fall back to\n/// the instrument's quote currency only when the fee is zero.\n///\n/// # Errors\n///\n/// Returns an error when an outcome side token carries a non-zero fee, or when\n/// `fee_token` cannot be resolved and `fee_amount` is non-zero.\npub fn resolve_fee_currency(\n    fee_token: &str,\n    fee_amount: Decimal,\n    instrument: &dyn Instrument,\n) -> anyhow::Result<Currency> {\n    if is_outcome_side_token(fee_token) {\n        if !fee_amount.is_zero() {\n            anyhow::bail!(\n                \"Outcome side token '{fee_token}' carried a non-zero fee {fee_amount}; \\\n                 venue does not denominate fees in side tokens\",\n            );\n        }\n        return Ok(instrument.quote_currency());\n    }\n\n    if let Some(currency) = Currency::try_from_str(fee_token) {\n        return Ok(currency);\n    }\n\n    if fee_amount.is_zero() {\n        let fallback = instrument.quote_currency();\n        log::debug!(\n            \"Unregistered fee token '{fee_token}' on zero-fee fill for {}; using {fallback} as fallback\",\n            instrument.id(),\n        );\n        return Ok(fallback);","sourceCodeStart":708,"sourceCodeEnd":744,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/hyperliquid/src/http/parse.rs#L708-L744","documentation":"When resolving the fee currency of a Hyperliquid fill, outcome side tokens (symbols starting with '+') are recognized, but the venue never denominates fees in side tokens. If a fill reports a fee in a side token with a non-zero amount, the parser treats it as an invariant violation and fails rather than misattributing the fee.","triggerScenarios":"parse_fill_report receiving a fill whose fee token is an outcome side token (leading '+') with fee_amount != 0 — the venue response contains a fee denominated in a side token, which the parser considers impossible.","commonSituations":"Unexpected venue-side changes to fee denomination on HIP-4 outcome markets; a malformed or spoofed fill payload; running against a venue API version that changed fee reporting for outcomes.","solutions":["Check the venue API version/adapter version — update the Hyperliquid adapter if fee reporting for outcomes changed.","Log and report the raw fill payload to verify what token the venue actually charged the fee in.","If the payload is genuine, this is an upstream contract change: file an issue / patch resolve_fee_currency to map the new fee token.","For normal operation, treat this as a parse failure of that fill and continue processing subsequent fills."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"fn fee_token_is_safe(fee_token: &str, fee_amount: Decimal) -> bool {\n    !(fee_token.starts_with('+') && !fee_amount.is_zero())\n}","typeGuard":null,"tryCatchPattern":"match resolve_fee_currency(fee_token, fee_amount, instrument) {\n    Ok(cur) => apply_fee(cur, fee_amount),\n    Err(e) => log::warn!(\"skipping fee attribution: {e}\"), // side-token fee invariant broken\n}","preventionTips":["Verify adapter version against current venue fee behavior","Log raw fill payloads for outcome markets","Treat non-zero side-token fees as an upstream contract change to report"],"tags":["rust","hyperliquid","hip-4","fees","invariant-violation"],"backgroundTag":"unexpected-api-response-shape","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"}