- The user’s L1 wallet — any EVM-compatible signer the user connects. It owns the funds.
- An SDK-managed agent — a separate keypair the SDK creates and the user authorizes once.
The L1 (user) wallet signature
This is a signature from the user’s own EVM-compatible signer — MetaMask, a smart-contract wallet, a backend signer, anything that can produce an EVM signature. It is the key that ultimately owns the account and its balance. You hand it to the SDK viauserWallet at construction (createPerpsClient) or later via setUserWallet().
These user-level messages are signed as EIP-712 typed data with the signature chain set to Arbitrum — Hyperliquid’s L1 signature chain. The signer is just an EVM key; it is not tied to Ethereum the chain, protocol, or asset.
On Hyperliquid the L1 wallet is asked to sign only the few actions the protocol requires the account owner to authorize directly:
APPROVE_AGENT— authorizes the agent keypair (the one-time bootstrap that makes popup-free trading possible).APPROVE_BUILDER_FEE— authorizes LI.FI’s per-trade builder fee.WITHDRAWAL— moves funds off Hyperliquid. Agents cannot withdraw.SEND_ASSET— transfers balance between sub-accounts / venues. Agents cannot move assets.
The agent signature
An agent (Hyperliquid also calls it an “API wallet” or “approved wallet”) is a key the account owner has authorized to place orders on its behalf — but which cannot withdraw or move funds. That asymmetry is what makes it safe to keep an agent key on the client: the worst it can do is trade. In@lifi/perps-sdk the agent is a standard secp256k1 keypair (the same curve EVM wallets use), generated and held by the SDK — distinct from the user’s wallet. It signs every trading action as EIP-712 typed data with no wallet prompt: placeOrder, placeTriggerOrder, cancelOrders, modifyOrders, updateLeverage, and updatePositionMargin.
How the agent is created
The SDK generates the agent keypair client-side, the first time an agent is needed (during theAPPROVE_AGENT setup step). The agent’s public address is what the user’s wallet signs to approve; the private key never leaves the client. The LI.FI backend and Hyperliquid only ever see the agent’s address, never its private key.
How the agent is stored
The keypair is persisted through a pluggableStorageAdapter. The default is the browser’s localStorage; pass your own adapter (via the provider/client config) for non-browser environments such as a server or a secure enclave.
- Namespace:
lifi-perps-agent:<l1-address>:hyperliquid— one agent per L1 address per provider. - Scope: client-side only. The agent private key is never transmitted to the LI.FI backend.
Expiry and re-provisioning
An agent approval can lapse (Hyperliquid policy, or an optional TTL set at approval time), and a user on a new device won’t have the stored key. When that happens,checkSetup() re-surfaces APPROVE_AGENT and the user re-approves once. Agents are not silently re-provisioned mid-trade — a trading call with no valid agent fails and points you back through Setup, so a re-approval is always an explicit, user-visible step.
Who signs what
| Action | Signer |
|---|---|
placeOrder, placeTriggerOrder, cancelOrders, modifyOrders, updateLeverage, updatePositionMargin | SDK-managed agent (no popup) |
APPROVE_AGENT, APPROVE_BUILDER_FEE | User’s L1 wallet (one-time setup) |
WITHDRAWAL, SEND_ASSET | User’s L1 wallet (always — agents cannot move funds) |
config.agents array — see Account Abstraction / Account Configuration.