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.
| Mode | Description | Trade UX | Best for |
|---|
USER | User signs every action with their wallet | Wallet popup per order | Maximum security, infrequent trading |
USER_AGENT | SDK-managed agent wallet signs on behalf of the user | No popups after setup | Active 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');