Add settlement volume totals FIX - #211
Merged
Jagadeeshftw merged 2 commits intoJul 27, 2026
Merged
Conversation
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.
================================================================================
PULL REQUEST
Repository : Mitch5000/AnchorNet-Backend
Base branch : main
Head branch : fix/metrics-settled-totals
Commit : 5cc1583
Type : Feature / enhancement (additive, backward compatible)
Files changed: 6 modified, 0 created, 0 deleted
Diff : +374 / -6
================================================================================
TITLE
Add totalSettledAmount and totalFeesCollected to the metrics snapshot
================================================================================
DESCRIPTION
Summary
GET /api/v1/metrics reported settlements and pendingSettlements as counts and
totalLiquidity as a pool-wide sum, but never summed settlement amount or fee.
An operator could see HOW MANY settlements existed, but not HOW MUCH value had
been settled or how much protocol fee revenue had been earned. Getting those
numbers meant paging through GET /api/v1/settlements and summing client-side.
This PR adds two fields to the metrics snapshot, both computed from executed
settlements only:
totalSettledAmount - sum of
amountover executed settlementstotalFeesCollected - sum of
feeover executed settlementsThe change is purely additive. Every pre-existing field keeps its exact name,
type and meaning, so existing consumers are unaffected.
Problem
In src/routes/metrics.ts, snapshot() pulled from three sources but only ever
produced counts of settlements:
The
amountandfeefields carried by every settlement were never aggregated.totalLiquidity does sum value, but it sums POOL BALANCES: supply currently
parked in the network. That is a different question from how much value has
actually flowed THROUGH the network, and it does not move when a settlement
executes against already-counted liquidity. There was no field answering
"what has this network settled, and what did we earn on it?"
Why executed-only
The settlement lifecycle in src/models/settlement.ts mirrors the on-chain
contract, and only one of the three states represents value that actually moved:
Counting pending settlements would inflate the totals with value that may never
settle (a pending settlement can still be cancelled). Counting cancelled ones
would report fees on revenue that was never earned. "Collected" has to mean
collected, so both are excluded.
This matches the accounting already inside SettlementService, where execute()
moves an amount out of
reservedand intoconsumed, while cancel() releasesthe reservation without ever touching
consumed.Changes
src/routes/metrics.ts (core fix)
Filter once to executed settlements, then reduce over amount and fee:
The MetricsSnapshot interface gained the two typed fields, was given TSDoc on
every member, and is now exported so consumers can import the response type.
Because recordSnapshot() spreads snapshot() into the bounded history buffer,
GET /api/v1/metrics/history inherits both fields with zero additional changes.
src/openapi.ts
Added descriptions to /api/v1/metrics and /api/v1/metrics/history naming both
new fields and stating the executed-only rule.
src/openapi.test.ts
New test asserting the spec documents both fields and the executed-only rule.
src/routes/metrics.test.ts
12 new tests in a new "metrics settled-value totals" block. The 5 original
tests are untouched.
README.md
Metrics section rewritten to describe both totals and the executed-only rule.
CHANGELOG.md
New [Unreleased] -> Added entry.
Design notes
A single .filter() is shared by both reducers. One pass over the status check
instead of two, and the executed-only predicate is stated exactly once, so the
two totals can never drift apart.
The aggregation lives in the route's snapshot(), per the issue's suggested
execution, rather than being pushed down into SettlementService. This keeps
the diff minimal and adds no new public service surface. Worth flagging for
reviewers: if these totals should be reusable by other callers, moving them
behind a SettlementService method would be the cleaner long-term home. Happy
to make that change if preferred.
Both reducers seed at 0, so a fresh app reports 0 / 0 rather than NaN or
undefined. Covered by a test.
Example
Given one anchor with 100,000 USDC liquidity and four settlements
(10,000 pending / 20,000 executed / 30,000 cancelled / 40,000 executed),
at the default 10 bps fee:
Counts still cover all four settlements. The value totals cover only the two
executed ones.
Backward compatibility
Fully backward compatible. Only additive.
existing timestamp; the shape is otherwise identical.
history snapshot, so any future accidental field rename or removal fails CI
rather than silently breaking clients.
Testing
The 12 new tests
Mutation testing
To confirm the new tests actually catch regressions rather than merely executing
lines, the implementation was deliberately broken five ways:
All five were caught. Source was restored and verified byte-identical (diff)
after each mutation, and the final committed file matches the intended fix.
Live smoke test
A real server was started on the compiled dist/ output and driven over HTTP with
a mixed pending + executed + cancelled workload. It returned
totalSettledAmount: 20000 and totalFeesCollected: 20 (the executed leg only),
confirmed the six pre-existing fields were unchanged, and confirmed the served
openapi.json contains the new documentation.
Acceptance criteria
Security
No security impact. This is a read-only aggregate computed over settlement data
that GET /api/v1/settlements already exposes. No new input is accepted, no new
data is persisted, and no new field is introduced to the domain model. The route
sits behind the same middleware stack (API key auth, rate limiting, security
headers) as before.
Files changed
No files created. No files deleted.
Reviewer notes
Field naming. The issue said "or similarly named". totalSettledAmount and
totalFeesCollected were chosen to pair readably with the existing
totalLiquidity. If the team prefers something more explicit about the status
filter, such as totalExecutedAmount, the rename is mechanical and I can push
it on request.
Placement. As noted in Design notes, the aggregation currently lives in the
route. Say the word and it moves into SettlementService.
Precision. amount and fee are plain numbers in the existing model, and these
sums inherit that. No change in precision behaviour is introduced by this PR,
but at very large volumes a shared integer/BigInt strategy across the codebase
would be the correct follow-up. Out of scope here.
================================================================================
HOW TO PUSH AND OPEN THIS PR
This sandbox has no GitHub credentials and no gh CLI, so the branch could not be
pushed from here. The commit is ready locally at /home/user/AnchorNet-Backend on
branch fix/metrics-settled-totals.
Option A - GitHub CLI
Option B - Web UI
Note: if you push from a fork rather than from Mitch5000/AnchorNet-Backend
directly, change the remote first:
================================================================================
Closes #146