Skip to content

fix(scoring): reject sub-dust-only rates in is_executable_rate#434

Merged
LandynDev merged 3 commits into
testfrom
fix/inexecutable-rate-dust-floor
May 30, 2026
Merged

fix(scoring): reject sub-dust-only rates in is_executable_rate#434
LandynDev merged 3 commits into
testfrom
fix/inexecutable-rate-dust-floor

Conversation

@anderdc
Copy link
Copy Markdown
Collaborator

@anderdc anderdc commented May 30, 2026

Problem

is_executable_rate is the crown-eligibility gate (scoring.py executable_check). It only checks that some positive integer source ≥ 1 maps a TAO leg into [min_swap, max_swap]. At the live SN7 bounds (0.1–0.5 TAO) that lets a rate whose only in-bounds source is a single satoshi through as "executable":

  • btc→tao at 5e7 TAO/BTC → 1 sat → 0.5 TAO
  • tao→btc at 2e-8 TAO/BTC → the inverse of the same boundary (swap 1670)

A 1-sat BTC output is below Bitcoin's dust limit (P2WPKH dust = 294 sat, bitcoin/policy.cpp), so it can never be broadcast. The rate is therefore unfundable, yet today it:

  1. Earns crown — these boundary rates win the rate sort and collect reward despite being un-routable.
  2. Powers a grief — a reservation taken against one forces an unfulfillable swap that times out and slashes the miner (swap 1670), and on btc→tao the timeout pays the reserver the full TAO leg for a sub-dust BTC input.

Fix

Floor the routable-source search at a per-chain min_onchain_amount (the smallest amount that can actually exist/move on-chain):

  • BTC: 1000 sat — verified transferable: IsDust uses strict < and 546 is the P2PKH dust line, so 1000 clears every standard output type with margin against higher dustrelayfee and wallet quirks. Also tightens the executable-rate ceiling to TAO_max/(10·1000) = 50,000 TAO/BTC (~171× market).
  • TAO: 500 rao — the existential deposit. Inert today (_has_integer_routable_source is only ever called with the non-TAO side), so TAO behavior is unchanged; defined for future chains.
  • default: 1 — no floor; any future chain just declares its own.

One line in _has_integer_routable_source: max(1, …)max(src.min_onchain_amount, …). The existing inverse-symmetry path means the same change rejects both crown-squat directions.

Effect (and honest scope)

  • Sub-dust-only rates now fail executable_check → dropped from crown qualification, and the surviving rate band becomes fundable, so an honest arbitrageur can finally reserve-and-punish an absurd rate (reserving makes the miner busy, which ends its crown, and forces deliver-or-slash). This is the breadth/depth doc's "allow extreme rates only if they can be backed up against a real reserver" — min_sat is the prerequisite that makes "backed up" physically possible.
  • Does not by itself stop crown-squatting: the executable ceiling moves to ~50,000 TAO/BTC, so a squatter can re-post just under it (now fundable, hence arbitrage-exposed). Eliminating the squat is the breadth/depth redesign (rank spillage + EMA quality bonus + a σ-gate on the posted rate), tracked separately.
  • Does not gate the reservation path (axon_handlers still only checks slippage). Gating reservations by is_executable_rate is a planned follow-up that closes the dust self-park at the source.

Deferred (consciously)

  • max_sat / dest-dust check — the sub-dust destination edge on absurd high tao→btc rates (a crown-loser, never triggers at market rates). Hygiene.
  • is_executable_rate at the reservation path.
  • Breadth/depth scoring + reservation bid window — the real crown-squat / arbitrage-swoop fixes.

Tests

  • Rewrote the two tests that asserted the old "1-sat boundary is executable" behavior to pin the dust-floor boundary (sub-dust rejected, dust-clearing boundary executable), in both directions; they derive the floor from min_onchain_amount so they track the constant.
  • Full suite: 617 passed.

A rate whose only in-bounds source is below the source chain's dust /
existential floor (e.g. 1 sat -> 0.5 TAO at 5e7 TAO/BTC) is unfundable on
the source chain, yet currently passes is_executable_rate. So crown-squat
miners posting these boundary rates are still rewarded, and a reservation
taken against one forces an unfulfillable swap that times out and slashes
the miner.

Floor the routable-source search at a per-chain min_onchain_amount
(BTC 1000 sat, TAO 500 rao existential deposit; default 1 = no floor). BTC
uses 1000 rather than the bare 546 P2PKH dust line for margin against
higher dustrelayfee / wallet quirks, and it tightens the executable-rate
ceiling to TAO_max/(10*1000) = 50,000 TAO/BTC (~171x market). The existing
inverse-symmetry path covers tao->btc with the same change.
@anderdc anderdc force-pushed the fix/inexecutable-rate-dust-floor branch from 65cea1f to 5e34d1d Compare May 30, 2026 02:06
@LandynDev LandynDev merged commit 9298b62 into test May 30, 2026
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.

2 participants