Skip to content
Open
4 changes: 4 additions & 0 deletions packages/perps-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add `getAccountSupport` to the controller, messenger, and optional provider contract. Hyperliquid detects native multi-signature accounts, caches successful checks per account/network session, and blocks exchange mutations for unsupported accounts. Transient detection failures remain retryable, authoritative exchange rejections correct cached support, and actions reject stale account, network, or provider contexts before signing. ([#10693](https://github.com/MetaMask/core/pull/10693))

### Changed

- Bump `reselect` from `^5.1.1` to `^5.3.0` ([#10532](https://github.com/MetaMask/core/pull/10532))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,19 @@ export type PerpsControllerGetActiveProviderAction = {
handler: PerpsController['getActiveProvider'];
};

/**
* Return whether the selected account can submit actions through the active
* provider route. Providers without an account-support check remain
* supported for backward compatibility.
*
* @param params - Optional provider route.
* @returns The provider-owned account support result.
*/
export type PerpsControllerGetAccountSupportAction = {
type: `PerpsController:getAccountSupport`;
handler: PerpsController['getAccountSupport'];
};

/**
* Get the currently active provider, returning null if not available
* Use this method when the caller can gracefully handle a missing provider
Expand Down Expand Up @@ -1596,6 +1609,7 @@ export type PerpsControllerMethodActions =
| PerpsControllerGetUserDataSnapshotAction
| PerpsControllerInitAction
| PerpsControllerGetActiveProviderAction
| PerpsControllerGetAccountSupportAction
| PerpsControllerGetActiveProviderOrNullAction
| PerpsControllerGetOrderCapabilitiesAction
| PerpsControllerGetMarginModeLockAction
Expand Down
23 changes: 23 additions & 0 deletions packages/perps-controller/src/PerpsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ import type {
FlipPositionParams,
Funding,
GetAccountStateParams,
GetAccountSupportParams,
GetAvailableDexsParams,
GetFundingParams,
GetMarketDataWithPricesParams,
Expand Down Expand Up @@ -161,6 +162,7 @@ import type {
PerpsAgentSigner,
PerpsPlatformDependencies,
PerpsActiveProviderMode,
PerpsAccountSupport,
PerpsAnalyticsProperties,
PerpsAttributionContext,
PerpsProviderType,
Expand Down Expand Up @@ -976,6 +978,7 @@ const MESSENGER_EXPOSED_METHODS = [
'fetchHistoricalCandles',
'flipPosition',
'getAccountState',
'getAccountSupport',
'getActiveProvider',
'getActiveProviderOrNull',
'getAttributionContext',
Expand Down Expand Up @@ -2906,6 +2909,26 @@ export class PerpsController extends BaseController<
}
}

/**
* Return whether the selected account can submit actions through the active
* provider route. Providers without an account-support check remain
* supported for backward compatibility.
*
* @param params - Optional provider route.
* @returns The provider-owned account support result.
*/
async getAccountSupport(
params?: GetAccountSupportParams,
): Promise<PerpsAccountSupport> {
const provider = await this.#getActiveProviderWhenReady();
if (this.#hasConflictingProviderRoute(params?.providerId, provider)) {
throw new Error(PERPS_ERROR_CODES.PROVIDER_NOT_FOUND);
}
return provider.getAccountSupport
? provider.getAccountSupport(params)
: { isSupported: true };
}

/**
* Identify the account, network and provider an action runs under.
*
Expand Down
4 changes: 4 additions & 0 deletions packages/perps-controller/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export type {
PerpsControllerFetchHistoricalCandlesAction,
PerpsControllerFlipPositionAction,
PerpsControllerGetAccountStateAction,
PerpsControllerGetAccountSupportAction,
PerpsControllerGetActiveProviderAction,
PerpsControllerGetActiveProviderOrNullAction,
PerpsControllerGetAttributionContextAction,
Expand Down Expand Up @@ -323,6 +324,9 @@ export type {
PositionModifyPreviewNone,
FeeCalculationParams,
FeeCalculationResult,
GetAccountSupportParams,
PerpsAccountSupport,
PerpsAccountUnsupportedReason,
GetOrderCapabilitiesParams,
GetMarginModeLockParams,
MarginModeLockReason,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import type {
FeeCalculationResult,
Funding,
GetAccountStateParams,
GetAccountSupportParams,
GetAvailableDexsParams,
GetFundingParams,
GetHistoricalPortfolioParams,
Expand Down Expand Up @@ -74,6 +75,7 @@ import type {
OrderParams,
OrderResult,
PerpsMarketData,
PerpsAccountSupport,
PerpsOrderCapabilities,
PerpsMarginModeLock,
PerpsScalePriceLadder,
Expand Down Expand Up @@ -304,6 +306,22 @@ export class AggregatedPerpsProvider implements PerpsProvider {
return this.#getDefaultProvider().getWithdrawalRoutes(params);
}

/**
* Route account support through the same explicit-provider/default-provider
* selection used by writes.
*
* @param params - Optional provider route.
* @returns The selected provider's account support result.
*/
async getAccountSupport(
params?: GetAccountSupportParams,
): Promise<PerpsAccountSupport> {
const [, provider] = this.#getProviderOrDefault(params?.providerId);
return provider.getAccountSupport
? provider.getAccountSupport(params)
: { isSupported: true };
}

/**
* Resolve capabilities with the same explicit-provider/default-provider
* selection used by order placement. Unknown routes return a typed
Expand Down
Loading
Loading