### Patch Changes - [#460](https://github.com/lifinance/perps-sdk/pull/460) [`f22b4c3`](https://github.com/lifinance/perps-sdk/commit/f22b4c3c85932531c23b9dc6971e33e315a1d7be) Thanks [@aaronmboyd](https://github.com/aaronmboyd)! - Encode and decode the activity cursor with `btoa`/`atob` only. `encodeActivityCursor` and `decodeActivityCursor` took the Node `Buffer` path whenever a global `Buffer` existed. A wallet dependency installs the npm `buffer` polyfill as `window.Buffer` in the browser, and that polyfill has no `base64url` encoding, so `getActivity` threw `TypeError: Unknown encoding: ba
Patch Changes - #460 f22b4c3 Thanks @aaronmboyd! - Encode and decode the activity cursor with btoa/atob only. encodeActivityCursor and decodeActivityCursor took the Node Buffer path whenever a global Buffer existed. A wallet dependency installs the npm buffer polyfill as window.Buffer in the browser, and that polyfill has no base64url encoding, so getActivity threw `TypeError: Unknown encoding: ba
Minor Changes - #457 c5be9cb Thanks @aaronmboyd! - Add the optional getPortfolioHistory provider read and PerpsClient.getPortfolioHistory. The method returns the account value and the cumulative PnL over a 24h, 7d, 30d, or all window. @lifi/perps-types exports PortfolioHistoryRange, PortfolioHistoryPoint, and PortfolioHistoryResponse. The Hyperliquid, Ondo, and Lighter providers implement the read
Major Changes - #458 c71802b Thanks @aaronmboyd! - Report candle channel support on the WS provider factory. WsProviderFactory is now a callable interface with a required readonly streamsCandles: boolean. PerpsWsClient.streamsCandles(provider) returns that value synchronously. It returns false for a provider with no registered factory. The Hyperliquid and Ondo factories report true. The Lighter factory re
Major Changes - #458 c71802b Thanks @aaronmboyd! - Report candle channel support on the WS provider factory. WsProviderFactory is now a callable interface with a required readonly streamsCandles: boolean. PerpsWsClient.streamsCandles(provider) returns that value synchronously. It returns false for a provider with no registered factory. The Hyperliquid and Ondo factories report true. The Lighter factory re
Major Changes - #458 c71802b Thanks @aaronmboyd! - Report candle channel support on the WS provider factory. WsProviderFactory is now a callable interface with a required readonly streamsCandles: boolean. PerpsWsClient.streamsCandles(provider) returns that value synchronously. It returns false for a provider with no registered factory. The Hyperliquid and Ondo factories report true. The Lighter factory re
Major Changes - #458 c71802b Thanks @aaronmboyd! - Report candle channel support on the WS provider factory. WsProviderFactory is now a callable interface with a required readonly streamsCandles: boolean. PerpsWsClient.streamsCandles(provider) returns that value synchronously. It returns false for a provider with no registered factory. The Hyperliquid and Ondo factories report true. The Lighter factory re
Minor Changes - #454 7595dad Thanks @aaronmboyd! - Correct market open interest, funding times, and Ondo oracle prices. MarketContext.openInterest now states its unit: a quote-asset notional as a decimal string. The Hyperliquid provider converts the venue base-unit figure at the emitted mark price, and mapMarketContext takes the fastAssetCtxs context as a third argument so the notional and the mark come from th
Minor Changes - #455 79a5291 Thanks @aaronmboyd! - Add PerpsMarket.minOrderValueUsd and map Lighter's maker-only minimum order notional to it. PerpsMarket gains an optional minOrderValueUsd, a plain decimal string. Lighter applies the floor to resting (post-only) orders only. The field is per-market and is separate from the venue-wide Provider.minOrderValueUsd, which is a number. Breaking: `mapMarketOrd
Minor Changes - #454 7595dad Thanks @aaronmboyd! - Correct market open interest, funding times, and Ondo oracle prices. MarketContext.openInterest now states its unit: a quote-asset notional as a decimal string. The Hyperliquid provider converts the venue base-unit figure at the emitted mark price, and mapMarketContext takes the fastAssetCtxs context as a third argument so the notional and the mark come from th
Major Changes - #455 79a5291 Thanks @aaronmboyd! - Add PerpsMarket.minOrderValueUsd and map Lighter's maker-only minimum order notional to it. PerpsMarket gains an optional minOrderValueUsd, a plain decimal string. Lighter applies the floor to resting (post-only) orders only. The field is per-market and is separate from the venue-wide Provider.minOrderValueUsd, which is a number. Breaking: `mapMarketOrd
Patch Changes - #435 be8f9da Thanks @aaronmboyd! - Load the Lighter signer without JavaScript string evaluation. The browser CSP requires 'wasm-unsafe-eval', not 'unsafe-eval'. Go's runtime initializes only when the signer loads, so backend imports preserve host globals and allow later polyfill installation. CommonJS, ESM, and declaration outputs remain available.
Minor Changes - #450 c6b3bd7 Thanks @aaronmboyd! - The Lighter provider declares every account, position, and trade wire field that Lighter marks omitempty as an optional member. Each mapper supplies an explicit default for such a field. A position with no accrued funding, a Classic/Simple account, and a flat counterparty each produced undefined against a required contract field. The provider now emits the zero v
Major Changes - #444 76a9f3f Thanks @aaronmboyd! - The Lighter authentication rejections now carry Unauthorized instead of ThirdPartyError, so a consumer can detect a rejected or revoked token from the error code. Both a rejected token and a revoked token report the same Unauthorized code. The error classes stay internal, so a consumer cannot tell the two apart. Treat every Unauthorized from a Lighter read as
Major Changes - #446 050dcd3 Thanks @aaronmboyd! - Parse the venue error body at the Lighter and Ondo provider boundaries and map a recognised rejection to the matching PerpsErrorCode. A Lighter body code for a nonce, margin, or balance rejection now produces InvalidNonce, InsufficientMargin, or InsufficientBalance; an Ondo errorcode of insufficientmargin or clientOrderID_collision now produces `Ins
Minor Changes - #441 fa4ba25 Thanks @aaronmboyd! - Read Lighter orders through a single request and resolve an order by its client order index. getOrders with no marketId now issues one accountActiveOrders request with the venue's all-markets market_id, instead of one request per market that holds an order. getOrders with a marketId keeps its single filtered request. getOrder resolves an id prefixed wit
Major Changes - #439 80791fb Thanks @aaronmboyd! - Guard null wire lists in the Lighter provider, adopt the 2026-08-18 Lighter OpenAPI spec, and export a default market id per provider. Lighter serializes an empty REST list as JSON null. Every list the provider reads is now typed T[] | null and normalized to an array at the response boundary, so an account with no trades, deposits, withdrawals, funding rows, liqu
Minor Changes - #439 80791fb Thanks @aaronmboyd! - Guard null wire lists in the Lighter provider, adopt the 2026-08-18 Lighter OpenAPI spec, and export a default market id per provider. Lighter serializes an empty REST list as JSON null. Every list the provider reads is now typed T[] | null and normalized to an array at the response boundary, so an account with no trades, deposits, withdrawals, funding rows, liqu
Patch Changes - #436 f87ed41 Thanks @aaronmboyd! - The provider error boundaries now derive PerpsErrorCode from the HTTP status. A Hyperliquid /info failure carries RateLimitExceeded for a 429, Unauthorized for a 401 and AgentUnauthorized for a 403, and keeps ThirdPartyError for every other status. A LI.FI request with an unparseable body carries RateLimitExceeded for a 429 and keeps DefaultError for
Major Changes - #436 f87ed41 Thanks @aaronmboyd! - The provider error boundaries now derive PerpsErrorCode from the HTTP status. A Hyperliquid /info failure carries RateLimitExceeded for a 429, Unauthorized for a 401 and AgentUnauthorized for a 403, and keeps ThirdPartyError for every other status. A LI.FI request with an unparseable body carries RateLimitExceeded for a 429 and keeps DefaultError for
Major Changes - #436 f87ed41 Thanks @aaronmboyd! - The provider error boundaries now derive PerpsErrorCode from the HTTP status. A Hyperliquid /info failure carries RateLimitExceeded for a 429, Unauthorized for a 401 and AgentUnauthorized for a 403, and keeps ThirdPartyError for every other status. A LI.FI request with an unparseable body carries RateLimitExceeded for a 429 and keeps DefaultError for