Skip to content

feat(graph): detect negative-weight edges in PaymentGraphChecker - #830

Open
woahwhattheheck wants to merge 2 commits into
Stellar-split:mainfrom
woahwhattheheck:feat/773-negative-edge-weights
Open

feat(graph): detect negative-weight edges in PaymentGraphChecker#830
woahwhattheheck wants to merge 2 commits into
Stellar-split:mainfrom
woahwhattheheck:feat/773-negative-edge-weights

Conversation

@woahwhattheheck

Copy link
Copy Markdown

Closes #773.

PaymentGraphChecker validated reachability but had no notion of edge
weight, so a negative-weight hop passed through unnoticed. A greedy traversal
treats a negative hop as if it adds funds, which makes a route containing
one repeatable for unbounded extraction.

Changes

src/graph/PaymentGraphChecker.ts:

  • checkGraph(graph) — returns { valid, issues }, reporting every edge whose
    weight is negative. Each issue carries code, from, to, weight, and a
    message naming the offending edge as from -> to.
  • New exported types: PaymentGraphEdge, PaymentGraph,
    NegativeEdgeWeightIssue, GraphValidationResult.

Zero-weight edges remain valid — they are legitimate pass-through hops, so the
check is strictly weight < 0, not weight <= 0.

Two details worth calling out:

  • number and bigint weights are both handled. Amounts elsewhere in the
    SDK are bigint (Recipient.amount, Invoice.funded), but graph weights
    are natural to express as plain numbers, so checkGraph accepts either and
    compares against the matching zero.
  • All offending edges are reported, not just the first. Returning the full
    list means a caller fixing a malformed graph sees every problem in one pass.

checkGraph accepts either { edges } or a bare PaymentGraphEdge[], since
the issue did not pin the shape and both read naturally at a call site.

Validation

  • npx vitest run test/paymentGraphChecker.test.ts — 15/15 passing (the 7
    pre-existing cases plus 8 new ones covering: positive weights accepted,
    zero weights accepted, empty graph, a single negative edge, the message
    naming source and target, negative bigint, multiple offenders reported in
    edge order, and the bare-array form).
  • npx tsc --noEmit reports 210 errors on this branch and 210 on unmodified
    main
    — identical, so this change adds none, and zero are in
    src/graph/PaymentGraphChecker.ts. That baseline is pre-existing (missing
    exported members in types.js/priceOracle.js/soroban/footprint.js and
    noUncheckedIndexedAccess nullability) and is not a prerequisite here; I
    mention it only so the red lint isn't read as coming from this PR.

A negative hop weight is treated as adding funds by a greedy traversal, so a
route containing one can be repeated for unbounded extraction. checkGraph()
now reports every edge with a negative weight, naming source and target.
Zero-weight edges stay valid: they are legitimate pass-through hops.
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.

Detect negative-weight edges in the payment graph checker

1 participant