hotstuff-market-cli
v0.1.3
Published
Hotstuff market + trading CLI powered by the official TypeScript SDK.
Maintainers
Readme
Hotstuff CLI
Terminal Preview
Features
- Prompted credential setup stored in
credentials.jsonin the current working directory - Market data commands for price discovery and monitoring
- Trade commands for place/cancel/order tracking
- Mainnet/testnet switching via env vars
- SDK-compatible transport and signing wrappers that mirror the latest request shapes
Install
npm install -g hotstuff-market-cliAliases available after install:
hotstuffhotstuff-marketcli
Quick Start
# 1) Configure API credentials once
node ./cli.mjs auth setup
# 2) Confirm auth is ready
node ./cli.mjs auth status
# 3) Inspect market
node ./cli.mjs market price BTC
# 4) Place an order
node ./cli.mjs trade buy BTC 0.01 70000
# 5) Check account state
node ./cli.mjs trade orders --limit 20
node ./cli.mjs trade positionsIf credentials are missing or the signer is not authorized, the CLI stops before placing the order and shows the next auth step to run.
auth setup always asks for the main account address and agent private key, then overwrites credentials.json in the current working directory.
Commands
Auth
node ./cli.mjs auth setup
node ./cli.mjs auth setup --private-key 0x... --address 0x...
node ./cli.mjs auth status
node ./cli.mjs auth clearRecommended order:
- Run
node ./cli.mjs auth setupand enter the main account address plus agent key when prompted - Run
node ./cli.mjs auth status - Trade only after the status output shows the expected account and signer
Market
node ./cli.mjs market list [--type all|perps|spot]
node ./cli.mjs market price <SYMBOL>
node ./cli.mjs market tickers [--market perp|spot|all] [--limit N]
node ./cli.mjs market candles <SYMBOL> [--period SECONDS] [--from UNIX] [--to UNIX] [--type mark|ltp|index]
node ./cli.mjs market orderbook <SYMBOL> [--depth N]
node ./cli.mjs market instruments [perps|spot|all]
node ./cli.mjs market ticker <SYMBOL>
node ./cli.mjs market oracle <ASSET>
node ./cli.mjs market supported-collateral <ASSET>
node ./cli.mjs market bbo <SYMBOL>
node ./cli.mjs market mids <SYMBOL>
node ./cli.mjs market trades <SYMBOL> [LIMIT]
node ./cli.mjs market chart <SYMBOL> <RES> <TYPE> <FROM_UNIX> <TO_UNIX>Trade
node ./cli.mjs trade buy <SYMBOL> <SIZE> <PRICE> [--position LONG|SHORT|BOTH] [--tif GTC|IOC|FOK] [--reduce-only] [--post-only] [--cloid ID] [--expires EPOCH_MS]
node ./cli.mjs trade sell <SYMBOL> <SIZE> <PRICE> [--position LONG|SHORT|BOTH] [--tif GTC|IOC|FOK] [--reduce-only] [--post-only] [--cloid ID] [--expires EPOCH_MS]
node ./cli.mjs trade cancel <SYMBOL> (--oid ORDER_ID | --cloid CLIENT_ID) [--expires EPOCH_MS]
node ./cli.mjs trade cancel-instrument <SYMBOL> [--expires EPOCH_MS]
node ./cli.mjs trade cancel-all [--expires EPOCH_MS]
node ./cli.mjs trade orders [--limit N] [--page N]
node ./cli.mjs trade positionsFor troubleshooting signer mismatches, add --debug or set HOTSTUFF_DEBUG=1 on trade commands.
CLI ↔ SDK Sync
The CLI uses SDK-compatible transport and signing wrappers:
createInfoClient()andcreateExplorerClient()are thin RPC proxies to the SDK info/explorer endpointscreateExchangeClient()signs exchange actions with the SDK'ssignAction,NonceManager, andEXCHANGE_OP_CODESutilitiescreateWebSocketTransport()andcreateHttpTransport()mirror the SDK transport behavior
Market command mapping:
| CLI command | SDK client method | Input payload | Output shape |
| --- | --- | --- | --- |
| market price <SYMBOL> | info.ticker, info.bbo, info.oracle | { symbol } | ticker array, bbo array, oracle object |
| market supported-collateral <ASSET> | info.supportedCollateral | { symbol } | collateral array |
| market mids <SYMBOL> | info.mids | { symbol } | mids array |
| market candles <SYMBOL> ... | info.chart | { instrument_id, resolution, from, to, chart_type } | chart point array |
| market chart <SYMBOL> ... | info.chart | { instrument_id, resolution, from, to, chart_type } | chart point array |
| market orderbook <SYMBOL> | info.orderbook | { symbol, depth? } | orderbook object |
| market trades <SYMBOL> | info.trades | { symbol, limit? } | trades array |
| market ticker <SYMBOL> | info.ticker | { symbol } | ticker array |
| market bbo <SYMBOL> | info.bbo | { symbol } | bbo array |
| market oracle <ASSET> | info.oracle | { symbol } | oracle object |
Trade command mapping:
| CLI command | SDK client method | Input payload | Output shape |
| --- | --- | --- | --- |
| trade buy ... | exchange.placeOrder | { orders: [{ instrumentId, side, positionSide, price, size, tif, ro, po, cloid, triggerPx, isMarket, tpsl, grouping }], expiresAfter } | exchange response |
| trade sell ... | exchange.placeOrder | same as buy, with side: "s" | exchange response |
| trade cancel <SYMBOL> --oid | exchange.cancelByOid | { cancels: [{ oid, instrumentId }], expiresAfter } | exchange response |
| trade cancel <SYMBOL> --cloid | exchange.cancelByCloid | { cancels: [{ cloid, instrumentId }], expiresAfter } | exchange response |
| trade cancel-instrument <SYMBOL> | exchange.cancelByInstrument | { instrumentId, expiresAfter } | exchange response |
| trade cancel-all | exchange.cancelAll | { expiresAfter } | exchange response |
| trade orders | info.openOrders | { user, page?, limit? } | paginated open orders |
| trade positions | info.positions | { user } | positions array |
Notes:
market candlesandmarket chartresolve the symbol to aninstrument_idbefore callinginfo.chart, matching the latest SDK signature.market midsis now symbol-based because the latest SDK requires{ symbol }.- The CLI keeps the helper aliases in
src/sdk.mjs, but the requests and payload shapes now track the latest SDK signatures.
Network Selection
Use testnet with either variable:
export HOTSTUFF_TESTNET=1
# or
export DATA_ENV=testnetIf neither is set, mainnet is used.
Credential Storage
- File:
credentials.jsonin the current working directory - Saved and overwritten by
node ./cli.mjs auth setup - Cleared with
node ./cli.mjs auth clear - The account address can be the main trading account, while the private key can be an authorized agent signer.
auth setupasks for both values every time and overwrites the old file.- The CLI checks the signer against the account's authorized agents before sending a trade.
- If the signer is missing or unauthorized, the command exits with a clear auth message instead of sending the order.
auth statusprints both the account address and signer address so you can confirm they match the intended account context.
Security reminder:
- Never share private keys
- Use a dedicated API trading key where possible
Local Development
npm install
npm link
hotstuff helpUseful scripts:
npm run cli -- help
npm run pack:checkProject Structure
cli.mjs # CLI entrypoint + top-level routing
src/sdk.mjs # standard client layer: HTTP/WS + info/exchange/explorer/subscriptions
src/market.mjs # market command handlers
src/auth.mjs # account + agent credential setup, status, clear, and credentials.json handling in the current working directory
src/trade.mjs # buy/sell/cancel/order commands
src/ui.mjs # help/cards/structured output renderingSDK Methods
RPC methods (Info/Explorer/Exchange)
src/sdk.mjs uses a dynamic RPC proxy, so new SDK methods are callable directly without updating a local method list.
import { createInfoClient, createExplorerClient } from "./src/sdk.mjs";
const info = createInfoClient();
const explorer = createExplorerClient();
await info.someNewMethod({ ...params });
await explorer.someExplorerMethod({ ...params });Subscription methods
Add a channel alias once in SUBSCRIPTION_METHODS:
export const SUBSCRIPTION_METHODS = {
...,
myFeed: {
channel: "my_feed",
normalize: (params = {}) => ({ ...params }),
},
};Then use it directly:
const subscriptions = createSubscriptionClient();
await subscriptions.myFeed({ ...params }, (event) => {
console.log(event.detail);
});