Skip to content

Commit 4b26130

Browse files
authored
feat: Perps max order error messaging (#20559)
## **Description** Hyperliquid contracts have limitations on the amount of margin for each token Contract specs: https://hyperliquid.gitbook.io/hyperliquid-docs/trading/contract-specifications Market orders: $15,000,000 for max leverage >= 25 $5,000,000 for max leverage in [20, 25) $2,000,000 for max leverage in [10, 20) otherwise $500,000 Limit orders: 10 * maximum market order value ## **Changelog** CHANGELOG entry: Add max order error messaging ## **Related issues** Fixes: ## **Manual testing steps** Best way to test this is by manually hardcoding available balance in `hyperLiquidAdapter` to `100000000` and then attempting to submit an order with max leverages that fit the above constraints. Not all perps have max 40x leverage. So you'll need to go through various perps to catch all cases. ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <img width="437" height="889" alt="Screenshot 2025-09-29 at 2 23 42 PM" src="https://github.com/user-attachments/assets/6e0ba540-3a35-4ef3-8311-16dda2295fc5" /> ## **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] > Adds leverage-based max order value checks for HyperLiquid orders, with new constants, validation logic, tests, and localized error messaging. > > - **Perps Validation**: > - Add `getMaxOrderValue(maxLeverage, orderType)` in `utils/hyperLiquidValidation.ts` to compute order value caps (limit = 10× market cap). > - Integrate max order value check in `HyperLiquidProvider.validateOrder` using `getMaxOrderValue` and `formatPerpsFiat`. > - **Constants**: > - Introduce `HYPERLIQUID_ORDER_LIMITS` in `constants/perpsConfig.ts` (market caps by leverage tier; limit multiplier = 10). > - **i18n**: > - Add `perps.order.validation.max_order_value` string in `en.json`. > - **Tests**: > - Expand `hyperLiquidValidation.test.ts` with comprehensive cases for `getMaxOrderValue` across leverage tiers, order types, and edge conditions. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 33d4511. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 7f0226e commit 4b26130

File tree

5 files changed

+434
-0
lines changed

5 files changed

+434
-0
lines changed

app/components/UI/Perps/constants/perpsConfig.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,26 @@ export const LIMIT_PRICE_CONFIG = {
141141
SHORT_PRESETS: [1, 2, 5, 10], // Sell above market for short orders
142142
} as const;
143143

144+
/**
145+
* HyperLiquid order limits based on leverage
146+
* From: https://hyperliquid.gitbook.io/hyperliquid-docs/trading/contract-specifications
147+
*/
148+
export const HYPERLIQUID_ORDER_LIMITS = {
149+
// Market orders
150+
MARKET_ORDER_LIMITS: {
151+
// $15,000,000 for max leverage >= 25
152+
HIGH_LEVERAGE: 15_000_000,
153+
// $5,000,000 for max leverage in [20, 25)
154+
MEDIUM_HIGH_LEVERAGE: 5_000_000,
155+
// $2,000,000 for max leverage in [10, 20)
156+
MEDIUM_LEVERAGE: 2_000_000,
157+
// $500,000 for max leverage < 10
158+
LOW_LEVERAGE: 500_000,
159+
},
160+
// Limit orders are 10x market order limits
161+
LIMIT_ORDER_MULTIPLIER: 10,
162+
} as const;
163+
144164
/**
145165
* Close position configuration
146166
* Controls behavior and constants specific to position closing

app/components/UI/Perps/controllers/providers/HyperLiquidProvider.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
} from '../../utils/hyperLiquidAdapter';
3535
import {
3636
createErrorResult,
37+
getMaxOrderValue,
3738
getSupportedPaths,
3839
validateAssetSupport,
3940
validateBalance,
@@ -42,6 +43,7 @@ import {
4243
validateOrderParams,
4344
validateWithdrawalParams,
4445
} from '../../utils/hyperLiquidValidation';
46+
import { formatPerpsFiat } from '../../utils/formatUtils';
4547
import { transformMarketData } from '../../utils/marketDataTransform';
4648
import type {
4749
AccountState,
@@ -1629,6 +1631,31 @@ export class HyperLiquidProvider implements IPerpsProvider {
16291631
};
16301632
}
16311633

1634+
// Validate order value against max limits
1635+
if (params.currentPrice && params.leverage) {
1636+
try {
1637+
const maxLeverage = await this.getMaxLeverage(params.coin);
1638+
1639+
const maxOrderValue = getMaxOrderValue(maxLeverage, params.orderType);
1640+
const orderValue = parseFloat(params.size) * params.currentPrice;
1641+
1642+
if (orderValue > maxOrderValue) {
1643+
return {
1644+
isValid: false,
1645+
error: strings('perps.order.validation.max_order_value', {
1646+
maxValue: formatPerpsFiat(maxOrderValue, {
1647+
minimumDecimals: 0,
1648+
maximumDecimals: 0,
1649+
}).replace('$', ''),
1650+
}),
1651+
};
1652+
}
1653+
} catch (error) {
1654+
DevLogger.log('Failed to validate max order value', error);
1655+
// Continue without max order validation if we can't get leverage
1656+
}
1657+
}
1658+
16321659
return { isValid: true };
16331660
} catch (error) {
16341661
return {

0 commit comments

Comments
 (0)