Skip to content

fix: Assert the ammAssetOut denominator is non-zero - #7959

Draft
SoubeDev wants to merge 2 commits into
XRPLF:developfrom
SoubeDev:fix-6661-amm-asset-out-denominator-assert
Draft

fix: Assert the ammAssetOut denominator is non-zero#7959
SoubeDev wants to merge 2 commits into
XRPLF:developfrom
SoubeDev:fix-6661-amm-asset-out-denominator-assert

Conversation

@SoubeDev

@SoubeDev SoubeDev commented Aug 5, 2026

Copy link
Copy Markdown

Closes #6661.

Adds the defensive XRPL_ASSERT requested in the issue.

Two notes on the issue as filed:

  • The path is stale — the code is at src/libxrpl/ledger/helpers/AMMHelpers.cpp, not src/libxrpl/tx/transactors/dex/.
  • The denominator appears twice, not once: the issue quotes the fixAMMv1_3 path but not the legacy branch. Hoisting into denom covers both with a single assert.

Uses beast::kZero rather than the issue's Number{0} — both compile, but beast::kZero is the existing idiom in this file and in the sibling denominator guard in AMMWithdraw::singleWithdrawEPrice.

The tighter 0 < t1 <= 1 invariant is deliberately not asserted. It is genuinely violable in production — t1 can exceed 1 marginally for a sole LP without fixAMMv1_1, and t1 == 0 is rle pre-fixAMMv1_3 in singleWithdrawTokens — so asserting it would crash Debug builds on real ledger data, contrary to CONTRIBUTING.md's rule on contracts violable by external conditions.

Release behavior is unchanged; XRPL_ASSERT compiles out, and hoisting the subexpression is value-identical (no rounding-mode guard is active at that point).

🤖 Generated with Claude Code

ammAssetOut divides by (t1 * f - 1) in both the pre-fixAMMv1_3 and
current paths without recording why the denominator is safe. Hoist it
into a named local and assert it, so the contract lives with the code
and a future change that widens the input ranges trips in Debug.

The invariant holds because f = tfee / kAuctionSlotFeeScaleFactor is
bounded by kTradingFeeThreshold (0.01) and t1 <= 1, putting denom in
[-1, -0.99]. The tighter 0 < t1 <= 1 is deliberately not asserted: it
is violable for a sole LP without fixAMMv1_1 and t1 == 0 is reachable
pre-fixAMMv1_3, which would crash Debug builds on real ledger data.

Fixes XRPLF#6661
@SoubeDev
SoubeDev marked this pull request as draft August 5, 2026 18:16
ammAssetOut divides by (t1 * f - 1) in both the pre-fixAMMv1_3 and
current paths without recording why the denominator is safe. Hoist it
into a named local and assert it, so the contract lives with the code
and a future change that widens the input ranges trips in Debug.

The invariant holds because f = tfee / kAuctionSlotFeeScaleFactor is
bounded by kTradingFeeThreshold (0.01) and t1 <= 1, putting denom in
[-1, -0.99]. The tighter 0 < t1 <= 1 is deliberately not asserted: it
is violable for a sole LP without fixAMMv1_1 and t1 == 0 is reachable
pre-fixAMMv1_3, which would crash Debug builds on real ledger data.

Fixes XRPLF#6661
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AMMHelpers: Add defensive XRPL_ASSERT for denominator in ammAssetOut

1 participant