> ## Documentation Index
> Fetch the complete documentation index at: https://public-perps-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# PerpsClient Methods

> Complete reference for all PerpsClient trading methods

Complete reference for `PerpsClient` trading and setup methods. Authorization follows each provider's `ProviderAction.signers` and `signingMethod`: order-management methods normally use the plugin's SDK-managed credential, while user-authorized operations such as Hyperliquid `sendAsset` can invoke the wallet.

## setUserWallet

Set or update the end-user wallet. Call this when the user connects their wallet (for example, from wagmi's `useWalletClient()`); pass `undefined` to clear it when the wallet disconnects.

```typescript theme={null}
import type { WalletClient } from 'viem';

perps.setUserWallet(walletClient);

// Later, on wallet disconnect:
perps.setUserWallet(undefined);
```

| Field        | Type                        | Required | Description                                              |
| ------------ | --------------------------- | -------- | -------------------------------------------------------- |
| `userWallet` | `WalletClient \| undefined` | Yes      | viem-compatible wallet client; pass `undefined` to clear |

The wallet is used for provider-declared `USER` authorization, including setup signatures, SIWE, EVM deposit transactions, Lighter's `REGISTER_API_KEY` countersignature, and user-signed transfers or withdrawals. Order-management actions use each plugin's SDK-managed credential and do not reach this wallet.

***

## setSwitchChain

Set or replace the chain-switching hook. Some setup and deposit actions must be signed on a specific chain; when the user's wallet is on the wrong one, the SDK calls this hook with the target `chainId` and expects it to return a wallet client on that chain (or `undefined` to abort). The hook can also be provided once at construction via the `switchChain` option on `PerpsClientOptions`.

```typescript theme={null}
import type { SwitchChainHook } from '@lifi/perps-sdk';

const switchChain: SwitchChainHook = async (chainId) => {
  await walletClient.switchChain({ id: chainId });
  return walletClient;
};

perps.setSwitchChain(switchChain);

// Later, to remove it:
perps.setSwitchChain(undefined);
```

| Field         | Type                           | Required | Description                                                                               |
| ------------- | ------------------------------ | -------- | ----------------------------------------------------------------------------------------- |
| `switchChain` | `SwitchChainHook \| undefined` | Yes      | `(chainId: number) => Promise<PerpsClientSigner \| undefined>`; pass `undefined` to clear |

***

## getMarketSettings

Read the current venue-side margin mode and leverage that the next order on a market will use.

```typescript theme={null}
const settings = await perps.getMarketSettings({
  provider: 'hyperliquid',
  address: userAddress,
  market: { marketId: 'BTC', categoryId: 'hyperliquid' },
});

if (settings) {
  console.log(settings.marginMode, settings.leverage);
}
```

| Field      | Type        | Required | Description                |
| ---------- | ----------- | -------- | -------------------------- |
| `provider` | `string`    | Yes      | Provider identifier        |
| `address`  | `string`    | Yes      | User wallet address        |
| `market`   | `MarketRef` | Yes      | Canonical market reference |

**Returns:** `MarketSettings | undefined` — `{ marginMode, leverage }`, or `undefined` when the provider exposes no readable market setting or does not implement the optional capability.

***

## placeOrder

Place an order. Builds the action, auto-signs through the provider plugin, and submits in one call.

```typescript theme={null}
const result = await perps.placeOrder(params);
```

| Field         | Type                | Required | Description                                                                                                           |
| ------------- | ------------------- | -------- | --------------------------------------------------------------------------------------------------------------------- |
| `address`     | `string`            | Yes      | User's wallet address                                                                                                 |
| `provider`    | `string`            | Yes      | Provider identifier                                                                                                   |
| `market`      | `MarketRef`         | Yes      | Target market (`{ marketId, categoryId }`)                                                                            |
| `side`        | `'BUY' \| 'SELL'`   | Yes      | Order direction                                                                                                       |
| `type`        | `OrderType`         | Yes      | Order type: `MARKET`, `LIMIT`, `STOP_MARKET`, `STOP_LIMIT`, `TAKE_PROFIT_MARKET`, `TAKE_PROFIT_LIMIT`, `TRIGGER_ONLY` |
| `size`        | `string`            | Yes      | Order size                                                                                                            |
| `price`       | `string`            | Yes      | Limit price or slippage limit                                                                                         |
| `leverage`    | `number`            | No       | Leverage to set (generates an `updateLeverage` step if it differs from the current setting)                           |
| `reduceOnly`  | `boolean`           | No       | Only reduce position                                                                                                  |
| `timeInForce` | `string`            | No       | `GTC`, `IOC`, `POST_ONLY`, `GTT`                                                                                      |
| `expiresAt`   | `string`            | No       | Unix ms timestamp expiry for GTT (must be in the future)                                                              |
| `takeProfit`  | `TriggerOrderInput` | No       | Take profit trigger                                                                                                   |
| `stopLoss`    | `TriggerOrderInput` | No       | Stop loss trigger                                                                                                     |

**Returns:** `ExecuteActionResponse` with `results[]` array.

***

## cancelOrders

Cancel one or more orders. Auto-signs through the provider plugin.

```typescript theme={null}
const result = await perps.cancelOrders(params);
```

| Field      | Type       | Required | Description           |
| ---------- | ---------- | -------- | --------------------- |
| `address`  | `string`   | Yes      | User's wallet address |
| `provider` | `string`   | Yes      | Provider identifier   |
| `ids`      | `string[]` | Yes      | Order IDs to cancel   |

**Returns:** `ExecuteActionResponse` with `results[]` array.

***

## modifyOrders

Modify orders in place. Auto-signs through the provider plugin.

```typescript theme={null}
const result = await perps.modifyOrders({
  provider: 'hyperliquid',
  address: userAddress,
  modifications: [{ id: '12345678', price: '94500.00' }],
});
```

| Field           | Type                 | Required | Description            |
| --------------- | -------------------- | -------- | ---------------------- |
| `provider`      | `string`             | Yes      | Provider identifier    |
| `address`       | `string`             | Yes      | User's wallet address  |
| `modifications` | `ModifyOrderInput[]` | Yes      | Modifications to apply |

**Returns:** `ExecuteActionResponse` with `results[]` array.

***

## placeTriggerOrder

Place standalone trigger orders (TP/SL on existing positions). Auto-signs with the agent.

```typescript theme={null}
const result = await perps.placeTriggerOrder({
  provider: 'hyperliquid',
  address: userAddress,
  market: { marketId: 'BTC', categoryId: 'hyperliquid' },
  side: 'SELL',
  takeProfit: { triggerPrice: '100000.00' },
  stopLoss: { triggerPrice: '90000.00' },
});
```

| Field        | Type                | Required | Description                                |
| ------------ | ------------------- | -------- | ------------------------------------------ |
| `provider`   | `string`            | Yes      | Provider identifier                        |
| `address`    | `string`            | Yes      | User's wallet address                      |
| `market`     | `MarketRef`         | Yes      | Target market (`{ marketId, categoryId }`) |
| `side`       | `'BUY' \| 'SELL'`   | Yes      | Order side                                 |
| `takeProfit` | `TriggerOrderInput` | No       | Take profit trigger                        |
| `stopLoss`   | `TriggerOrderInput` | No       | Stop loss trigger                          |

**Returns:** `ExecuteActionResponse` with `results[]` array.

***

## placeTwapOrder

Place a TWAP parent order that executes over a fixed duration. Auto-signs with the provider's SDK-managed credential.

```typescript theme={null}
const result = await perps.placeTwapOrder({
  provider: 'hyperliquid',
  address: userAddress,
  market: { marketId: 'BTC', categoryId: 'hyperliquid' },
  side: 'BUY',
  size: '1.5',
  durationSeconds: 1800,
});

console.log(result.results[0].twapId);
```

| Field              | Type              | Required | Description                                                                                                     |
| ------------------ | ----------------- | -------- | --------------------------------------------------------------------------------------------------------------- |
| `provider`         | `string`          | Yes      | Provider identifier                                                                                             |
| `address`          | `string`          | Yes      | User's wallet address                                                                                           |
| `market`           | `MarketRef`       | Yes      | Target market (`{ marketId, categoryId }`)                                                                      |
| `side`             | `'BUY' \| 'SELL'` | Yes      | Order direction                                                                                                 |
| `size`             | `string`          | Yes      | Total base-asset size executed across the TWAP's lifetime                                                       |
| `durationSeconds`  | `number`          | Yes      | Total execution window in seconds                                                                               |
| `reduceOnly`       | `boolean`         | No       | Only reduce the position                                                                                        |
| `randomize`        | `boolean`         | No       | Hyperliquid extra — randomize sub-order timing within the window. Honoured only by providers that advertise it. |
| `frequencySeconds` | `number`          | No       | Ondo extra — interval between child orders in seconds. Honoured only by providers that advertise it.            |
| `minPrice`         | `string`          | No       | Ondo extra — lowest acceptable child-order price. Honoured only by providers that advertise it.                 |
| `maxPrice`         | `string`          | No       | Ondo extra — highest acceptable child-order price. Honoured only by providers that advertise it.                |

**Returns:** `ExecuteActionResponse` with `results[]` array. A successful result carries `twapId` — the provider-native identifier for the placed TWAP parent.

<Info>
  A provider only honours the extras it declares via its `placeTwapOrder` action's `params` descriptors (`GET /providers`); other providers ignore them. See each provider's trading page — [Hyperliquid](/providers/hyperliquid/trading), [Lighter](/providers/lighter/trading), [Ondo](/providers/ondo/trading) — for its extras and duration bounds.
</Info>

***

## cancelTwapOrder

Cancel a running TWAP parent order. Auto-signs with the provider's SDK-managed credential.

```typescript theme={null}
const result = await perps.cancelTwapOrder({
  provider: 'hyperliquid',
  address: userAddress,
  market: { marketId: 'BTC', categoryId: 'hyperliquid' },
  twapId: '4521',
});
```

| Field      | Type        | Required | Description                                                                                                                         |
| ---------- | ----------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `provider` | `string`    | Yes      | Provider identifier                                                                                                                 |
| `address`  | `string`    | Yes      | User's wallet address                                                                                                               |
| `market`   | `MarketRef` | Yes      | Target market — required by every provider's cancel wire even where the TWAP id is globally unique                                  |
| `twapId`   | `string`    | Yes      | Provider-native TWAP identifier: Hyperliquid's numeric id, Ondo's `twap_`-prefixed id, or Lighter's order index (scoped per market) |

**Returns:** `ExecuteActionResponse` with `results[]` array.

***

## updatePositionMargin

Adjust position margin. Auto-signs with the agent.

```typescript theme={null}
const result = await perps.updatePositionMargin({
  provider: 'hyperliquid',
  address: userAddress,
  market: { marketId: 'BTC', categoryId: 'hyperliquid' },
  action: 'add',
  amount: '500.00',
});
```

| Field      | Type                | Required | Description                                |
| ---------- | ------------------- | -------- | ------------------------------------------ |
| `provider` | `string`            | Yes      | Provider identifier                        |
| `address`  | `string`            | Yes      | User's wallet address                      |
| `market`   | `MarketRef`         | Yes      | Target market (`{ marketId, categoryId }`) |
| `action`   | `'add' \| 'remove'` | Yes      | Add or remove margin                       |
| `amount`   | `string`            | Yes      | Margin amount                              |

**Returns:** `ExecuteActionResponse` with `results[]` array.

***

## sendAsset

Move collateral between a provider's categories (e.g. between perps and spot). This is a convenience wrapper over `execute(SEND_ASSET)` and follows the provider descriptor's signer; Hyperliquid uses the user's wallet.

```typescript theme={null}
const result = await perps.sendAsset({
  provider: 'hyperliquid',
  address: userAddress,
  collateral: 'USDC',
  sourceDex: 'perps',
  destinationDex: 'spot',
  amount: '100.00',
});
```

| Field            | Type      | Required | Description                                                                                                                       |
| ---------------- | --------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `provider`       | `string`  | Yes      | Provider identifier                                                                                                               |
| `address`        | `Address` | Yes      | User's wallet address                                                                                                             |
| `collateral`     | `string`  | Yes      | Canonical `Asset.id` of the asset being moved (for Hyperliquid spot assets, the token index as a string) — never a display symbol |
| `sourceDex`      | `string`  | Yes      | Category id to move from                                                                                                          |
| `destinationDex` | `string`  | Yes      | Category id to move to                                                                                                            |
| `amount`         | `string`  | Yes      | Amount to move                                                                                                                    |

**Returns:** `ExecuteActionResponse` with `results[]` array.

***

## Generic action helper

The high-level methods above (`placeOrder`, `cancelOrders`, `modifyOrders`, `placeTriggerOrder`, `placeTwapOrder`, `cancelTwapOrder`, `updatePositionMargin`) are convenience wrappers around a single generic helper. Use it directly when an action does not have a dedicated wrapper.

### execute

Auto-sign-and-submit for any action type. Mirrors `placeOrder`/`modifyOrders`/etc. but generic over `ActionType`. Internally builds the action, picks the correct signing pipeline (EIP-712, WASM blob, or EVM tx) from the provider's descriptor, signs, and submits in a single create→sign→submit pass.

```typescript theme={null}
import { ActionType } from '@lifi/perps-types';

const result = await perps.execute({
  provider: 'hyperliquid',
  address: userAddress,
  action: ActionType.UPDATE_LEVERAGE,
  params: {
    market: { marketId: 'BTC', categoryId: 'hyperliquid' },
    leverage: 10,
  },
});
```

| Field        | Type                                     | Required | Description                                                                                                                       |
| ------------ | ---------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `provider`   | `string`                                 | Yes      | Provider identifier                                                                                                               |
| `address`    | `string`                                 | Yes      | User's wallet address                                                                                                             |
| `action`     | `ActionType`                             | Yes      | Action type to execute                                                                                                            |
| `params`     | `ActionParamsMap[T]`                     | Yes      | Action-specific params                                                                                                            |
| `onProgress` | `(progress: SignActionProgress) => void` | No       | Progress sink for on-chain legs (e.g. a native deposit's `approve` then `deposit`); called as each leg is submitted and confirmed |

**Returns:** `ExecuteActionResponse` with `results[]` array.

<Info>
  `SignActionProgress` is `{ index, total, action, functionName, chainId, status, txHash }`, where `status` is `'submitted'` (wallet broadcast, hash known) then `'confirmed'` (receipt mined) — emitted twice per on-chain leg, so a consumer can render a live per-transaction stepper.
</Info>

<Info>
  Use `execute` for action types without dedicated wrappers — for example `UPDATE_LEVERAGE` or provider-specific account-configuration actions. For trading actions with wrappers (`placeOrder`, `cancelOrders`, ...), prefer the wrappers; they expose richer typed parameters.
</Info>

### buildAction

Build the action payloads for an action without signing or submitting. Typed wrapper around the `createAction` service (see [Actions / createAction](/sdk/actions#createaction)) and the natural counterpart to `execute` — use it when you need to inspect the steps, sign them in a custom flow, or hand them off across a process boundary before calling `executeAction` yourself.

```typescript theme={null}
import { ActionType } from '@lifi/perps-types';

const { actions } = await perps.buildAction(ActionType.UPDATE_LEVERAGE, {
  provider: 'hyperliquid',
  address: userAddress,
  params: {
    market: { marketId: 'BTC', categoryId: 'hyperliquid' },
    leverage: 10,
  },
});
```

| Field      | Type                 | Required | Description                                      |
| ---------- | -------------------- | -------- | ------------------------------------------------ |
| `action`   | `ActionType`         | Yes      | Action type to build (first positional argument) |
| `provider` | `string`             | Yes      | Provider identifier                              |
| `address`  | `string`             | Yes      | User's wallet address                            |
| `params`   | `ActionParamsMap[T]` | Yes      | Action-specific params                           |

**Returns:** `CreateActionResponse` — `{ actions: ActionStep[] }`. The SDK resolves the correct signer address (agent or user) for the given action type before delegating to `createAction`.

***

## Setup

Account-setup actions (e.g. `APPROVE_AGENT`, `APPROVE_BUILDER_FEE` on Hyperliquid; `REGISTER_API_KEY` on Lighter) are coordinated through the setup helpers. The high-level flow is described in [Concepts / Action Pattern](/concepts/action-pattern); the methods below are the lower-level building blocks.

### checkSetup

Return the unsatisfied entries on the provider's `setup` descriptors for this account as a flat list. Each `ActionStep` is self-describing — its action keys back to the provider's `setup` descriptor, which declares the step's signer and signing scheme — so no signer-role partition is exposed here.

```typescript theme={null}
const required = await perps.checkSetup({
  provider: 'hyperliquid',
  address: userAddress,
});

if (!required.isReady) {
  // required.setup: ActionStep[] — outstanding steps, ordered by descriptor sequence
}
```

| Field      | Type     | Required | Description           |
| ---------- | -------- | -------- | --------------------- |
| `provider` | `string` | Yes      | Provider identifier   |
| `address`  | `string` | Yes      | User's wallet address |

**Returns:** `ProviderSetup` — `{ accountExists: boolean; setup: ActionStep[]; isReady: boolean }`. `accountExists` reports whether the address already has account state with the provider.

`Provider.options` descriptors are never returned here — options are post-setup tunables and never gate trading. Option state is surfaced separately via `getAccount().settings`.

### buildProviderSetup

Materialise **every** setup step for the provider (ordered by descriptor `sequence`) as unsigned action payloads, without checking which are already satisfied and without signing or submitting. Where `checkSetup` returns only the outstanding steps, `buildProviderSetup` builds the full descriptor set — useful for previewing or re-staging the complete setup flow.

```typescript theme={null}
const { actions } = await perps.buildProviderSetup({
  provider: 'hyperliquid',
  address: userAddress,
});
```

| Field      | Type     | Required | Description           |
| ---------- | -------- | -------- | --------------------- |
| `provider` | `string` | Yes      | Provider identifier   |
| `address`  | `string` | Yes      | User's wallet address |

**Returns:** `CreateActionResponse` — `{ actions: ActionStep[] }`.

### executeProviderSetupAction

Sign and submit one pre-staged setup `ActionStep` end-to-end. The caller is expected to have already obtained the step from a prior `checkSetup` call (no refetch). Run the outstanding steps in descriptor order:

```typescript theme={null}
const required = await perps.checkSetup({
  provider: 'lighter',
  address: userAddress,
});

for (const step of required.setup) {
  await perps.executeProviderSetupAction({
    provider: 'lighter',
    address: userAddress,
    step,
  });
}
```

| Field      | Type         | Required | Description                             |
| ---------- | ------------ | -------- | --------------------------------------- |
| `provider` | `string`     | Yes      | Provider identifier                     |
| `address`  | `string`     | Yes      | User's wallet address                   |
| `step`     | `ActionStep` | Yes      | A single step from `checkSetup().setup` |

**Returns:** `Promise<void>`.

<Note>
  Requires the user wallet to be set via `setUserWallet` (or passed at construction) for any step that requires the user's L1 wallet — that includes EIP-712, EVM-tx, and Lighter's `REGISTER_API_KEY` (which signs the EIP-191 message embedded in the WASM blob).
</Note>

### executeProviderOption

Sign and submit a single `Provider.options` change (a post-setup tunable such as Hyperliquid `accountMode` or Lighter `accountType`) end-to-end. Dispatches through the same pipeline as [`execute`](#execute), but an option change is a single mandatory action: a per-action `success: false` throws a `PerpsError` (`PerpsErrorCode.ExchangeRejected`) rather than being silently dropped.

```typescript theme={null}
import { ActionType } from '@lifi/perps-types';

await perps.executeProviderOption({
  provider: 'hyperliquid',
  address: userAddress,
  action: ActionType.ACCOUNT_MODE,
  params: { mode: 'unifiedAccount' },
});
```

| Field      | Type                 | Required | Description                                                       |
| ---------- | -------------------- | -------- | ----------------------------------------------------------------- |
| `provider` | `string`             | Yes      | Provider identifier                                               |
| `address`  | `string`             | Yes      | User's wallet address                                             |
| `action`   | `ActionType`         | Yes      | The options action to apply (e.g. `ACCOUNT_MODE`, `ACCOUNT_TYPE`) |
| `params`   | `ActionParamsMap[T]` | Yes      | The selected option value                                         |

**Returns:** `Promise<void>` — resolves on success, throws `PerpsError` on venue rejection.

**API Reference:** [POST /createAction · /executeAction](/api-reference/actions)
