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

## [Unreleased]

### Added

- Add optional `PerpsAccountSigner.getChainId`. When set, HyperLiquid user-signed actions (builder fee approval, withdrawals, transfers) are signed for the chain it returns instead of chain 1, so a wallet that only signs for its connected chain does not switch chains ([#10643](https://github.com/MetaMask/core/pull/10643))

### Changed

- **BREAKING:** `OrderFill.pnl` is optional when the venue omits realized PnL. Consumers must preserve missing amounts as unknown when aggregating or displaying fills; only a reported `'0'` is zero ([#10605](https://github.com/MetaMask/core/pull/10605))
- `HyperLiquidProvider.getExchangeClient` initializes the provider's SDK clients before returning the exchange client, so it signs L1 actions with the provider's agent ([#10643](https://github.com/MetaMask/core/pull/10643))

### Fixed

- Accept Lighter trades that omit position-sign flags, preserve omitted account PnL as unknown, and reject known reductions without realized PnL. Retain side-only fill directions when lifecycle context is ambiguous ([#10605](https://github.com/MetaMask/core/pull/10605))
- Detect a revoked or expired HyperLiquid agent that the venue answers with "Must deposit before performing actions" ([#10643](https://github.com/MetaMask/core/pull/10643))
- The provider then checks `extraAgents` for the agent that signed the answered request. When it is missing or past its `validUntil`, the write fails with `KEYRING_LOCKED`, the agent is dropped and `onAgentRejected` is called. Requests signed by the main account, or by a wallet of an earlier network or session, are not checked
- When the agent is still listed (an account with no funds), or the list cannot be read, the venue error is returned as before
- Sign a HyperLiquid L1 action the SDK queued before a network switch with the agent of the network it was queued on, not the new network's ([#10643](https://github.com/MetaMask/core/pull/10643))
- Attribute a HyperLiquid "User or API Wallet ... does not exist" rejection to the network of the request it answers, so an agent used on both networks is dropped, and `onAgentRejected` called, only for that network ([#10643](https://github.com/MetaMask/core/pull/10643))
- Stop asking again for a HyperLiquid builder fee approval the venue refused for a reason signing again cannot fix, such as "Builder has insufficient balance to be approved" ([#10643](https://github.com/MetaMask/core/pull/10643))
- Until the provider disconnects, the approval is not requested again: orders are sent as after any failed approval, TP/SL updates fail with `TPSL_UPDATE_FAILED`, and `prepareTradingWallet` returns the venue error
- Stop reporting HyperLiquid WebSocket transport failures (a closed or terminated socket, request timeout or abort) during the unified-account setup as errors ([#10651](https://github.com/MetaMask/core/pull/10651))
- After such a failure, provider entry waits one minute before running the setup again instead of retrying every time; `reconnect()` or `disconnect()` ends the wait, and trading and withdraw still run the setup
- Venue rejections, signing failures and other setup errors are still reported
Expand Down
13 changes: 9 additions & 4 deletions packages/perps-controller/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,11 @@ increase or reduce the existing position.

By default the controller signs through the `KeyringController:*` messenger
actions. A client without a keyring passes `accountSigner` in its platform
dependencies (`signTypedData`, `signPersonalMessage`, optional `isReady` and
`requiresSignatureConfirmation`); the signing address still comes from the
selected account, and a signer that is not ready fails with `KEYRING_LOCKED`.
dependencies (`signTypedData`, `signPersonalMessage`, optional `isReady`,
`requiresSignatureConfirmation` and `getChainId`); the signing address still
comes from the selected account, and a signer that is not ready fails with
`KEYRING_LOCKED`. HyperLiquid user-signed actions are signed for the chain
`getChainId` returns, or for chain 1 without it.

HyperLiquid L1 actions (orders, cancels, leverage, ...) can be signed by a
client-owned agent key: return it from
Expand All @@ -81,7 +83,10 @@ account and network with `PerpsController:setAgentSigner`. User-signed actions
(builder fee, withdrawals) stay on the main account, and approving the agent
is the client's job. When the venue rejects an agent (revoked or expired), the
write fails with `KEYRING_LOCKED`, the agent is dropped and
`providerCredentials.hyperliquid.onAgentRejected` is called. Call
`providerCredentials.hyperliquid.onAgentRejected` is called. A "Must deposit
before performing actions" answer to a request the agent signed counts as a
rejection only when `extraAgents` no longer lists the agent, which needs a
named agent. Call
`PerpsController:clearAgentSigners` when the agent key locks.

`PerpsController:prepareTradingWallet` runs the setup that needs signatures
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,10 @@ export type PerpsControllerClearAgentSignersAction = {
* - `NO_ACCOUNT_SELECTED` when no account is selected;
* - `PROVIDER_LIFECYCLE_STALE` when the provider disconnected or the account
* changed during setup;
* - the venue's message when HyperLiquid refused the builder fee approval
* for a reason signing again cannot fix (for example "Builder has
* insufficient balance to be approved"); it is not logged, and the
* approval is not asked for again until the provider disconnects;
* - otherwise the message of the error that stopped setup, which is logged.
* @throws Like the other provider-backed actions, `CLIENT_NOT_INITIALIZED`
* before `init`, and `CLIENT_REINITIALIZING` or `PROVIDER_NOT_AVAILABLE`
Expand Down
4 changes: 4 additions & 0 deletions packages/perps-controller/src/PerpsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6091,6 +6091,10 @@ export class PerpsController extends BaseController<
* - `NO_ACCOUNT_SELECTED` when no account is selected;
* - `PROVIDER_LIFECYCLE_STALE` when the provider disconnected or the account
* changed during setup;
* - the venue's message when HyperLiquid refused the builder fee approval
* for a reason signing again cannot fix (for example "Builder has
* insufficient balance to be approved"); it is not logged, and the
* approval is not asked for again until the provider disconnects;
* - otherwise the message of the error that stopped setup, which is logged.
* @throws Like the other provider-backed actions, `CLIENT_NOT_INITIALIZED`
* before `init`, and `CLIENT_REINITIALIZING` or `PROVIDER_NOT_AVAILABLE`
Expand Down
Loading
Loading