@candledottv/agent-sdk 0.4.5 → 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,21 +1,24 @@
1
1
  # @candledottv/agent-sdk
2
2
 
3
3
  A typed TypeScript SDK for the Candle agent rail. It wraps the REST surface documented in
4
- `docs/headless-launch.md` (headless launches, jobs, dry runs, market state, quotes, feeds,
5
- verification, presets, agent profiles, image uploads), ships the webhook signature verifier,
6
- and drives the client-side HPKE seal behind linked-wallet import, so an agent integrates
7
- against typed methods instead of hand-rolled HTTP.
8
-
9
- Built on the global `fetch`; runs on Bun and Node 18+. Three runtime dependencies --
10
- `@hpke/core`, `@hpke/chacha20poly1305`, and `@scure/base` -- exist solely to power
11
- `importWallet()`'s client-side HPKE seal and base58 decode (see "Importing a wallet" below);
12
- nothing else in the SDK needs them. The one `node:` builtin used is `node:crypto` (webhook
4
+ [Headless launch](https://docs.candle.tv/developers/headless-launch) and
5
+ [Agent trading](https://docs.candle.tv/developers/agent-trading) (launches, jobs, dry runs, trades,
6
+ swaps, market state, quotes, feeds, verification, presets, plans, P&L, agent profiles, image
7
+ uploads), ships the webhook signature verifier, and drives the client-side HPKE seal behind
8
+ linked-wallet import, so an agent integrates against typed methods instead of hand-rolled HTTP.
9
+ The full guide is [TypeScript SDK](https://docs.candle.tv/developers/sdk).
10
+
11
+ Built on the global `fetch`; runs on Bun and Node 18+. Five runtime dependencies:
12
+ `@hpke/core`, `@hpke/chacha20poly1305` and `@scure/base` power `importWallet()`'s client-side
13
+ HPKE seal and base58 decode (see "Importing a wallet" below), and `canonicalize` and
14
+ `@noble/hashes` build the payloads a key signer signs (Privy authorization signatures and
15
+ Hyperliquid actions). The one `node:` builtin used is `node:crypto` (webhook
13
16
  verification only), which Bun also provides. Edge runtimes without `node:crypto` would need a
14
17
  Web Crypto port of the verifier; that is a deliberate later concern.
15
18
 
16
- > **Not yet published to npm.** Publishing `@candledottv/agent-sdk` (and `@candledottv/mcp`)
17
- > is the post-Phase-2 follow-up. Until then, consume it as a workspace package:
18
- > `import { CandleClient } from "@candledottv/agent-sdk"`.
19
+ ```bash
20
+ npm i @candledottv/agent-sdk
21
+ ```
19
22
 
20
23
  ## Quick start
21
24
 
@@ -91,6 +94,33 @@ else console.error("failed:", job.errorCode)
91
94
  Need a hosted image first? `uploadImage(bytes, contentType)` posts raw bytes to
92
95
  `/api/v1/uploads/agent-image` and returns `{ imageUrl }`, ready for the launch body.
93
96
 
97
+ `selfLaunch()` launches from a linked wallet the agent signs for locally, and `launchAtomic()`
98
+ launches and seeds in one transaction; both need the Pro or Max plan.
99
+
100
+ ## Trading, swaps and account reads
101
+
102
+ ```ts
103
+ const fill = await candle.trade({ mint: "9dXSV8...CNDL", side: "buy", amountRaw: "200000000", from: "main" })
104
+ // fill.amounts.expectedOutRaw is the quote; fill.amounts.actualOutRaw is what arrived (Solana only)
105
+ ```
106
+
107
+ - `trade()` buys or sells a token in one call, from the account's main wallet (executed inline)
108
+ or from a linked wallet the caller signs for. Amounts are raw units. On Solana,
109
+ `amounts.actualOutRaw` is the delivered amount, decoded from the payer's balance change; book
110
+ positions from it rather than from `expectedOutRaw`. It is absent on Hood.
111
+ - `swap()` converts base assets (`SOL`, `USDC`, `CNDL`, `ETH`, `USDG`); a pair that spans Solana
112
+ and Hood is a bridge.
113
+ - `getPlans()` (no key) returns every plan's price, fees, limits and capabilities as the server
114
+ serves them.
115
+ - `getPortfolio()`, `getProfilePnl(keyPrefix)`, `getProfileTrades(keyPrefix)` and
116
+ `getSpendLimits()` read the account's holdings, a profile's P&L and fills, and this key's caps.
117
+ - `closeEmptyAccounts()` closes the embedded wallet's empty token accounts and returns the rent.
118
+ - The `perps*` methods (`perpsSetup`, `perpsOpen`, `perpsClose`, `perpsOrders`,
119
+ `perpsPositions`, ...) drive Hyperliquid perps.
120
+
121
+ Limit orders are a REST surface only (`/api/v1/trade/agent/orders`); the SDK has no method for
122
+ them.
123
+
94
124
  ## Importing a wallet
95
125
 
96
126
  `importWallet()` drives Candle's ciphertext-only wallet import end to end: it fetches Privy's
@@ -149,7 +179,8 @@ async function handleWebhook(req: Request): Promise<Response> {
149
179
  if (!ok) return new Response("invalid signature", { status: 401 })
150
180
 
151
181
  const event = JSON.parse(rawBody)
152
- // handle launch.confirmed, launch.failed, curve.graduated, migration.completed, migration.delayed
182
+ // event is one of the sixteen the endpoint subscribed to: launch.confirmed, trade.executed,
183
+ // order.triggered, transfer.executed, key.access_widened, ... (see the Webhooks docs page)
153
184
  return new Response("ok")
154
185
  }
155
186
  ```
@@ -160,9 +191,12 @@ bodies all return `false`. Comparison is constant-time (`timingSafeEqual`).
160
191
  ## Errors
161
192
 
162
193
  Every non-2xx response throws `CandleApiError` with `code`, `status`, `retryable`, and
163
- (for field-level validation) `field`. Structured envelopes map straight through; the few
164
- legacy endpoints without envelopes (activity, users) surface as `code: "HTTP_<status>"`.
165
- The full code table lives in `docs/headless-launch.md`.
194
+ (for field-level validation) `field`, plus `routing`, `discovery`, `coverage`, `uiHint` and
195
+ `docsPath` when the envelope carries them. Structured envelopes map straight through; the few
196
+ legacy endpoints without envelopes (activity, users) surface as `code: "HTTP_<status>"`. A
197
+ Solana or EVM JSON-RPC failure throws `JsonRpcError`, with the RPC's numeric `code` and its
198
+ `data` (for a failed simulation, `{ err, logs }`). The full code table is on
199
+ [Headless launch](https://docs.candle.tv/developers/headless-launch).
166
200
 
167
201
  ## Development
168
202
 
@@ -170,3 +204,33 @@ The full code table lives in `docs/headless-launch.md`.
170
204
  bun test # pure tests against an injected fake fetch; no server, no network
171
205
  bun run typecheck # tsc --noEmit
172
206
  ```
207
+
208
+ ### Hyperliquid per-key PnL
209
+
210
+ `candle pnl --profile <name>` / SDK `getProfilePnl(keyPrefix)` / MCP `candle_get_profile_pnl`
211
+ read the existing `GET /api/v1/agent/keys/{prefix}/pnl`. The answer adds an optional
212
+ `hyperliquid` section, and the CLI prints it under **Hyperliquid**. The existing read
213
+ authentication applies; on an older API the section is simply absent. No additional signing, deposit or setup is needed for this read.
214
+
215
+ The section reports main-exchange perp `realizedGrossUsd` (venue `closedPnl`), signed
216
+ `fundingUsd` (received positive, paid negative), `feesUsd` (venue fees including builder fees;
217
+ rebates are negative), and `realizedNetUsd = realizedGrossUsd + fundingUsd - feesUsd`.
218
+ Builder fees are already included in the venue fee and are not subtracted again. These figures
219
+ stay separate from spot and LP totals and exclude unrealized perps, deposits and withdrawals.
220
+
221
+ Coverage is **currently bound EVM TEE wallets since the current TEE binding**,
222
+ shown in `byWallet` with `startTime` in epoch milliseconds. That start is the latest rebind
223
+ onto this key, or the wallet's creation time when it was bound then and never rebound. A
224
+ rebound wallet does not bring its previous key's history. A wallet-set row is not required,
225
+ and an older one cannot move the start earlier than the binding. Revoked and previous
226
+ bindings, spot and HIP-3 fills are excluded. This is a binding-period read, not lifetime or
227
+ order-level attribution.
228
+
229
+ Reads use the venue client's two-second cache. `userFills` is capped at 2,000 recent rows;
230
+ `userFunding` at 500 rows from `startTime`, and this response covers at most 20 bound
231
+ wallets. `truncated` flags any reached history cap or remaining wallet page; `byWallet` names
232
+ `fillsTruncated` and `fundingTruncated`. Funding and fills can cover different time spans when
233
+ capped: a partial net must not be quoted as a lifetime figure. On upstream, wallet-discovery or
234
+ malformed-data failure the section is `{ read: false, reason }`, without amounts; spot PnL still
235
+ answers. An empty successful read is `{ read: true, ... }` with zero amounts. `--json` preserves
236
+ the section and its coverage fields. Agent boards are outside this slice.