Add a `transfer liquidity fixed - #208
Merged
Jagadeeshftw merged 3 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 (PLAIN TEXT — paste into GitHub as-is)
TITLE
feat: add atomic liquidity transfer between anchors
(POST /api/v1/liquidity/transfer)
BODY
SUMMARY
Moving liquidity between two anchors previously required a withdraw
from one anchor followed by a separate add for the other. That two-call
flow was not atomic, was not auditable as a single logical operation,
and briefly reduced the total pool liquidity between the two calls.
This PR adds a dedicated transfer operation that performs both halves
atomically in memory: LiquidityService.transferLiquidity({ from, to,
asset, amount }) and a new POST /api/v1/liquidity/transfer endpoint.
Fixes the issue: "Add a dedicated transfer operation that performs both
halves atomically in memory."
WHAT CHANGED
New transferLiquidity(input: { from, to, asset, amount }) method.
It reuses the existing validation helpers (requireString,
normalizeAsset, requirePositiveNumber), checks that the source
anchor has sufficient balance, then atomically decrements the
source and increments the destination for the same asset. Returns
the resulting entries for both anchors as { from, to }.
New route POST /api/v1/liquidity/transfer. Responds 200 with
{ from, to }.
New OpenAPI path entry for /api/v1/liquidity/transfer.
8 new service-level tests (see Testing below).
6 new route-level tests (see Testing below).
Endpoint documentation for the new transfer route.
WHY IT IS ATOMIC
All validation that can throw runs before the first state mutation.
throws before any repository access.
INSUFFICIENT_LIQUIDITY, the exact same error code and message format
as withdrawLiquidity.
protects accounting, because source and destination share a
repository key and would otherwise be double-counted.
The two remaining steps (decrement source, increment destination) are
plain in-memory map writes that cannot fail for inputs that passed
validation, so the transfer is never partially applied: never debited
from the source without being credited to the destination, or vice
versa. Because the decrement always equals the increment, the asset's
pool total never dips mid-operation, so the liquidity available for
settlements is unchanged by construction and no reserved-liquidity
check is needed.
Both resulting entries share a single updatedAt timestamp, making the
transfer auditable as one logical operation.
When the full source balance is transferred, the source entry is
removed and returned with amount 0, mirroring withdrawLiquidity.
BEHAVIOR / API CONTRACT
Request:
Success response (200):
Error responses:
TESTING
New tests: 14 (8 service-level, 6 route-level).
Service tests cover:
balances and the pool total verified unchanged (atomicity criterion)
Route tests cover:
VALIDATION RESULTS
tests unaffected, 14 new tests all green).
and lines in liquidityService.ts and routes/liquidity.ts.
criterion: 200 success with the pool total never changing, 400
INSUFFICIENT_LIQUIDITY leaving both balances and the pool total
unchanged, 404 for an unknown source, 400 for self-transfer and
invalid bodies, and the new path present in GET /api/v1/openapi.json.
ACCEPTANCE CRITERIA
anchors for the same asset in a single atomic operation.
destination balances completely unchanged.
SECURITY NOTES
Atomicity prevents a partially-applied transfer (debited from source
but not credited to destination, or vice versa) from corrupting total
pool accounting. The 400 SAME_ANCHOR guard closes the one edge case
where in-place math on a shared repository key could create liquidity
out of thin air.
FILES CHANGED (6 modified, 0 created)
BRANCH AND COMMIT
(AnchorNet-Org/AnchorNet-Backend, or the Mitch5000 fork's main)
HOW TO OPEN THIS PR
This workspace has no GitHub credentials, so run the following from a
clone that does. The branch and commit are already prepared:
then either:
or open https://github.com/Mitch5000/AnchorNet-Backend/compare,
select the feat/liquidity-transfer branch, and paste the TITLE and
BODY sections from this file into the pull request form.
Closes #155