feat(ledger): book ccxt venue fees against their native asset (draft, #4277) - #4278
Closed
TaprootFreak wants to merge 1 commit into
Closed
feat(ledger): book ccxt venue fees against their native asset (draft, #4277)#4278TaprootFreak wants to merge 1 commit into
TaprootFreak wants to merge 1 commit into
Conversation
…4277) Draft for evaluation — the honest recommendation is hold/won't-fix given an immaterial benefit against a high semantic blast radius (see the PR description). The ccxt Trade branch books the venue fee as a CHF-only spread leg valued at the pre-2dp-rounded feeAmountChf, so a sub-cent fee (a Binance micro-fill's BNB commission) rounds to 0 and no leg is booked. And because the quote-spread plug neutralizes it, the fee has zero net P&L effect on every ccxt fill and its native outflow is never tracked. Mirror payout-order appendDistinctFeeLegs: book the fee against its native ASSET/{exchange}/{feeCurrency} account (mark-valued) so the native outflow survives even when its CHF value rounds to 0. Conservative: only for a distinct fee asset (not base/quote) with a bootstrapped account and a historical mark, else fall back to today's CHF spread leg — no trade that books today defers.
Collaborator
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft for evaluation, not a merge candidate. Addresses #4277. The honest recommendation is hold / won't-fix — the benefit is immaterial and the semantic blast radius is high. Opening it so the change and its trade-offs are concrete.
What #4277 is, and the deeper finding
The ccxt Trade branch (
exchange-tx.consumer.tstradeSpec) books the venue fee as a CHF-onlyEXPENSE/spread-{exchange}leg valued at the persisted, 2-dp-roundedfeeAmountChf. A Binance micro-fill's BNB commission is worth< 0.005 CHF→feeAmountChf = 0→ no leg (the #4277 symptom, and the benign cause of the pre-#4268checkNativeBalancenoise).Investigating the fix surfaced a bigger point: the quote-spread plug (
residualChf = -Σ amountChf) makestotal spread-{exchange} = quoteChf − baseChfindependent offeeAmountChf, so the venue fee is algebraically neutralized on every ccxt fill (not just sub-cent ones) — it is neither recognized as a cost nor tracked as a native outflow. The fee-currency (BNB) journal balance therefore carries a growing phantom that §7 reconciliation only observes and alarms (§7 never writes), so nothing is silently corrupted today.The change
Mirror
payout-order.consumer.appendDistinctFeeLegs: book the fee against its nativeASSET/{exchange}/{feeCurrency}account (mark-valued), so the native outflow survives even when its CHF rounds to 0. New privateappendCcxtFeeLegreplaces the two-line CHF push. Conservative by design: the native leg is booked only for a fee in a distinct asset (≠ base/quote — those are already incost, native booking there would double-count) that has a bootstrapped account and a historical mark; otherwise it falls back to today's exact CHF spread leg, so no trade that books today starts deferring. Sign-aware off the signedfeeAmount(maker rebate → Dr / INCOME). Scrypt's market-spread branch is untouched. No new account names, no CoA/bootstrap change, no migration; forward-only.Blast radius (why hold)
spread-{exchange}expense on all ccxt trades (Binance/MEXC/Kraken) and starts native fee-asset tracking. Cumulative P&L/native impact is the total ccxt fees over the ledger period (still small vs total balance, but larger than the sub-cent-only ~tens-of-CHF/20-months in Ledger: sub-cent fee-less exchange micro-fills omit the EXPENSE fee leg (feeAmountChf rounds to 0) #4277).Binance/BNB(and every ccxt fee currency) to be a bootstrapped ASSET account for the fix to bite; otherwise it safely no-ops to the CHF fallback.Bottom line: correct and buildable, but the cost/benefit doesn't justify a merge on its own. Nothing is lost today that §7 doesn't already surface.
Does the pattern generalize? (the survey)
A repo-wide audit of the ledger for the same anti-pattern (a crypto-native amount booked via a pre-rounded
*AmountChffield, losing sub-cent precision) found three confirmed sites; fiat/CHF-denominated 2-dp values are correct and were not flagged:exchange-tx.consumer.ts(this PR) — ccxt venue fee. Immaterial.trading-order.consumer.ts(book, network-fee leg) — DfxDex arbitrage on-chain gas (txFeeAmount, native) booked only as CHFtxFeeAmountChf; no native gas-coin leg. Materiality plausibly non-trivial but unquantified (L1 gas). Higher fix risk (TradingOrder has no fee-currency column → the gas token must be derived from the swap chain). → own issue, not this PR.payout-order.consumer.ts(appendDistinctFeeLegsearly-return gateif (feeChf === 0) return) — short-circuits before the correct native-leg machinery, so a distinct non-payout fee asset whose CHF sum rounds to 0 loses its native leg. Immaterial, narrowest edge, lowest fix risk (un-gate the existing native legs, gate only the CHF EXPENSE). → small follow-up issue.So: the approach is not exchange-tx-specific — the same "book fees natively, not via a pre-rounded CHF scalar" principle applies to
trading-orderand (narrowly)payout-order. Each is an independent mechanism on a different entity with different materiality and risk, so they belong in separate issues rather than one bundled PR.Verification (Node 20)
prettier/eslint/type-check/buildclean · DI graph resolves · full accounting suite 780/780 (incl. 3 new: native distinct-asset fee; sub-cent fee preserved natively; CHF fallback when the fee account is missing). The existing ccxt fee test (feeAmountChf only) now exercises the fallback path unchanged, as a regression guard.Staying draft intentionally. If the team decides native fee tracking is a principle worth the churn, I'll take it through the full review-to-ready gate and file the two sibling issues; merge stays with the maintainer.