@candledottv/agent-sdk 0.4.6 → 0.4.8

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,40 @@ 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
+ `launch()` works on every plan, Free included: it launches from the account's embedded wallet,
98
+ and `buyAmount` adds an optional dev buy: in the launch transaction on Solana (up to 0.5 SOL by default), a best-effort follow-up transaction on Hood.
99
+
100
+ Two more paths need the Pro or Max plan. `selfLaunch()` launches from a linked or TEE wallet the
101
+ agent signs for locally. `launchAtomic()` lands the launch and 1 to 4 first buys in one Jito bundle: several
102
+ transactions in the same block, all or none. Each buy is paid by the embedded wallet or a linked
103
+ wallet; the same payer may fund more than one leg. A TEE wallet can be the creator or a buyer, and
104
+ `selfLaunch()` from a TEE wallet can carry a `buyAmount`, only where the server has
105
+ `TEE_LAUNCH_BUYS_ENABLED` on. It is off by default, and a TEE wallet is refused there until it is.
106
+
107
+ ## Trading, swaps and account reads
108
+
109
+ ```ts
110
+ const fill = await candle.trade({ mint: "9dXSV8...CNDL", side: "buy", amountRaw: "200000000", from: "main" })
111
+ // fill.amounts.expectedOutRaw is the quote; fill.amounts.actualOutRaw is what arrived (Solana only)
112
+ ```
113
+
114
+ - `trade()` buys or sells a token in one call, from the account's embedded wallet (executed inline)
115
+ or from a linked wallet the caller signs for. Amounts are raw units. On Solana,
116
+ `amounts.actualOutRaw` is the delivered amount, decoded from the payer's balance change; book
117
+ positions from it rather than from `expectedOutRaw`. It is absent on Hood.
118
+ - `swap()` converts base assets (`SOL`, `USDC`, `CNDL`, `ETH`, `USDG`); a pair that spans Solana
119
+ and Hood is a bridge.
120
+ - `getPlans()` (no key) returns every plan's price, fees, limits and capabilities as the server
121
+ serves them.
122
+ - `getPortfolio()`, `getProfilePnl(keyPrefix)`, `getProfileTrades(keyPrefix)` and
123
+ `getSpendLimits()` read the account's holdings, a profile's P&L and fills, and this key's caps.
124
+ - `closeEmptyAccounts()` closes the embedded wallet's empty token accounts and returns the rent.
125
+ - The `perps*` methods (`perpsSetup`, `perpsOpen`, `perpsClose`, `perpsOrders`,
126
+ `perpsPositions`, ...) drive Hyperliquid perps.
127
+
128
+ Limit orders are a REST surface only (`/api/v1/trade/agent/orders`); the SDK has no method for
129
+ them.
130
+
94
131
  ## Importing a wallet
95
132
 
96
133
  `importWallet()` drives Candle's ciphertext-only wallet import end to end: it fetches Privy's
@@ -149,7 +186,8 @@ async function handleWebhook(req: Request): Promise<Response> {
149
186
  if (!ok) return new Response("invalid signature", { status: 401 })
150
187
 
151
188
  const event = JSON.parse(rawBody)
152
- // handle launch.confirmed, launch.failed, curve.graduated, migration.completed, migration.delayed
189
+ // event is one of the sixteen the endpoint subscribed to: launch.confirmed, trade.executed,
190
+ // order.triggered, transfer.executed, key.access_widened, ... (see the Webhooks docs page)
153
191
  return new Response("ok")
154
192
  }
155
193
  ```
@@ -160,9 +198,12 @@ bodies all return `false`. Comparison is constant-time (`timingSafeEqual`).
160
198
  ## Errors
161
199
 
162
200
  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`.
201
+ (for field-level validation) `field`, plus `routing`, `discovery`, `coverage`, `uiHint` and
202
+ `docsPath` when the envelope carries them. Structured envelopes map straight through; the few
203
+ legacy endpoints without envelopes (activity, users) surface as `code: "HTTP_<status>"`. A
204
+ Solana or EVM JSON-RPC failure throws `JsonRpcError`, with the RPC's numeric `code` and its
205
+ `data` (for a failed simulation, `{ err, logs }`). The full code table is on
206
+ [Headless launch](https://docs.candle.tv/developers/headless-launch).
166
207
 
167
208
  ## Development
168
209
 
@@ -170,3 +211,33 @@ The full code table lives in `docs/headless-launch.md`.
170
211
  bun test # pure tests against an injected fake fetch; no server, no network
171
212
  bun run typecheck # tsc --noEmit
172
213
  ```
214
+
215
+ ### Hyperliquid per-key PnL
216
+
217
+ `candle pnl --profile <name>` / SDK `getProfilePnl(keyPrefix)` / MCP `candle_get_profile_pnl`
218
+ read the existing `GET /api/v1/agent/keys/{prefix}/pnl`. The answer adds an optional
219
+ `hyperliquid` section, and the CLI prints it under **Hyperliquid**. The existing read
220
+ authentication applies; on an older API the section is simply absent. No additional signing, deposit or setup is needed for this read.
221
+
222
+ The section reports main-exchange perp `realizedGrossUsd` (venue `closedPnl`), signed
223
+ `fundingUsd` (received positive, paid negative), `feesUsd` (venue fees including builder fees;
224
+ rebates are negative), and `realizedNetUsd = realizedGrossUsd + fundingUsd - feesUsd`.
225
+ Builder fees are already included in the venue fee and are not subtracted again. These figures
226
+ stay separate from spot and LP totals and exclude unrealized perps, deposits and withdrawals.
227
+
228
+ Coverage is **currently bound EVM TEE wallets since the current TEE binding**,
229
+ shown in `byWallet` with `startTime` in epoch milliseconds. That start is the latest rebind
230
+ onto this key, or the wallet's creation time when it was bound then and never rebound. A
231
+ rebound wallet does not bring its previous key's history. A wallet-set row is not required,
232
+ and an older one cannot move the start earlier than the binding. Revoked and previous
233
+ bindings, spot and HIP-3 fills are excluded. This is a binding-period read, not lifetime or
234
+ order-level attribution.
235
+
236
+ Reads use the venue client's two-second cache. `userFills` is capped at 2,000 recent rows;
237
+ `userFunding` at 500 rows from `startTime`, and this response covers at most 20 bound
238
+ wallets. `truncated` flags any reached history cap or remaining wallet page; `byWallet` names
239
+ `fillsTruncated` and `fundingTruncated`. Funding and fills can cover different time spans when
240
+ capped: a partial net must not be quoted as a lifetime figure. On upstream, wallet-discovery or
241
+ malformed-data failure the section is `{ read: false, reason }`, without amounts; spot PnL still
242
+ answers. An empty successful read is `{ read: true, ... }` with zero amounts. `--json` preserves
243
+ the section and its coverage fields. Agent boards are outside this slice.