{"record":{"id":"8ac38a06757992ff","repo":"nautechsystems/nautilus_trader","slug":"finalized-swap-base-amount-base-amount-is-not-a","errorCode":null,"errorMessage":"Finalized Swap base amount {base_amount} is not a BUY output","messagePattern":"Finalized Swap base amount (.+?) is not a BUY output","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":4790,"sourceCode":"        } else {\n            (event.amount1, event.amount0)\n        };\n    let last_qty = match plan.order.order_side() {\n        OrderSide::Sell => {\n            anyhow::ensure!(\n                base_amount.is_positive() && base_amount.unsigned_abs() == plan.amount_in,\n                \"Finalized Swap input {base_amount} does not match the persisted amount {}\",\n                plan.amount_in\n            );\n            plan.order.quantity()\n        }\n        OrderSide::Buy => {\n            anyhow::ensure!(\n                quote_amount.is_positive() && quote_amount.unsigned_abs() == plan.amount_in,\n                \"Finalized Swap input {quote_amount} does not match the persisted amount {}\",\n                plan.amount_in\n            );\n            anyhow::ensure!(\n                base_amount.is_negative(),\n                \"Finalized Swap base amount {base_amount} is not a BUY output\"\n            );\n            raw_amount_to_quantity(\n                base_amount.unsigned_abs(),\n                plan.pool.get_base_token().decimals,\n            )?\n        }\n    };\n\n    let block = &included.finality.inclusion_header;\n    anyhow::ensure!(\n        block.number == included.block_number\n            && block.hash == included.receipt.block_hash.to_string(),\n        \"Verified inclusion header {} does not match receipt hash {}\",\n        included.block_number,\n        included.receipt.block_hash\n    );","sourceCodeStart":4772,"sourceCodeEnd":4808,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L4772-L4808","documentation":"For BUY orders the base token is the output of the swap, so the decoded base amount must be negative (output amounts are signed negatively in this event representation). If the base amount is not negative, the event does not represent a BUY-shaped swap for this pool, so the verification aborts instead of computing a wrong fill quantity.","triggerScenarios":"Verifying a BUY where the decoded base amount is zero or positive — typically because base/quote were swapped in the amount0/amount1 selection, the order side was mislabeled, or the decoder emits unsigned amounts for this DEX.","commonSituations":"Order side recorded as Buy but the actual trade direction was Sell (plan built from stale intent); pool token ordering mismatch between configuration and on-chain token0/token1; a DEX decoder that does not sign output amounts as this verification expects.","solutions":["Fix the base/quote amount selection (swap the amount0/amount1 branch) if token ordering is misconfigured","Verify the plan's order_side matches the actual submitted trade direction","Check the DEX decoder's sign convention for output amounts and normalize it to the library's signed convention","Re-derive the order side from amount signs in the event if the direction is ambiguous"],"exampleFix":"// before\nanyhow::ensure!(base_amount.is_negative(), \"...\");\n// after (if decoder emits unsigned outputs)\nlet base_signed = -Decimal::from(raw_base_output);\nanyhow::ensure!(base_signed.is_negative(), \"...\");","handlingStrategy":"type-guard","validationCode":"if order_side == OrderSide::Buy && !base_amount.is_negative() {\n    return Err(anyhow!(\"BUY base output must be negative, got {}\", base_amount));\n}","typeGuard":"fn is_buy_output(base_amount: &Decimal) -> bool { base_amount.is_negative() }","tryCatchPattern":"let qty = if is_buy_output(&base_amount) {\n    raw_amount_to_quantity(base_amount.unsigned_abs(), decimals)?\n} else {\n    return Err(anyhow!(\"unexpected sign for BUY output\"));\n};","preventionTips":["Verify order_side is derived from the actual trade direction, not stale intent","Standardize the decoder's sign convention (inputs positive, outputs negative)","Check pool token ordering matches configuration before signing amounts","Add a unit test per DEX decoder asserting BUY/SELL sign shapes"],"tags":["blockchain","swap","sign-convention","buy"],"backgroundTag":"invalid-argument-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"}