Skip to content

CP-14881: add adjust margin (add/remove) to isolated perps positions - #4010

Open
bogdandobritoiu wants to merge 2 commits into
mainfrom
CP-14881
Open

CP-14881: add adjust margin (add/remove) to isolated perps positions#4010
bogdandobritoiu wants to merge 2 commits into
mainfrom
CP-14881

Conversation

@bogdandobritoiu

@bogdandobritoiu bogdandobritoiu commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Description

Ticket: CP-14881

Adds the Adjust margin flow for isolated perps positions (Figma), mirroring core-web's AdjustMarginModal.

  • Entry point: a new "Margin" row on the Manage position screen showing the live marginUsed, rendered only for isolated positions (cross positions share account-wide collateral). Drills into /perpetualsManage/adjustMargin.
  • New PerpetualsAdjustMarginScreen: Add/Remove segmented toggle, amount input with 25%/50%/100% presets of the active mode's max, details rows (current margin, margin available to add/remove, liquidation price with a live current → projected preview), and a Confirm gated by the enable-trading flow. Submits a signed USD delta via the previously unused updateIsolatedMargin (positive adds, negative removes). The position re-resolves live over WS while the sheet is open.
  • Domain math (ported from core-web into utils/economics.ts, unit-tested):
    • maxRemovableMarginUsd — Hyperliquid's transfer floor max(notional/setLeverage, 0.1·notional), unrealized PnL counted toward equity, 2% price-drift cushion, capped at deposited margin (prevents HL's "insufficient margin for reduction" reject).
    • estimateLiquidationPriceFromMargin — margin-based liquidation estimate for the projection.
    • floorToDecimals — the 100% preset can never round up past the true cap.
  • k2-alpine:
    • TokenUnitInputWidget presets support percent (fraction of the live balance, resolved at press time so they track balance updates); percentage presets no-op at zero max instead of writing a literal "0".
    • SegmentedControl gains an optional height prop.
  • Zero-max states are explained in the caption (danger color): "No balance available to add" / "No margin available to remove" (a fresh isolated position sits exactly at HL's required margin — only added-on-top margin or unrealized profit is removable).
  • Misc: Market/Limit close on the expanded position card use SplitButton; padding fixes on the Balance/Withdraw loading and error states.

No new dependencies.

Screenshots/Videos

TODO: add iOS/Android screenshots and recording.

Testing

Dev Testing

Happy path:

  1. Open an isolated position (place order with margin mode Isolated), go to Positions → expand → Manage.
  2. A "Margin" row shows the position's current margin → tap it.
  3. Add: with free account collateral available, enter an amount (or tap 25/50/100%) — the liquidation price shows current → projected (green), Confirm submits, snackbar "Margin updated", Manage margin row and liq price update.
  4. Remove: after adding margin on top, switch to Remove — ~98% of the added margin is offered; projected liq price shows in red; Confirm returns the margin.

Edge cases:

  • Cross position → no Margin row on Manage.
  • Zero free collateral → Add shows "No balance available to add" (red), presets no-op, Confirm disabled.
  • Fresh isolated position at set leverage → Remove shows "No margin available to remove" (red) — expected per HL margining rules (matches core-web / HL app).
  • Amount above max → red error caption + Confirm disabled.
  • Trading not enabled → Confirm opens the enable-trading sheet first.

Bitrise: iOS - 9405 / Android - 9405

QA Testing

  • Verify add/remove margin on an isolated position updates the position's margin and liquidation price on Hyperliquid (cross-check with app.hyperliquid.xyz).
  • Verify the projected liquidation price approximates HL's posted value after confirm (small drift from funding/fees is expected).
  • Verify removal is capped: attempting to remove more than the offered max is blocked client-side; the 100% preset never triggers an HL "insufficient margin for reduction" reject.

Checklist

Please check all that apply (if applicable)

  • I have performed a self-review of my code
  • I have verified the code works
  • I have included screenshots / videos of android and ios
  • I have added testing steps
  • I have added/updated necessary unit tests
  • I have updated the documentation

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings July 23, 2026 20:43
@bogdandobritoiu
bogdandobritoiu marked this pull request as draft July 23, 2026 20:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an Adjust margin modal flow for isolated perpetuals positions in core-mobile, including UI entry points from the Manage position screen and new economics utilities (ported from core-web) to compute removable margin and margin-based liquidation estimates. It also extends k2-alpine input presets/segmented control to support the new UI requirements.

Changes:

  • Add isolated-position “Margin” entry point on Manage screen and a new PerpetualsAdjustMarginScreen modal to add/remove isolated margin.
  • Port/introduce perps economics helpers (maxRemovableMarginUsd, estimateLiquidationPriceFromMargin, floorToDecimals) with unit tests.
  • Extend k2-alpine TokenUnitInputWidget presets to support percent-of-live-balance presets and SegmentedControl to accept a custom height.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/k2-alpine/src/components/TokenUnitInput/TokenUnitInputWidget.tsx Adds percent-based presets resolved against live balance; includes zero-max no-op behavior.
packages/k2-alpine/src/components/SegmentedControl/SegmentedControl.tsx Adds optional height prop for custom segment row height.
packages/core-mobile/app/new/routes/(signedIn)/(modals)/perpetualsManage/adjustMargin.tsx Expo Router entrypoint exporting the new Adjust Margin screen.
packages/core-mobile/app/new/routes/(signedIn)/(modals)/perpetualsManage/_layout.tsx Registers the adjustMargin modal route in the perps manage stack.
packages/core-mobile/app/new/features/trade/perpetuals/utils/economics.ts Adds economics helpers for removable margin, liquidation estimate from margin, and safe flooring.
packages/core-mobile/app/new/features/trade/perpetuals/utils/economics.test.ts Adds unit tests covering the new economics helpers.
packages/core-mobile/app/new/features/trade/perpetuals/screens/PerpetualsWithdrawScreen.tsx Adds padding for loading/error modal states.
packages/core-mobile/app/new/features/trade/perpetuals/screens/PerpetualsManageScreen.tsx Adds isolated-only Margin row showing live marginUsed and navigation to Adjust Margin.
packages/core-mobile/app/new/features/trade/perpetuals/screens/PerpetualsBalanceScreen.tsx Adds padding for loading/error modal states.
packages/core-mobile/app/new/features/trade/perpetuals/screens/PerpetualsAdjustMarginScreen.tsx Implements the Adjust Margin modal UI + submission via updateIsolatedMargin.
packages/core-mobile/app/new/features/trade/perpetuals/components/PositionCard.tsx Uses SplitButton for Market/Limit close actions in expanded position card.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/k2-alpine/src/components/TokenUnitInput/TokenUnitInputWidget.tsx Outdated
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

Coverage report ✅

2/2 packages passed thresholds
Thresholds are shown inline against each package baseline.

🟢 @avalabs/core-mobile

St. Category Percentage Covered / Total
🟢 Statements 27.84% (+9.84% vs 18% ▲) 12340/44319
🟢 Branches 23.50% (+11.50% vs 12% ▲) 6058/25778
🟢 Functions 22.11% (+9.11% vs 13% ▲) 2264/10237
🟢 Lines 27.92% (+9.92% vs 18% ▲) 11817/42322

🟢 @avalabs/k2-alpine

St. Category Percentage Covered / Total
🟢 Statements 8.49% (+6.49% vs 2% ▲) 304/3580
🟢 Branches 7.88% (+6.88% vs 1% ▲) 172/2181
🟢 Functions 4.99% (+3.99% vs 1% ▲) 41/821
🟢 Lines 7.82% (+5.82% vs 2% ▲) 257/3285
Artifacts and threshold sources
  • @avalabs/core-mobile: summary core-mobile/coverage/coverage-summary.json, thresholds core-mobile/coverage-thresholds.json
  • @avalabs/k2-alpine: summary k2-alpine/coverage/coverage-summary.json, thresholds k2-alpine/coverage-thresholds.json

Source run: Mobile PR

- remove-mode caption shows the removable max, not account balance
- TokenUnitInputWidget: percent presets take precedence over value (per docs), zero no-op scoped to percent presets
- floorToDecimals: clamp decimals to a safe non-negative integer

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bogdandobritoiu
bogdandobritoiu marked this pull request as ready for review July 24, 2026 12:27
Copilot AI review requested due to automatic review settings July 24, 2026 12:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Comment on lines +148 to +152
const safeDecimals = Number.isFinite(decimals)
? Math.max(0, Math.trunc(decimals))
: 0
const factor = 10 ** safeDecimals
return Math.max(0, Math.floor(value * factor) / factor)
Comment on lines +261 to +270
<SplitButton
left={{
children: 'Market close',
onPress: handleMarketClose
}}
right={{
children: 'Limit close',
onPress: handleLimitClose
}}
/>
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.

2 participants