npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@locker-protocol/agent-wallet-hyperliquid-signer

v2.5.0

Published

Your private key is nowhere: not on our servers, not on the agent's machine, not with anyone. The agent trades. It holds nothing. Hyperliquid signing, orders and account reads for agents whose keys stay in Locker Vault.

Readme

@locker-protocol/agent-wallet-hyperliquid-signer

Your private key is nowhere: not on our servers, not on the agent's machine, not with anyone.

The agent trades. It holds nothing.

  • Where the key is: the account's private key stays in Locker Vault, an offline app on a phone or tablet. This package never sees it.
  • Who can withdraw: only the vault, by a QR code a person scans and signs. Hyperliquid refuses the agent key this package signs orders with every withdrawal and every send; the one movement of funds it accepts from that key is a deposit into a Hyperliquid vault (measured on mainnet, 2026-09-28).
  • What goes where: requests go to api.hyperliquid.xyz only. No server of ours, no account, no telemetry.

Documentation: doc.lockerprotocol.com/agent-wallet: install, the setup in steps, how it trades and every command. Website: hyperagentictrader.com.

Hyperliquid signing, order building and account reads for programs and AI agents that trade perps while the keys stay offline. It is the engine under the lpa command (@locker-protocol/agent-wallet-hyperliquid-trader), usable on its own.

This page is the complete reference: how it works, a full example, then every export with its signature.

Contents

How it works

Two keys, two paths. The agent key trades from your program; everything that moves funds or grants a right goes to the phone.

 your program
   |
   |  reads: markets, books, candles, accounts,
   |  positions, orders (public, no key) ------------------------> api.hyperliquid.xyz/info
   |
   |  trading: placeHlOrder, setHlPositionTpsl, cancelHlOrder,
   |  closeHlPosition
   |     signed with the AGENT key, through the key store
   |     you install (useAgentKeyStore) ------------------------> api.hyperliquid.xyz/exchange
   |
   |  funds and rights: buildApproveAgentPayload,
   |  buildWithdrawTypedPayload, buildSendAssetTypedPayload ...
   |     plain EIP-712 --> @locker-protocol/agent-wallet-vault --> QR --> Locker Vault
   |                                                              (phone signs)
   |     the signature --> userSignedExchangeBody --> postHlExchange --> /exchange
   |
   |  deposit: buildDepositCall --> a USDC transfer the vault signs --> Arbitrum One
   |
   |  live: createHlStream -----------------------------------> wss://api.hyperliquid.xyz/ws

Nothing here holds the account's key: approving an agent, withdrawing, sending and moving margin between dexes are payloads for the vault. The agent key is made here, sealed under a password when stored, and handed to the signing path through a key store that refuses any other account's orders, an expired agent, and (optionally) any action outside a list you give it.

What an agent key can and cannot do

An agent key is approved once by the vault and expires on its own. Measured on Hyperliquid mainnet on 2026-09-28, with an approved agent key:

| Action | Signed by the agent key | |---|---| | Place, modify and cancel orders, set leverage | accepted | | withdraw3, usdSend, spotSend, sendAsset, usdClassTransfer | refused | | approveAgent (approve another agent), approveBuilderFee | refused | | vaultTransfer (deposit the account into a vault) | accepted |

So a stolen agent key cannot withdraw, but it can lose money by trading or by depositing into a vault run by someone else. Use a dedicated account holding only what you are ready to risk, and sign a closed list of trading actions (memoryAgentKeyStore's actions option, below). The Locker CLI does exactly that.

Install

npm install @locker-protocol/agent-wallet-hyperliquid-signer

Node 22 or later. ESM and CommonJS, with TypeScript declarations. One dependency: ethers.

A full example

import {
    getHlMarkets, getHlL2Book, meetsMinOrderUsd,
    createAgentKey, sealAgentKey, openAgentKey, buildApproveAgentPayload,
    memoryAgentKeyStore, useAgentKeyStore, probeAgentApproved,
    placeHlOrder, getHlPositions, setHlPositionTpsl, getHlOpenOrders, cancelHlOrder, closeHlPosition,
} from '@locker-protocol/agent-wallet-hyperliquid-signer';

const account = '0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE'; // the vault account

// 1. Read the market: no key.
const eth = (await getHlMarkets()).find((m) => m.name === 'ETH')!;
const book = await getHlL2Book('ETH', 5);             // { bids, asks, time }, best level first
console.log(eth.markPx, book.bids[0].px, book.asks[0].px);
console.log(meetsMinOrderUsd(Number(eth.markPx), 0.03)); // true: above Hyperliquid's $10

// 2. A new agent key, sealed for storage, and its approval for the vault to sign.
const agent = createAgentKey({ base: 'my-bot', validityMs: 7 * 86_400_000 });
const sealed = await sealAgentKey({ privateKey: agent.privateKey, user: account, validUntil: agent.validUntil, password });
const approval = buildApproveAgentPayload(agent.address, agent.agentName, Date.now());
// ... show `approval` to Locker Vault with @locker-protocol/agent-wallet-vault, post its answer
// with userSignedExchangeBody + postHlExchange, then check Hyperliquid lists the agent:
console.log(await probeAgentApproved(account, agent.address)); // true, false, or null (cannot tell)

// 3. Install the key: orders for `account` only, trading actions only.
const store = memoryAgentKeyStore(Date.now, {
    actions: ['order', 'cancel', 'cancelByCloid', 'modify', 'batchModify', 'updateLeverage', 'updateIsolatedMargin', 'scheduleCancel', 'setReferrer'],
});
store.add({ user: account, privateKey: (await openAgentKey(sealed, password))!, validUntil: agent.validUntil });
useAgentKeyStore(store);

// 4. Trade.
const r = await placeHlOrder({ user: account, coin: 'ETH', isBuy: true, size: '0.03', leverage: 3, takeProfitPx: '2750', stopLossPx: '2600' });
console.log(r);                                         // { oid: 77738308, filled: true, filledSz: 0.03, avgPx: 2702.4 }
console.log(await getHlPositions(account));             // [{ coin: 'ETH', szi: '0.03', entryPx: '2668.9', ... }]
await setHlPositionTpsl({ user: account, coin: 'ETH', takeProfitPx: '2800' });
for (const o of await getHlOpenOrders(account)) await cancelHlOrder({ user: account, coin: o.coin, oid: o.oid });
await closeHlPosition({ user: account, coin: 'ETH' });  // 1: positions closed

// 5. Done: zero the key in memory.
store.clear();
useAgentKeyStore(null);

Reference

Every read goes to https://api.hyperliquid.xyz/info and is memoized for a few seconds (5 s for books and rosters, longer for lists that only grow); invalidateHlInfoMemo() drops the memo, and the order functions call it after they act. Prices, sizes and balances come back as Hyperliquid's decimal strings, never floats, unless the name says otherwise. A market on a HIP-3 dex is named dex:TICKER (xyz:GOLD); the main dex is ''.

Markets and books

| Export | Signature | What it does | |---|---|---| | getHlMarkets | (dex?: string) => Promise<HlMarket[]> | the roster of one dex with live context: name, dex, markPx, midPx (null when halted), oraclePx, prevDayPx, funding (hourly), openInterest, dayNtlVlm, maxLeverage, szDecimals | | getHlMarketsMerged | () => Promise<HlMarket[]> | the main dex and every HIP-3 dex in one list; one builder dex failing never sinks the rest | | getHlMarketsFor | (coins: string[]) => Promise<HlMarket[]> | the markets of exactly the dexes these coins live on | | getPerpDexs | () => Promise<HlPerpDex[]> | the HIP-3 dexes: name, fullName, assetOffset | | getHlL2Book | (coin: string, depth = 8) => Promise<HlBook> | the book around the spread: bids and asks as { px, sz, n }, best first, and time; a halted or one-sided book is refused | | getHlCandles | (coin: string, interval: string, count = 60) => Promise<HlCandle[]> | the last candles, { t, o, h, l, c, v }; interval is 1m, 5m, 15m, 1h, 4h or 1d | | getHlMid | (coin: string) => Promise<number> | the mid price | | getHlAssetInfo | (coin: string) => Promise<HlAssetInfo> | what the order wire needs: assetIndex, szDecimals, maxLeverage, onlyIsolated, marginTiers | | getHlDexCollateralToken | (dex: string) => Promise<number> | the token a dex margins in; 0 is USDC | | coinDex | (coin: string) => string | the dex a coin routes to: coinDex('xyz:GOLD') is 'xyz', coinDex('BTC') is '' | | infoQuery | (body: object, ttlMs?: number) => Promise<unknown> | any /info request, memoized | | invalidateHlInfoMemo | () => void | forget every memoized answer |

const gold = await getHlMarkets('xyz');                 // names come back as 'xyz:GOLD', ...
const candles = await getHlCandles('BTC', '1h', 24);     // the last day of hourly candles
const info = await getHlAssetInfo('ETH');                // { assetIndex: 1, szDecimals: 4, maxLeverage: 25, ... }

Accounts

Public reads of any address.

| Export | Signature | What it does | |---|---|---| | getHlAccount | (address: string, dex?: string) => Promise<HlAccount> | equity, withdrawable, unrealizedPnl (number), positionCount, unified | | getHlPositions | (user: string, dex?: string) => Promise<HlPositionRow[]> | open positions of one dex: coin, szi (signed), entryPx, positionValue, unrealizedPnl, liquidationPx, leverage, marginUsed | | getHlPositionsAll | (user: string) => Promise<HlPositionRow[]> | the main dex and every funded HIP-3 dex | | getHlOpenOrders | (user: string, dex?: string) => Promise<HlOpenOrderRow[]> | open orders of one dex, triggers included: coin, oid, side (B or A), limitPx, sz, orderType, isTrigger, triggerPx, isPositionTpsl | | getHlOpenOrdersAll | (user: string) => Promise<HlOpenOrderRow[]> | across every funded dex | | getHlSpotBalances | (address: string) => Promise<HlSpotBalance[]> | spot balances: coin, token, total, hold, available | | getHlPnl | (address: string) => Promise<HlPnlWindows> | perps PnL over day, week, month, allTime (a window Hyperliquid does not return is absent) | | parseHlPortfolioPnl | (body: unknown) => HlPnlWindows | the same, from a portfolio answer you already have | | getHlUserFees | (address: string) => Promise<HlUserFees> | the account's own takerRate and makerRate, or null | | noteFundedDex | (user: string, dex: string) => Promise<void> | remember at once that a dex was just funded, so its positions are read | | clearFundedDexCache | () => void | forget every funded-dex set | | subDecimalStrings | (a: string, b: string) => string | exact subtraction of two non-negative decimal strings |

const a = await getHlAccount(account);                   // { equity: '55.78', withdrawable: '55.78', ... }
const everywhere = await getHlPositionsAll(account);
const fees = await getHlUserFees(account);               // { takerRate: 0.00045, makerRate: 0.00015 }

Agent keys

| Export | Signature | What it does | |---|---|---| | createAgentKey | ({ base, validityMs, now? }) => NewAgentKey | a fresh random key: address, privateKey, agentName (<base> valid_until <ms>), validUntil; validityMs is capped at Hyperliquid's ceiling | | agentNameFor | (base: string, validUntil: number) => string | the name an agent is approved under | | parseAgentValidUntil | (agentName: string) => number | the expiry a name carries, or null | | sealAgentKey | ({ privateKey, user, validUntil, password }) => Promise<SealedAgentKey> | the key encrypted for storage, bound to one account and dated; a password is required | | openAgentKey | (sealed: SealedAgentKey, password: string) => Promise<string> | the private key back, or null for a wrong password; a record that does not decrypt to its own address is refused | | needsReseal | (sealed: SealedAgentKey) => boolean | the record was sealed with fewer PBKDF2 rounds than today's: seal it again while the password is in hand | | memoryAgentKeyStore | (now?, { actions? }) => AgentKeyStore & { add, clear } | a key store in memory, one agent per account; refuses another account's orders, an expired agent, and any action outside actions when given; clear() zeroes the keys | | useAgentKeyStore | (store: AgentKeyStore \| null) => void | installs the store every order signs through (null removes it) | | withAgentKey | (user, fn, action?) => Promise<T> | runs fn with the agent key of user, through the installed store | | probeAgentApproved | (user: string, agentAddress: string) => Promise<boolean> | is the agent approved for the account: true, false, or null when Hyperliquid cannot tell | | AGENT_NAME_BASE_MAX | 16 | the longest base Hyperliquid takes for a name | | AGENT_MAX_VALIDITY_MS | number | Hyperliquid's ceiling on an agent's validity | | PBKDF2_ITERATIONS | 600000 | the rounds that wrap a sealed key |

const key = createAgentKey({ base: 'lpa', validityMs: 30 * 86_400_000 });
const sealed = await sealAgentKey({ privateKey: key.privateKey, user: account, validUntil: key.validUntil, password });
// store `sealed` as JSON; later:
const privateKey = await openAgentKey(sealed, password);   // null: wrong password

Orders

Signed with the agent key of user through the installed store, and posted. Each throws Hyperliquid's refusal verbatim.

| Export | Signature | What it does | |---|---|---| | placeHlOrder | (input: HlOrderInput) => Promise<HlOrderResult> | one order, and its TP/SL when given; answers { oid?, filled?, filledSz?, avgPx?, tpslError? }: oid, the order on Hyperliquid, whether it rests on the book or executed at once, filledSz and avgPx when it executed at once (as Hyperliquid answers them) | | setHlPositionTpsl | ({ user, coin, takeProfitPx?, stopLossPx? }) => Promise<void> | TP/SL on a position already open; refused when nothing is open | | cancelHlOrder | ({ user, coin, oid }) => Promise<void> | cancels an order | | closeHlPosition | ({ user, coin?, slippage? }) => Promise<number> | market-closes one position, or every position of every funded dex without coin; answers how many | | setHlReferrer | (user: string) => Promise<void> | sets the referral code once; an account already referred keeps its referrer | | postL1 | (user: string, action: object) => Promise<unknown> | signs any L1 action with the agent key and posts it | | orderWire, orderAction | | the wire of one order and of a batch, as Hyperliquid hashes them | | nextNonce | () => number | a millisecond nonce, strictly increasing in this process | | MIN_ORDER_USD | 10 | Hyperliquid's minimum notional | | meetsMinOrderUsd | (px: number, size: number) => boolean | is the order worth the minimum, at the price it signs with |

HlOrderInput:

| Field | Type | Meaning | |---|---|---| | user | string | the account | | coin | string | the market | | isBuy | boolean | long (buy) or short (sell) | | size | string | in the base asset | | limitPx | string | a limit price; absent, a market order at the mid plus or minus slippage (IOC) | | tif | 'Gtc', 'Ioc' or 'Alo' | the validity of a limit: Gtc (the default) rests until it fills or is cancelled, Ioc fills what it can at once and the rest is cancelled, Alo is posted to the book only and refused by Hyperliquid if it would fill at once; refused without limitPx | | slippage | number | for a market order, as a fraction; default 0.03 | | leverage | number | set on the market before the order (capped at its maximum); Hyperliquid sets it for the whole market, a position open on it included | | marginMode | 'cross' or 'isolated' | the margin that leverage is set in; absent, isolated on a market that takes no other and cross elsewhere; cross on a market that takes isolated only is refused before anything is signed; it goes with leverage | | reduceOnly | boolean | only reduce a position | | takeProfitPx, stopLossPx | string | TP/SL triggers placed with the order |

await placeHlOrder({ user: account, coin: 'BTC', isBuy: false, size: '0.001', limitPx: '84000' });
await placeHlOrder({ user: account, coin: 'xyz:GOLD', isBuy: true, size: '0.01', leverage: 2, slippage: 0.01 });
await closeHlPosition({ user: account });   // every position, every funded dex

Prices and sizes

Hyperliquid refuses off-tick prices and sizes. These round the way it requires.

| Export | Signature | What it does | |---|---|---| | roundPx | (px: number, szDecimals: number) => number | 5 significant figures, then at most 6 - szDecimals decimals | | roundLimitPx | (px: number, szDecimals: number, isBuy: boolean) => number | a limit price the wire takes, rounded toward the user; NaN for an input that is not a positive number | | hlPriceDecimals | (px: number, szDecimals: number) => number | how many decimals a price may carry | | roundSize | (sz: number, szDecimals: number) => number | a size rounded down, never up | | slippagePrice | (mid: number, isBuy: boolean, slippage: number, szDecimals: number) => number | the price of a market order | | floatToWire | (x: number) => string | a number as the wire writes it |

roundPx(2669.4567, 4);                 // 2669.5
slippagePrice(2669.5, true, 0.03, 4);  // 2749.6

Signing L1 actions

What postL1 does under the hood, for actions you build yourself.

| Export | Signature | What it does | |---|---|---| | signL1Action | (agentPrivKey, action, vaultAddress, nonce, expiresAfter, isMainnet = true) => HlSig | signs an action with the agent key; deterministic, no network | | actionHash | (action, vaultAddress, nonce, expiresAfter) => string | the hash Hyperliquid signs over | | msgpackEncode | (action: object) => Uint8Array | the msgpack encoding, key order kept |

Payloads the vault signs

Plain EIP-712 payloads, { domain, types, primaryType, message }, signed on Arbitrum's chain id. Show them to Locker Vault with @locker-protocol/agent-wallet-vault, then post the answer.

| Export | Signature | What the vault signs | |---|---|---| | buildApproveAgentPayload | (agentAddress, agentName, nonce) | lets an agent key trade for the account; approving another address under the same name replaces the agent | | buildApproveBuilderFeePayload | (builder, maxFeeRate, nonce) | lets orders carry a builder fee up to that rate | | buildWithdrawTypedPayload | (destination, amount, time) | a withdrawal to Arbitrum (withdraw3) | | buildSpotSendTypedPayload | (destination, token, amount, time) | a spot send | | buildSendAssetTypedPayload | (destination, sourceDex, destinationDex, amount, nonce) | USDC margin between dexes; '' is the main dex | | userSignedExchangeBody | (payload, signature, signer) => body | the /exchange body; the signature must recover to signer, or it is refused here | | postHlExchange | (payload: object) => Promise<unknown> | posts to /exchange; Hyperliquid's refusal is thrown verbatim | | ARBITRUM_CHAIN_ID | '0xa4b1' | the signatureChainId of these payloads |

import { buildSignRequest, DataType } from '@locker-protocol/agent-wallet-vault';
import { hexlify, toUtf8Bytes } from 'ethers';

const payload = buildWithdrawTypedPayload(account, '25', Date.now());
const req = buildSignRequest({
    signDataHex: hexlify(toUtf8Bytes(JSON.stringify(payload))),   // the typed data, as JSON bytes
    dataType: DataType.typedData,
    chainId: payload.domain.chainId,
    address: account,
    origin: 'My bot',
});
// ... req.frames on screen, the phone signs, read the answer (see the vault package) ...
await postHlExchange(userSignedExchangeBody(payload, signature, account));

Deposits and withdrawals

| Export | Signature | What it does | |---|---|---| | buildDepositCall | (amount: string) => { chainId, to, data, value } | the deposit: USDC.transfer(HL_BRIDGE, amount) on Arbitrum One, for the vault to sign as a transaction; under the bridge minimum it is refused | | parseUsdcAmount | (amount: string) => bigint | a USDC amount on Arbitrum (6 decimals) | | parseCoreUsdcAmount | (amount: string) => string | a USDC amount as Hyperliquid takes it, normalized; what is signed is what is shown | | checkWithdrawAmount | (amount: string, withdrawable: string) => string | above the fee, within what is withdrawable, normalized | | HL_BRIDGE | 0x2Df1c51E09aECF9cacB7bc98cB1742757f163dF7 | the Hyperliquid bridge on Arbitrum | | USDC_ARBITRUM | 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 | native USDC on Arbitrum One | | MIN_DEPOSIT_USDC | 5 | below this, the bridge loses the deposit | | WITHDRAW_FEE_USDC | 1 | Hyperliquid's flat withdrawal fee | | ARBITRUM_USDC_DECIMALS, CORE_USDC_DECIMALS | 6, 8 | USDC decimals on Arbitrum and on Hyperliquid |

const call = buildDepositCall('20');   // { chainId: '0xa4b1', to: USDC_ARBITRUM, data: '0xa9059cbb...', value: '0x0' }
// build an EIP-1559 transaction from it (nonce, gas), have the vault sign it, send it to an Arbitrum node

Builder fee and referral

| Export | What it is | |---|---| | HL_BUILDER_ADDRESS | Locker's builder address | | HL_BUILDER_MAX_FEE_RATE | '0.05%', the rate approveBuilderFee names | | HL_BUILDER_FEE_TENTHS_BP | 50, the same in tenths of a basis point | | HL_BUILDER_FEE_FRACTION | 0.0005, the same as a fraction of the notional | | HL_REFERRAL_CODE | LOCKERPROTOCOL | | hlFeeRail() | the builder rail, or null when unarmed | | feeRiderFor(rail, approvedTenthsBp) | the fee an order carries given the account's approval: none without it | | builderParam(user) | the fee an order of this account carries now, or null | | builderCollectible() | can the builder collect fees now | | getHlFeeStatus(user) | { armed, collectible, approved, referralCode, maxFeeRate } |

Live data

A WebSocket to wss://api.hyperliquid.xyz/ws that reconnects on its own and routes each message to its subscribers.

| Export | Signature | What it does | |---|---|---| | createHlStream | (opts?) => HlStream | the stream: subscribe(sub, onData) returns an unsubscribe function; onStatus(fn), status() (connecting, open, closed), close() | | HL_WS_URL | 'wss://api.hyperliquid.xyz/ws' | | | parseMids | (data) => Map<string, number> | allMids: perp mids by name | | parseAssetCtx | (data) => HlLiveCtx | activeAssetCtx: mark, mid, oracle, funding, open interest, volume | | parseCandle | (data) => HlLiveCandle | candle | | parseBook | (data) => HlLiveBook | l2Book | | parseTrades | (data) => HlLiveTrade[] | trades | | parseUserFills | (data) => { user, snapshot, fills } | userFills: an account's executions, the first message being a snapshot | | subscriptionKey, messageKey | | the routing keys of a subscription and of a message |

Subscriptions: { type: 'allMids', dex? }, { type: 'activeAssetCtx', coin }, { type: 'candle', coin, interval }, { type: 'l2Book', coin }, { type: 'trades', coin }, { type: 'userFills', user }. Options: url, retryMs, maxRetryMs, pingMs, maxMessageBytes, socket (a WebSocket factory, for tests).

const stream = createHlStream();
const stop = stream.subscribe({ type: 'l2Book', coin: 'ETH' }, (data) => {
    const book = parseBook(data);
    console.log(book.bids[0]?.px, book.asks[0]?.px);
});
stream.subscribe({ type: 'trades', coin: 'ETH' }, (data) => console.log(parseTrades(data)));
// later
stop();
stream.close();

The userFills subscription sends a snapshot of recent executions when it opens and nothing for the time a dropped socket was down. What a feed missed is read back over REST:

| Export | Signature | What it does | |---|---|---| | getHlFillsSince | (user, from) => Promise<{ fills, complete }> | the executions of user from from (ms, included) on, oldest first, each once, read in pages of 2,000; complete is false when the reading stopped at HL_FILLS_MAX_PAGES pages. Never memoized. An account very active keeps only its recent history readable at Hyperliquid (about 21 hours for the busiest trader tried, on 2026-09-30) | | HL_FILLS_PAGE, HL_FILLS_MAX_PAGES | 2000, 5 | the size of a page, and the most pages one reading asks (each weighs about 100 of the 1,200 an IP may spend on /info in a minute) |

const { fills, complete } = await getHlFillsSince('0x5b5d51203a0f9079f8aeb098a6523a13f298c060', Date.now() - 3_600_000);
console.log(fills.length, complete);

Fees

Orders carry a builder fee of 0.05 % to Locker once the account has approved it, and never otherwise: without the approval, orders go out without the fee, they are never blocked. The referral code LOCKERPROTOCOL is set once when the agent is activated; an account that already has a referrer keeps it.

Licence

LOCKER PROTOCOL PROPRIETARY NON-COMMERCIAL LICENSE. See LICENSE.