> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://www.openfort.io/api/mcp` to find what you need.
>
> **Have feedback?** Use `submit_feedback` on the same MCP server.

# Policies

Openfort's policy engine defines rules that restrict what a backend wallet can sign. For Hyperliquid, what the engine can see today is limited, so the main way to keep a trading key from withdrawing funds is Hyperliquid's own agent model.

## How Hyperliquid actions map to signing

Every Hyperliquid action is an EIP-712 typed data signature.

| Hyperliquid action | EIP-712 type | Key field |
|-------------------|-------------|-----------|
| Place order | `Agent` (L1 action) | `connectionId` (hash of the action) |
| Withdraw | `HyperliquidTransaction:Withdraw` | `destination`, `amount` |
| USD transfer | `HyperliquidTransaction:UsdSend` | `destination`, `amount` |
| Approve agent | `HyperliquidTransaction:ApproveAgent` | `agentAddress` |
| Update leverage | `Agent` (L1 action) | `connectionId` (hash of the action) |

Orders, cancels, and leverage updates are L1 actions: the SDK signs an `Agent` message whose `connectionId` is a hash of the action, so their fields (asset, side, leverage) aren't visible to a policy.

:::warning
`@openfort/openfort-node` backend wallets hash EIP-712 typed data locally and send only the 32-byte hash to Openfort, so the policy engine evaluates every Hyperliquid signature as `signEvmHash`. `signEvmHash` supports no criteria, and `signEvmTypedData` rules with `evmTypedDataField` criteria never match these requests. A policy can't tell a withdrawal from an order today: it can allow or block all Hyperliquid signing for an account.
:::

## Separate trading from withdrawals

Hyperliquid [agent wallets](https://www.openfort.io/docs/recipes/hyperliquid/agent-wallets) can place orders but can't withdraw or transfer funds. Use a backend wallet as the agent for your trading server, and keep the master wallet, which can withdraw and approve agents, separate from the code that trades.

## Freeze a wallet

An account policy that rejects `signEvmHash` stops a backend wallet from signing any Hyperliquid action, for example to freeze a master wallet between fund-management operations:

```ts
import Openfort from '@openfort/openfort-node'

const openfort = new Openfort(process.env.OPENFORT_SECRET_KEY!, {
  walletSecret: process.env.OPENFORT_WALLET_SECRET!,
})

await openfort.policies.create({
  scope: 'account',
  accountId: account.id,
  rules: [
    {
      action: 'reject',
      operation: 'signEvmHash',
    },
  ],
})
```

Delete or disable the policy when the wallet needs to sign again.

## Allow Hyperliquid signing only

An account policy with a single `accept` rule for `signEvmHash` lets the wallet sign Hyperliquid actions and rejects every other operation, such as transactions and personal messages, unless another enabled policy accepts it:

```ts
await openfort.policies.create({
  scope: 'account',
  accountId: account.id,
  rules: [
    {
      action: 'accept',
      operation: 'signEvmHash',
    },
  ],
})
```
