Commit 32eabc9
feat(perps): margin adjustment matching hyperliquid computation (MetaMask#23467)
## **Description**
This PR adds margin adjustment UI improvements and fixes the max
removable margin calculation to match Hyperliquid's official
documentation.
**What changed:**
### UI Improvements
- Added two new i18n strings: `margin_available_to_add` and
`margin_available_to_remove`
- Added a new info row in the adjust margin view that displays the
maximum amount of margin that can be added or removed
- Updated the first row to always show "Current margin" (previously
showed "Perps balance" for add mode)
- Re-enabled "Reduce Margin" action in the action sheet (was previously
disabled pending calculation fix)
### Max Removable Margin Calculation Fix
- Fixed `calculateMaxRemovableMargin` to use position's actual leverage
instead of asset's max leverage
- Formula now matches Hyperliquid's official documentation exactly:
`transfer_margin_required = max(notional/leverage, notional*0.1)`
- Removed excessive 3x safety buffer that was causing incorrect
calculations
- Added `unrealizedPnl` parameter for more accurate effective margin
calculation
**Root cause:** The calculation was using `maxLeverage` (asset's max,
e.g., 50x) instead of `position.leverage.value` (actual position
leverage, e.g., 10x). This caused significant discrepancies - a position
at 10x leverage requires 10% initial margin, not 2% that 50x would
imply.
The info section now displays four rows:
1. Current margin (always shows the margin in position)
2. Margin available to add/remove (shows max amount based on mode)
3. Liquidation price (with transition arrow when adjusting)
4. Liquidation distance (with transition arrow when adjusting)
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes: https://consensyssoftware.atlassian.net/browse/TAT-2167
## **Manual testing steps**
```gherkin
Feature: Margin adjustment with correct calculations
Scenario: User views margin available to add
Given user has an open perpetual position
And user navigates to the position details
When user taps "Adjust Margin"
And user selects "Add Margin"
Then user sees "Current margin" row with current margin value
And user sees "Margin available to add" row with available balance
Scenario: User views margin available to remove
Given user has an open perpetual position
And user navigates to the position details
When user taps "Adjust Margin"
And user selects "Reduce Margin"
Then user sees "Current margin" row with current margin value
And user sees "Margin available to remove" row with max removable margin
Scenario: Max removable margin matches Hyperliquid
Given user has an isolated position with known values
And user compares max removable in MetaMask vs Hyperliquid UI
When the values match (or are very close)
And user attempts to remove the displayed max amount
Then the transaction succeeds without rejection
```
## **Screenshots/Recordings**
### **Before**
The info section only showed:
- Perps balance (add mode) / Margin in position (remove mode)
- Liquidation price
- Liquidation distance
<img width="420" height="876" alt="image"
src="https://github.com/user-attachments/assets/96364845-73bd-4dff-8712-db21afbffde5"
/>
### **After**
The info section now shows:
- Current margin (both modes)
- Margin available to add (add mode) / Margin available to remove
(remove mode)
- Liquidation price
- Liquidation distance
<img width="414" height="830" alt="image"
src="https://github.com/user-attachments/assets/4ce0decd-7a88-45ee-ab65-3a1d1f4cb67f"
/>
<img width="425" height="822" alt="image"
src="https://github.com/user-attachments/assets/e5596180-37d5-4340-a984-222c9af958c9"
/>
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Refactors adjust margin to a new live-data hook and fixes max
removable margin per Hyperliquid, updates UI (current/max rows),
re-enables reduce action, and adds tests/docs.
>
> - **Logic/Calculations**:
> - **New hook** `usePerpsAdjustMarginData`: centralizes live
position/account/price data and computes `maxAmount`, liquidation
price/distance, and mode; exported via `hooks/index`.
> - **Fix** `calculateMaxRemovableMargin`: use `positionLeverage` (not
asset max), accept optional `notionalValue`, rely on mark price, remove
inflated safety buffer; update related tests.
> - **UI**:
> - **PerpsAdjustMarginView**: refactor to use new hook; remove
manual/live hooks and inline calcs; pass loading state; floor values to
2 decimals; clamp inputs; slider `maximumValue` uses floored
`maxAmount`.
> - **Info rows**: always show `margin_in_position`; add
`margin_available_to_add/remove`; keep liquidation price/distance with
transition.
> - **Action Sheet**: re-enable `reduce_margin` option.
> - **Tests/Docs**:
> - Add tests for new hook and update view/utils tests to new behavior.
> - Add doc `docs/perps/hyperliquid/margining.md` describing margin
rules.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
bf29e8d. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Signed-off-by: dan437 <80175477+dan437@users.noreply.github.com>
Co-authored-by: Nick Gambino <35090461+gambinish@users.noreply.github.com>
Co-authored-by: javiergarciavera <76975121+javiergarciavera@users.noreply.github.com>
Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
Co-authored-by: sethkfman <10342624+sethkfman@users.noreply.github.com>
Co-authored-by: Jorge Carrasco <jorge.carrasco@consensys.net>
Co-authored-by: Vinicius Stevam <45455812+vinistevam@users.noreply.github.com>
Co-authored-by: Alejandro Garcia Anglada <aganglada@gmail.com>
Co-authored-by: Daniel <80175477+dan437@users.noreply.github.com>
Co-authored-by: Juanmi <95381763+juanmigdr@users.noreply.github.com>
Co-authored-by: Matthew Grainger <46547583+Matt561@users.noreply.github.com>
Co-authored-by: Salim TOUBAL <salim.toubal@outlook.com>
Co-authored-by: CW <chris.wilcox@consensys.net>
Co-authored-by: George Marshall <george.marshall@consensys.net>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Kevin Bluer <kevin@bluer.com>
Co-authored-by: Michele Esposito <34438276+mikesposito@users.noreply.github.com>
Co-authored-by: Pedro Pablo Aste Kompen <wachunei@gmail.com>
Co-authored-by: Kylan Hurt <6249205+smilingkylan@users.noreply.github.com>
Co-authored-by: Brian August Nguyen <brianacnguyen@gmail.com>
Co-authored-by: Vince Howard <vincenguyenhoward@gmail.com>
Co-authored-by: Curtis David <Curtis.David7@gmail.com>
Co-authored-by: Bryan Fullam <bryan.fullam@consensys.net>
Co-authored-by: Monte Lai <monte.lai@consensys.net>
Co-authored-by: Charly Chevalier <charlyy.chevalier@gmail.com>
Co-authored-by: Patryk Łucka <5708018+PatrykLucka@users.noreply.github.com>
Co-authored-by: Goktug Poyraz <omergoktugpoyraz@gmail.com>
Co-authored-by: Michal Szorad <michal.szorad@consensys.net>
Co-authored-by: Nicholas Smith <nick.smith@consensys.net>
Co-authored-by: Matthew Walsh <matthew.walsh@consensys.net>
Co-authored-by: Bruno Nascimento <brunonascimentodev@gmail.com>
Co-authored-by: cmd-ob <ola.bale@consensys.net>
Co-authored-by: AxelGes <34173844+AxelGes@users.noreply.github.com>
Co-authored-by: George Weiler <georgejweiler@gmail.com>
Co-authored-by: Owen Craston <owen.craston@consensys.net>
Co-authored-by: Prithpal Sooriya <prithpal.sooriya@consensys.net>
Co-authored-by: Caainã Jeronimo <caainaje@gmail.com>
Co-authored-by: Nicholas Gambino <nicholas.gambino@consensys.net>
Co-authored-by: VGR <VanGulckRik@gmail.com>
Co-authored-by: Daniel Suchý <suchydan@gmail.com>
Co-authored-by: Nicholas Ellul <15018469+NicholasEllul@users.noreply.github.com>
Co-authored-by: Harika <153644847+hjetpoluru@users.noreply.github.com>
Co-authored-by: Maarten Zuidhoorn <maarten@zuidhoorn.com>
Co-authored-by: jvbriones <1674192+jvbriones@users.noreply.github.com>
Co-authored-by: Christopher Ferreira <104831203+christopherferreira9@users.noreply.github.com>
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
Co-authored-by: António Regadas <antonio.regadas@consensys.net>
Co-authored-by: Baptiste Marchand <75846779+baptiste-marchand@users.noreply.github.com>
Co-authored-by: Cal Leung <cal.leung@consensys.net>
Co-authored-by: sophieqgu <37032128+sophieqgu@users.noreply.github.com>
Co-authored-by: George Gkasdrogkas <georgegkas@gmail.com>
Co-authored-by: ffmcgee <51971598+ffmcgee725@users.noreply.github.com>
Co-authored-by: Luis Taniça <matallui@gmail.com>
Co-authored-by: Guillaume Roux <guillaumeroux123@gmail.com>
Co-authored-by: Priya <priya.narayanaswamy@consensys.net>
Co-authored-by: sahar-fehri <sahar.fehri@consensys.net>
Co-authored-by: Ulisses Ferreira <ulisses@hey.com>
Co-authored-by: imblue <106779544+imblue-dabadee@users.noreply.github.com>
Co-authored-by: Amélie <amelie.chan@gmail.com>
Co-authored-by: asalsys <sallem.ahmed@consensys.net>
Co-authored-by: SteP-n-s <stylianos.panagakos@consensys.net>
Co-authored-by: tommasini <46944231+tommasini@users.noreply.github.com>
Co-authored-by: Bernardo Garces Chapero <bernardo.chapero@consensys.net>
Co-authored-by: Gaurav Goel <grvgoel19@gmail.com>
Co-authored-by: Frederik Bolding <frederik.bolding@gmail.com>
Co-authored-by: jiexi <jiexiluan@gmail.com>
Co-authored-by: khanti42 <florin.dzeladini@consensys.net>
Co-authored-by: Ramon AC <36987446+racitores@users.noreply.github.com>
Co-authored-by: ieow <4881057+ieow@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Andre Pimenta <andrepimenta7@gmail.com>
Co-authored-by: infiniteflower <139582705+infiniteflower@users.noreply.github.com>1 parent e545385 commit 32eabc9
9 files changed
Lines changed: 952 additions & 300 deletions
File tree
- app/components/UI/Perps
- Views/PerpsAdjustMarginView
- components/PerpsAdjustMarginActionSheet
- hooks
- utils
- docs/perps/hyperliquid
Lines changed: 79 additions & 30 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
47 | | - | |
| 46 | + | |
48 | 47 | | |
49 | | - | |
50 | | - | |
51 | | - | |
52 | | - | |
53 | | - | |
54 | | - | |
55 | | - | |
56 | | - | |
57 | | - | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
58 | 51 | | |
59 | 52 | | |
60 | 53 | | |
61 | 54 | | |
62 | 55 | | |
63 | 56 | | |
64 | | - | |
65 | | - | |
66 | | - | |
67 | | - | |
68 | | - | |
69 | 57 | | |
70 | 58 | | |
71 | 59 | | |
| |||
167 | 155 | | |
168 | 156 | | |
169 | 157 | | |
170 | | - | |
171 | | - | |
172 | | - | |
173 | | - | |
174 | | - | |
175 | | - | |
176 | | - | |
177 | | - | |
178 | | - | |
179 | | - | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
180 | 173 | | |
181 | 174 | | |
182 | 175 | | |
| |||
200 | 193 | | |
201 | 194 | | |
202 | 195 | | |
203 | | - | |
| 196 | + | |
204 | 197 | | |
205 | 198 | | |
206 | 199 | | |
207 | | - | |
| 200 | + | |
208 | 201 | | |
| 202 | + | |
209 | 203 | | |
210 | 204 | | |
211 | 205 | | |
212 | | - | |
| 206 | + | |
213 | 207 | | |
214 | 208 | | |
215 | 209 | | |
| |||
243 | 237 | | |
244 | 238 | | |
245 | 239 | | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
246 | 257 | | |
247 | 258 | | |
248 | 259 | | |
| |||
253 | 264 | | |
254 | 265 | | |
255 | 266 | | |
256 | | - | |
| 267 | + | |
257 | 268 | | |
258 | 269 | | |
259 | 270 | | |
260 | 271 | | |
261 | 272 | | |
262 | 273 | | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
263 | 278 | | |
264 | 279 | | |
265 | 280 | | |
| |||
291 | 306 | | |
292 | 307 | | |
293 | 308 | | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
294 | 326 | | |
295 | 327 | | |
296 | 328 | | |
| |||
358 | 390 | | |
359 | 391 | | |
360 | 392 | | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
361 | 410 | | |
362 | 411 | | |
363 | 412 | | |
| |||
0 commit comments