# Agent wallets

Hyperliquid's agent system lets a **master wallet** authorize an **agent wallet** to trade on its behalf. The master retains full control — the agent can only place orders, never withdraw funds.

Use agents for automated trading bots — the agent wallet runs on a server with limited permissions while the master wallet stays secure.

## How agents work

| Role | Can trade | Can withdraw | Can approve agents |
|------|-----------|-------------|-------------------|
| Master | Yes | Yes | Yes |
| Agent | Yes | No | No |

* An agent is authorized via an on-chain `approveAgent` action signed by the master
* Agents can be given an expiration timestamp or approved indefinitely
* A master can revoke an agent at any time by re-approving with an expired timestamp

## L1 Actions vs User Signed Actions

Hyperliquid splits actions into two categories based on who can sign them:

| Action type | Examples | Agent can sign? |
|------------|---------|----------------|
| **L1 Actions** (trading) | Place/cancel/modify orders, set leverage, TWAP orders | Yes |
| **User Signed Actions** (account) | Withdraw funds, approve agents, USD transfers, approve builder fees | No — master only |

This distinction is important when designing your system: agents handle all trading operations while the master wallet stays secure and is only needed for fund management and agent lifecycle.

## Create master and agent wallets

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

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

// Master wallet — holds funds, approves agents
const master = await openfort.accounts.evm.backend.create()

// Agent wallet — trades on behalf of master
const agent = await openfort.accounts.evm.backend.create()
```

## Approve an agent

Register the agent with Hyperliquid using the master wallet:

```ts
import * as hl from '@nktkas/hyperliquid'

const transport = new hl.HttpTransport({ isTestnet: true })
const exchange = new hl.ExchangeClient({ wallet: master, transport })

await exchange.approveAgent({
  agentAddress: agent.address,
  agentName: 'Trading Bot',
  // Approve for 30 days (null for indefinite)
  nonce: Date.now(),
})
```

## Time-limited agents

Set an expiration by encoding a timestamp in the agent name. The agent loses access once the timestamp passes:

```ts
// Approve agent for 24 hours
const expirationMs = Date.now() + 24 * 60 * 60 * 1000
const expirationSeconds = Math.floor(expirationMs / 1000)

await exchange.approveAgent({
  agentAddress: agent.address,
  agentName: `Trading Bot <${expirationSeconds}>`,
  nonce: Date.now(),
})
```

:::tip
For production systems, set a short expiration (24–72 hours) and rotate agent wallets periodically. This limits the blast radius if an agent key is compromised.
:::

## Trade with the agent

Create an `ExchangeClient` using the agent wallet, but specify the master's address as the `vaultAddress` so orders execute against the master's account:

```ts
const agentExchange = new hl.ExchangeClient({ wallet: agent, transport })

await agentExchange.order({
  orders: [
    {
      a: 4, // ETH
      b: true,
      p: '3000',
      s: '0.01',
      r: false,
      t: { limit: { tif: 'Gtc' } },
    },
  ],
  grouping: 'na',
  vaultAddress: master.address,
})
```

## Revoke an agent

Revoke access by calling `approveAgent` again with an empty name:

```ts
await exchange.approveAgent({
  agentAddress: agent.address,
  agentName: '',
  nonce: Date.now(),
})
```

## List approved agents

Query the current agent approvals for a wallet:

```ts
const info = new hl.InfoClient({ transport })

const extraAgents = await info.extraAgents({ user: master.address })

for (const agentInfo of extraAgents) {
  console.log('Agent:', agentInfo.address, 'Name:', agentInfo.name)
}
```

## Combine with policies

Use Openfort [policies](/docs/recipes/hyperliquid/policies) on the master wallet to restrict which agent approvals are permitted — for example, only allowing agents from a specific allow-list of addresses.

## Best practices

* **One agent per strategy** — separate nonce spaces prevent order conflicts between bots
* **Set short expirations** — 24–72 hours limits risk if a key is compromised
* **Audit regularly** — use `info.extraAgents()` to review active agents and revoke any that are no longer needed
* **Never store master keys on trading servers** — the master wallet should only be used for fund management and agent lifecycle
