Skip to content

feat(routing): fund waterfall tiers in descending score order - #836

Open
woahwhattheheck wants to merge 3 commits into
Stellar-split:mainfrom
woahwhattheheck:feat/777-waterfall-route-scoring
Open

feat(routing): fund waterfall tiers in descending score order#836
woahwhattheheck wants to merge 3 commits into
Stellar-split:mainfrom
woahwhattheheck:feat/777-waterfall-route-scoring

Conversation

@woahwhattheheck

Copy link
Copy Markdown

Closes #777.

WaterfallRouter funded tiers strictly in declaration order, so a
lower-value tier listed first took the funds ahead of a preferred one, with
no way to express preference short of reordering the array.

Changes

  • src/types/routing.tsWaterfallTier gains score?: number (higher is
    funded first, default 0).
  • src/routing/WaterfallRouter.ts — tiers are ordered by score descending
    before the waterfall runs; equal scores keep declaration order.

A config with no scores behaves exactly as before, so existing callers are
unaffected.

Ordering is total, not merely stable

The sort decorates each tier with its original index and breaks ties on that
index:

const byScore = (b.tier.score ?? 0) - (a.tier.score ?? 0);
return byScore !== 0 ? byScore : a.index - b.index;

Array.prototype.sort has been stable since ES2019, but an explicit tiebreak
makes the ordering total, so FIFO among equal scores holds regardless of the
engine or compile target rather than resting on that guarantee. The tiers are
sorted on a copy, so the caller's array is never reordered — there is a test
for that.

A non-finite score is rejected

NaN in a comparator makes it return NaN, which is neither <0, 0, nor
>0. The sort then produces an arbitrary order with no error — the funding
sequence silently becomes undefined. So score is validated alongside the
existing minimumAmount check and throws ValidationError, consistent with
how this file already reports bad tier input. Infinity is rejected on the
same grounds.

Validation

  • npx vitest run test/waterfallRouter.test.ts — 18/18 passing: the 9
    pre-existing cases plus 9 new ones covering unscored configs (unchanged
    order), descending order, unscored-treated-as-0, negative scores, FIFO
    across 8 equal-scored tiers, FIFO within each score group when groups
    interleave, a high score winning limited funds, caller-array immutability,
    and each non-finite score.
  • npx tsc --noEmit reports 210 errors on this branch and 210 on unmodified
    main
    — identical, with none in either changed file. That baseline is
    pre-existing and unrelated to this change.

Tiers were always funded in declaration order, so a lower-value tier declared
first would take the funds ahead of a preferred one. Tiers are now ordered by
score before execution, with declaration order preserved among equal scores.

Ordering is done on a copy via an index tiebreak, so the caller's array is
untouched and ties keep FIFO order independently of engine sort stability.
A non-finite score is rejected rather than silently producing an arbitrary
order through a NaN comparator.
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.

Add route scoring to select the optimal path in WaterfallRouter

1 participant