Skip to main content
The SDK supports two signing modes that determine who signs trading transactions. Signing mode is an SDK-level concept only — the API accepts actions[] (each containing action, typedData, and signature) and does not need to know who signed.
ModeDescriptionTrade UXBest for
USERUser signs every action with their walletWallet popup per orderMaximum security, infrequent trading
USER_AGENTSDK-managed agent wallet signs on behalf of the userNo popups after setupActive trading, seamless UX

USER mode

The user signs each piece of typedData directly with their connected wallet (e.g., MetaMask, WalletConnect). Every order placement and cancellation requires a wallet interaction.
await perps.setSigningMode(userAddress, 'hyperliquid', 'USER');

USER_AGENT mode

The SDK generates a local agent keypair, stored in the browser’s localStorage. The user approves this agent once via a wallet signature, then the agent can sign all subsequent trading actions without wallet popups.
await perps.setSigningMode(userAddress, 'hyperliquid', 'USER_AGENT');
// Agent keypair is generated and stored automatically
The agent wallet’s private key never leaves the client. It’s stored via a pluggable storage adapter and is scoped to a specific user + DEX pair.

Agent Key Storage

By default, agent keys are persisted using the browser’s localStorage. For server-side environments (Node.js, Deno) or custom persistence, pass a storage adapter:
import {
  createPerpsClient,
  PerpsClient,
  createMemoryStorage,
  localStorageAdapter,
} from '@lifi/perps-sdk';

// Browser (default) — uses localStorage
const client = createPerpsClient({ integrator: 'my-app' });

// Testing / ephemeral — keys are lost when the process exits
const client = createPerpsClient({
  integrator: 'my-app',
  storage: createMemoryStorage(),
});

// Same options work with PerpsClient
const perps = new PerpsClient({
  integrator: 'my-app',
  storage: createMemoryStorage(),
});
For production server-side use, implement the StorageAdapter interface backed by your own datastore (e.g., Redis, database):
import type { StorageAdapter } from '@lifi/perps-sdk';

const redisStorage: StorageAdapter = {
  get: async (key) => await redis.get(key),
  set: async (key, value) => { await redis.set(key, value) },
  remove: async (key) => { await redis.del(key) },
};

const perps = new PerpsClient({
  integrator: 'my-app',
  storage: redisStorage,
});

Agent Key Management

The AgentManager is accessible via client.agentManager (from createPerpsClient) or perps.client.agentManager (from PerpsClient). It provides methods for importing, inspecting, and removing agent keys:
const agentManager = perps.client.agentManager;

// Import an existing agent keypair (e.g., restoring from backup)
await agentManager.importAgent(userAddress, 'hyperliquid', '0xprivatekey...');

// Check if an agent exists for a user + DEX pair
const exists = await agentManager.hasAgent(userAddress, 'hyperliquid');

// Get or create an agent (creates a new keypair if none exists)
const agent = await agentManager.getOrCreateAgent(userAddress, 'hyperliquid');
console.log(agent.address); // Agent's public address

// Remove an agent (also resets signing mode to USER)
await agentManager.removeAgent(userAddress, 'hyperliquid');