Skip to content

Exchange endpoint userPortfolioMargin, info endpoint exchangeStatus - #155

Merged
TuxedoFish merged 2 commits into
mainfrom
endpoint/portfolio-margin-exchange-status
Sep 8, 2026
Merged

Exchange endpoint userPortfolioMargin, info endpoint exchangeStatus#155
TuxedoFish merged 2 commits into
mainfrom
endpoint/portfolio-margin-exchange-status

Conversation

@TuxedoFish

@TuxedoFish TuxedoFish commented Sep 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds exchangeStatus - a no-argument /info endpoint returning operational status (RestApi::exchangeStatus, WebsocketApi::exchangeStatus).
  • Adds userPortfolioMargin - an EIP-712 user-signed /exchange action toggling portfolio margin mode (RestApi::userPortfolioMargin, WebsocketApi::userPortfolioMargin).
  • Follows CONTRIBUTING.md's repeatable patterns for both endpoint kinds (request/response types, builder, parser, listener callbacks, RestApi/WebsocketApi methods, tests, README coverage tables, examples).

Closes #128
Closes #129

Verification notes - both endpoints now confirmed live

exchangeStatus: ran curl -X POST .../info -d '{"type":"exchangeStatus"}' against both api.hyperliquid-testnet.xyz and api.hyperliquid.xyz. Both returned the identical shape:

{"specialStatuses":null,"time":1788859210259}

specialStatuses was null in both captures. Its element shape when non-null is inferred, not confirmed - assumed to be an array of strings by analogy with every other "list of status/message" field in this API (e.g. ApprovedBuildersResponse). time is a raw (non-string-encoded) millisecond timestamp, parsed via get_uint64().

userPortfolioMargin: ran both directions live against testnet with a real signed request from this repo's test wallet:

action: {"type":"userPortfolioMargin","user":"0x6829Fdea522a6Fc3697311d2Ab93414BAd4b0C55","enabled":true,...}
response: status=err, error="Portfolio margin requires account value of $10000 or total volume of $5000000."

action: {"type":"userPortfolioMargin","user":"0x6829Fdea522a6Fc3697311d2Ab93414BAd4b0C55","enabled":false,...}
response: status=ok, type=default

The enabled=true request was accepted and parsed by the server, then rejected on a genuine business rule (this wallet's account value/volume) - not a schema error, confirming the EIP-712 action shape (type/user/enabled, HyperliquidTransaction:UserPortfolioMargin) is correct. The enabled=false request (disabling an already-disabled setting, a no-op) actually succeeded end-to-end - a full confirmed round trip, not just a business-rule rejection. tests/user_portfolio_margin_test.cpp's success/error fixtures now use these real captures instead of the TS-SDK-inferred ones (the success shape happened to already match exactly; the error message did not, and has been corrected to the real wording).

Test plan

🤖 Generated with Claude Code

https://claude.ai/code/session_018Le73N2EZjGLsCqmCScAse

@codecov

codecov Bot commented Sep 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 79.57746% with 29 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.17%. Comparing base (cec0144) to head (6ee2f81).

Files with missing lines Patch % Lines
src/rest/RestApi.cpp 0.00% 12 Missing ⚠️
src/websocket/WebsocketApi.cpp 0.00% 7 Missing ⚠️
src/rest/RestApiMessageParser.cpp 85.00% 3 Missing ⚠️
src/websocket/PostResponseDispatch.cpp 0.00% 3 Missing ⚠️
include/hyperliquid/types/RequestTypes.h 50.00% 2 Missing ⚠️
include/hyperliquid/rest/RestEndpointListener.h 0.00% 1 Missing ⚠️
...clude/hyperliquid/websocket/WebsocketApiListener.h 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #155      +/-   ##
==========================================
+ Coverage   70.02%   70.17%   +0.15%     
==========================================
  Files          53       54       +1     
  Lines        8640     8782     +142     
  Branches      533      534       +1     
==========================================
+ Hits         6050     6163     +113     
- Misses       2587     2616      +29     
  Partials        3        3              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions github-actions Bot added the ready for review CI passed; ready to be reviewed label Sep 8, 2026
exchangeStatus: no-argument /info endpoint returning operational status
(specialStatuses, time). Response shape confirmed live against both
api.hyperliquid-testnet.xyz/info and api.hyperliquid.xyz/info
({"specialStatuses":null,"time":<ms>}); specialStatuses' element shape
when non-null is inferred (assumed array of strings), never observed live.

userPortfolioMargin: EIP-712 user-signed /exchange action (user, enabled)
toggling portfolio margin mode, modeled directly on the existing
userDexAbstraction/userSetAbstraction pattern. Request shape cross-checked
against nktkas/hyperliquid's userPortfolioMargin.ts; the generic
{status,response} response shape is inferred from that same source and
from the shape shared by every other simple exchange action - not
independently confirmed against a live response (no funded testnet wallet
available in this environment).

Both endpoints get RestApi and WebsocketApi methods, request-builder and
response-parser tests, an example, and README coverage table updates.

Closes #128, #129

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Le73N2EZjGLsCqmCScAse
@TuxedoFish
TuxedoFish force-pushed the endpoint/portfolio-margin-exchange-status branch from fc3e5de to 3d443a3 Compare September 8, 2026 13:31
Replaces the TS-SDK-inferred success fixture (which happened to
already match) and the placeholder error message with real testnet
responses: enabling failed with a genuine business-rule error on this
test wallet, disabling (a no-op, already off) succeeded.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Le73N2EZjGLsCqmCScAse
@TuxedoFish
TuxedoFish merged commit 9869c9e into main Sep 8, 2026
12 checks passed
@TuxedoFish
TuxedoFish deleted the endpoint/portfolio-margin-exchange-status branch September 8, 2026 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready for review CI passed; ready to be reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement exchangeStatus Implement userPortfolioMargin

1 participant