@candledottv/agent-sdk 0.6.7 → 0.6.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
@@ -52,7 +52,7 @@ The API key is attached as `x-api-key` on every request when configured. The key
52
52
  (`launch`, `launchAsync`, `dryRunLaunch`, `getLaunchJob`, `reportActivity`, `uploadImage`)
53
53
  refuse to fetch without one and throw a plain `Error` locally instead of a server 401.
54
54
 
55
- ## Launching with built-in idempotent retries
55
+ ## Embedded launches with built-in idempotent retries
56
56
 
57
57
  `launch()` fills in a `clientLaunchId` (`"sdk-" + crypto.randomUUID()`) when you omit one, and
58
58
  retries transient failures by re-sending the SAME id, which the server's idempotency ledger
@@ -73,7 +73,7 @@ try {
73
73
  symbol: "TREND",
74
74
  imageUrl: "https://example.com/logo.png",
75
75
  chain: "solana",
76
- buyAmount: 100_000_000, // lamports
76
+ buy: "0.1", // SOL
77
77
  })
78
78
  console.log("minted", result.mint, "explorer:", result.links.explorer, "id:", result.clientLaunchId)
79
79
  } catch (error) {
@@ -100,16 +100,56 @@ else console.error("failed:", job.errorCode)
100
100
  Need a hosted image first? `uploadImage(bytes, contentType)` posts raw bytes to
101
101
  `/api/v1/uploads/agent-image` and returns `{ imageUrl }`, ready for the launch body.
102
102
 
103
- `launch()` works on every plan, Free included: it launches from the account's embedded wallet,
104
- 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.
103
+ `launch()` with an embedded wallet works on every plan, Free included. `buy` adds an optional
104
+ first buy: atomic on Solana (up to 0.5 SOL by default), a best-effort follow-up on Hood.
105
105
 
106
- Two more paths need the Pro or Max plan. `selfLaunch()` launches from a linked or TEE wallet the
107
- agent signs for locally. `launchAtomic()` lands the launch and 1 to 4 first buys in one Jito bundle: several
106
+ A TEE wallet passed to `launch()` needs Pro or Max and the agent signs locally; the deprecated
107
+ `selfLaunch()` follows the same path. `launchAtomic()` lands the launch and 1 to 4 first buys in one Jito bundle: several
108
108
  transactions in the same block, all or none. Each buy is paid by the embedded wallet or a linked
109
109
  wallet; the same payer may fund more than one leg. A TEE wallet can be the creator or a buyer, and
110
- `selfLaunch()` from a TEE wallet can carry a `buyAmount`, only where the server has
110
+ A TEE `launch()` can carry `buy`, only where the server has
111
111
  `TEE_LAUNCH_BUYS_ENABLED` on. It is off by default, and a TEE wallet is refused there until it is.
112
112
 
113
+ ## One launch method
114
+
115
+ `launch()` and `dryRunLaunch()` take the shared generated launch fields. Omit `wallet` or use
116
+ `wallet: "embedded"` to pay from the account's embedded wallet. Name a TEE wallet by label, id or
117
+ address, or pass `{ linkedWalletId, privyWalletId }` for an existing SDK integration. A named
118
+ wallet's chain is inferred; supply `chain: "hood"` for an explicit Hood wallet object. Conflicting
119
+ chains or quote assets are refused before building. The SDK uses your configured `privyAppId`
120
+ and `secretStore` for TEE signing, and `solanaRpcUrl` / `evmRpcUrl` for caller broadcasts.
121
+
122
+ ```ts
123
+ await candle.launch({
124
+ wallet: "spider-01",
125
+ name: "Trend Coin",
126
+ symbol: "TREND",
127
+ imageUrl: "https://example.com/logo.png",
128
+ buy: "0.1", // optional, whole units of the quote asset (SOL by default)
129
+ })
130
+ ```
131
+
132
+ `buy` is a decimal string: SOL has 9 decimals, USDC/CNDL/USDG 6, ETH 18. Empty or zero means no
133
+ first buy. Excess precision and passing both `buy` and deprecated raw `buyAmount` are refused
134
+ locally. `socials` accepts only `website`, `twitter`, `telegram` and `discord`, each an http(s) URL.
135
+ The remaining limits, defaults and field help come from the shared launch definition; the server
136
+ validates ranges and eligibility.
137
+
138
+ Embedded launches use `/launch/headless` with or without a buy. TEE launches use `/launch/self/build`
139
+ and the existing sign/broadcast/confirm flow; a Solana TEE buy signs the returned bundle and sends
140
+ it to `/launch/atomic/submit`. Dry runs use the selected family's `/dry-run`. Existing server
141
+ gates still apply: embedded-wallet allowance, launch availability, and TEE tier, `allowLaunch`
142
+ and first-buy switches. No server switch is enabled by this SDK release. `launchAsync()` remains
143
+ embedded-only.
144
+
145
+ Migration for this release: replace `selfLaunch({ linkedWalletId, privyWalletId, ...fields })`
146
+ with `launch({ wallet: { linkedWalletId, privyWalletId }, ...fields })`. Replace raw `buyAmount`
147
+ with whole-unit `buy`. `selfLaunch()`, `buildSelfLaunch()` and `dryRunSelfLaunch()` are deprecated
148
+ for one release; existing calls still work. `confirmSelfLaunch()` remains the recovery method.
149
+ TEE `launch()` preserves `SelfLaunchOutcomeError` on Hood: after a create-curve broadcast,
150
+ recover by confirming its original id and hashes, never by starting another launch. Embedded
151
+ launch retries and Solana same-id recovery retain their existing behavior.
152
+
113
153
  ## Trading, swaps and account reads
114
154
 
115
155
  ```ts
@@ -223,7 +263,7 @@ safe for a main payer.
223
263
  | `failed`, other | not confirmed. A row with broadcast evidence may still be on chain, and a same-id call answers `stage: "unconfirmed"` for it. The same-id call is the check | call again with the same id |
224
264
  | `built` | in flight or unresolved | a same-id `trade()` answers `IDEMPOTENCY_CONFLICT`. If it carries `stage: "unconfirmed"` and `retryable: false`, check its `signature` on chain and do not retry |
225
265
 
226
- ### `launch()`, `launchAsync()`
266
+ ### Embedded `launch()`, `launchAsync()`
227
267
 
228
268
  Retry with the same `clientLaunchId` and body, or read `getLaunchJob(id)` (`waitForLaunch(id)`
229
269
  polls it). The rules are the ones under "Idempotency" in
@@ -440,28 +480,35 @@ read the existing `GET /api/v1/agent/keys/{prefix}/pnl`. The answer adds an opti
440
480
  `hyperliquid` section, and the CLI prints it under **Hyperliquid**. The existing read
441
481
  authentication applies; on an older API the section is simply absent. No additional signing, deposit or setup is needed for this read.
442
482
 
443
- The section reports main-exchange perp `realizedGrossUsd` (venue `closedPnl`), signed
444
- `fundingUsd` (received positive, paid negative), `feesUsd` (venue fees including builder fees;
445
- rebates are negative), and `realizedNetUsd = realizedGrossUsd + fundingUsd - feesUsd`.
446
- Builder fees are already included in the venue fee and are not subtracted again. These figures
447
- stay separate from spot and LP totals and exclude unrealized perps, deposits and withdrawals.
448
-
449
- Coverage is **currently bound EVM TEE wallets since the current TEE binding**,
450
- shown in `byWallet` with `startTime` in epoch milliseconds. That start is the latest rebind
451
- onto this key, or the wallet's creation time when it was bound then and never rebound. A
452
- rebound wallet does not bring its previous key's history. A wallet-set row is not required,
453
- and an older one cannot move the start earlier than the binding. Revoked and previous
454
- bindings, spot and HIP-3 fills are excluded. This is a binding-period read, not lifetime or
455
- order-level attribution.
456
-
457
- Reads use the venue client's two-second cache. `userFills` is capped at 2,000 recent rows;
458
- `userFunding` at 500 rows from `startTime`, and this response covers at most 20 bound
459
- wallets. `truncated` flags any reached history cap or remaining wallet page; `byWallet` names
460
- `fillsTruncated` and `fundingTruncated`. Funding and fills can cover different time spans when
461
- capped: a partial net must not be quoted as a lifetime figure. On upstream, wallet-discovery or
462
- malformed-data failure the section is `{ read: false, reason }`, without amounts; spot PnL still
463
- answers. An empty successful read is `{ read: true, ... }` with zero amounts. `--json` preserves
464
- the section and its coverage fields. Agent boards are outside this slice.
483
+ The section reports main-exchange perps for **every EVM TEE wallet bound to the key's profile,
484
+ per binding period** (`coverage: "profile"`; revoked, swept and rebound wallets included for the
485
+ time they were the profile's). `realizedGrossUsd` is the venue `closedPnl`, `fundingUsd` is
486
+ signed (received positive, paid negative), `feesUsd` is venue fees including builder fees
487
+ (rebates are negative), and `realizedNetUsd = realizedGrossUsd + fundingUsd - feesUsd`. Builder
488
+ fees are already included in the venue fee and are not subtracted again. `unrealizedUsd` is the
489
+ open positions' unrealized at each wallet's cutoff, `netUsd = realizedNetUsd + unrealizedUsd`
490
+ (both USD decimal strings), and `positions` lists the open positions, each with
491
+ `fundingNetUsd` positive when earned. Deposits and withdrawals are not P&L.
492
+
493
+ Facts and unrealized stop at the same cutoff per wallet. For a wallet still bound to the
494
+ profile, the cutoff is Hyperliquid's position time at this read: the fills and funding since the
495
+ wallet's last stored snapshot are read through that time and must reconcile with the positions
496
+ (each fill continues the previous position, the positions match, and every open hour has its
497
+ funding row). That wallet's `byWallet` entries say `reconciliation: "live"`, and the CLI prints
498
+ "(live, not yet settled)". A wallet whose binding to the profile ended before its last stored
499
+ snapshot is `settled`. `markedAt` is the oldest wallet cutoff, `completeThroughMs` the lowest
500
+ completeness watermark, and `perpsSnapshotId` identifies the cutoff vector. "Reconciled" is not
501
+ "complete": a round opened and closed between two fills Hyperliquid never returned cannot be
502
+ seen.
503
+
504
+ The net is **also counted in the total**: when `read` is true, `pnl.totalUsd` includes `netUsd`
505
+ and the answer's `perpsInTotal` is `true`; the CLI's `Total` line says it includes Hyperliquid.
506
+ When the section cannot be read or reconciled within the request's Hyperliquid budget, it is
507
+ `{ read: false, code, reason }` without amounts, `pnl.totalUsd` is the spot total,
508
+ `perpsInTotal` is `false`, and the CLI says the total excludes perps and why. Never a zero.
509
+ `historyPartial` (and `partialReasons`) flags history the stored record does not cover;
510
+ `truncated` repeats it for older CLIs. At most 20 wallets are read. `--json` preserves the
511
+ section and its coverage fields. Agent boards are outside this slice.
465
512
 
466
513
 
467
514
  ## CNDL staking
package/dist/client.d.ts CHANGED
@@ -19,7 +19,7 @@
19
19
  * endpoints (launch, dry run, jobs, activity, uploads) refuse to fetch at all without one,
20
20
  * throwing a plain `Error` that names the missing option, so a misconfigured agent fails
21
21
  * fast and locally instead of with a server 401.
22
- * - Idempotent launch retries: `launch()` fills in `clientLaunchId` ("sdk-" + UUID) when the
22
+ * - Embedded launch retries: `launch()` fills in `clientLaunchId` ("sdk-" + UUID) when the
23
23
  * caller omits one and re-sends the SAME id on network errors, non-envelope 5xx responses,
24
24
  * retryable envelopes with 5xx status, and the retryable in-flight 409. It never retries a
25
25
  * non-retryable envelope (IDEMPOTENCY_CONFLICT with a different body, LAUNCH_DISABLED, every
@@ -45,6 +45,7 @@ import { type PerpsBookOptions, type PerpsBookResult, type PerpsCandlesOptions,
45
45
  import type { HyperliquidPnlSection } from "./hyperliquid-pnl";
46
46
  import { type PerpsAccountLine, type PerpsAccountReport, type PerpsPortfolioSection, type PerpsPositionRow, type PerpsRiskReport, type PerpsRiskSettings, type PerpsRiskThresholds, type PerpsRiskThresholdsReport, type PerpsWatchEvent } from "./hyperliquid-risk";
47
47
  import { type PerpsWithdrawAuthorization, type PerpsWithdrawBuild, type PerpsWithdrawPins } from "./hyperliquid-withdraw";
48
+ import type { GeneratedLaunchFields } from "./launch-definition";
48
49
  import { type PerpsFillsPage, type PerpsFundingPage, type PerpsHistoryOptions } from "./perps-history";
49
50
  import type { AgentPlansResult, PlanPrice, PlanTable } from "./plans";
50
51
  import type { SecretStore } from "./secret-store";
@@ -230,57 +231,18 @@ export interface LaunchCurve {
230
231
  /** G: the quote the curve raises before it graduates. */
231
232
  threshold: string;
232
233
  }
233
- /** POST /api/v1/launch/headless request body. The server is the authoritative validator. */
234
- export interface LaunchRequest {
235
- /** Idempotency key, unique per account. launch() generates "sdk-" + UUID when absent. */
236
- clientLaunchId?: string;
237
- chain?: Chain;
238
- quoteAsset?: string;
239
- mode?: LaunchTier;
240
- /** `mode: "exp-custom"` only, and required there. Dry-run first: the API checks the limits. */
241
- curve?: LaunchCurve;
242
- /**
243
- * An `exp-` mode only: an extra creator fee of 100 or 200 basis points on top of the curve's 1%
244
- * and the pool's 0.5%, paid to the creator in full. 0 is the same as leaving it out.
245
- */
246
- creatorFeeBps?: 0 | 100 | 200;
247
- stakerAllocationBps?: number;
248
- /** Solana only: the graduated pool's fee. Omitted keeps the flat 50 bps pool. */
249
- poolFee?: PoolFee;
250
- /**
251
- * Solana preset tiers only: "curve_price" opens the pool at the curve's last price and burns the rest.
252
- * Omitted defaults to "curve_price" when stakerAllocationBps plus the team allocation fit the tier's
253
- * limit (dry-run graduation.maxStakerCarveBps), otherwise falls back to "legacy" without refusal.
254
- * Set "legacy" explicitly to opt out. Explicit "curve_price" is refused above the limit.
255
- */
256
- poolOpen?: "legacy" | "curve_price";
257
- /** Solana exp- curves only: "full_range" opens the pool across the whole price range. Omitted is "floor". */
258
- expPoolShape?: "floor" | "full_range";
259
- /** Hood only, required there: which Uniswap version the curve graduates through. */
260
- dexVersion?: "v3" | "v4";
261
- /** Initial dev buy. Solana: JSON number in the pair's base units. Hood: decimal string in wei. */
262
- buyAmount?: number | string;
263
- name: string;
264
- symbol: string;
265
- /** Roughly SQUARE (at most 1.5:1): this is the avatar. Wider is rejected as IMAGE_WRONG_SHAPE. */
266
- imageUrl: string;
267
- /**
268
- * Optional WIDE artwork (wider than 1.5:1, e.g. 1200x630) for the token page's banner strip.
269
- * Where a share card or OG image belongs; a square image here is rejected as
270
- * BANNER_WRONG_SHAPE. Omitted, the strip falls back to `imageUrl`.
271
- */
272
- bannerUrl?: string;
273
- description?: string;
274
- socials?: {
275
- twitter?: string;
276
- telegram?: string;
277
- website?: string;
278
- discord?: string;
234
+ /** Shared launch fields, plus SDK wallet identifiers and the legacy raw first buy. */
235
+ export interface LaunchRequest extends Omit<GeneratedLaunchFields, "wallet" | "dryRun"> {
236
+ /** Omitted means embedded. A TEE wallet may be named by label, address or id. */
237
+ wallet?: string | {
238
+ linkedWalletId: string;
239
+ privyWalletId: string;
279
240
  };
280
- visibility?: "production" | "test" | "local" | "hidden";
241
+ /** @deprecated Use buy, a decimal string in whole quote units, for one release. */
242
+ buyAmount?: number | string;
281
243
  }
282
244
  /** POST /api/v1/launch/self/build request body. Extends LaunchRequest with linkedWalletId. */
283
- export interface BuildSelfLaunchRequest extends LaunchRequest {
245
+ export interface BuildSelfLaunchRequest extends Omit<LaunchRequest, "wallet" | "buy"> {
284
246
  linkedWalletId: string;
285
247
  }
286
248
  /** POST /api/v1/launch/self/build response for Solana (unsigned transaction). */
@@ -1210,8 +1172,18 @@ export interface ProfileChainPnl extends ProfilePnlEngineFields {
1210
1172
  export interface ProfilePnlResult {
1211
1173
  /** Public board figures including fee income; independent of pnl.totalUsd and its coverage. */
1212
1174
  board?: ProfileBoardPnl;
1213
- /** Optional while Hyperliquid is enabled; separate from spot totals. */
1175
+ /**
1176
+ * The key's profile on Hyperliquid, every binding period: its own heading and net, also counted
1177
+ * in `pnl.totalUsd` when `read` is true (see `perpsInTotal`). Unrealized is at each wallet's live
1178
+ * cutoff, and facts stop at that same cutoff. A `read: false` section is never a zero.
1179
+ */
1214
1180
  hyperliquid?: HyperliquidPnlSection;
1181
+ /**
1182
+ * True when `pnl.totalUsd` includes `hyperliquid.netUsd`. False when the section was not read,
1183
+ * and then `pnl.totalUsd` is the spot total. Absent from servers that predate it: their
1184
+ * `pnl.totalUsd` never included perps.
1185
+ */
1186
+ perpsInTotal?: boolean;
1215
1187
  success: true;
1216
1188
  keyPrefix: string;
1217
1189
  pnl: ProfilePnlEngineFields & {
@@ -2888,7 +2860,7 @@ export interface AtomicFirstBuyRequest {
2888
2860
  * buy via `firstBuys` instead, so it lands as bundle leg 1 against a still-virgin curve) plus the
2889
2861
  * creator's own payer and 1-4 first-buy legs.
2890
2862
  */
2891
- export interface BuildAtomicLaunchRequest extends Omit<LaunchRequest, "buyAmount"> {
2863
+ export interface BuildAtomicLaunchRequest extends Omit<LaunchRequest, "buyAmount" | "buy" | "wallet"> {
2892
2864
  payer: AtomicLaunchPayer;
2893
2865
  /** 1 to 4 buy legs, sharing the launch transaction's own recent blockhash and landing atomically with it (Jito's 5-transaction bundle cap: 1 launch + up to 4 buys). */
2894
2866
  firstBuys: AtomicFirstBuyRequest[];
@@ -3156,9 +3128,14 @@ export declare class CandleClient {
3156
3128
  * it. A server that predates the table answers 404 (`CandleApiError`).
3157
3129
  */
3158
3130
  getPlans(): Promise<AgentPlansResult>;
3159
- dryRunLaunch(req: LaunchRequest): Promise<DryRunResult>;
3160
- /**
3161
- * Blocking launch with idempotent retries. Generates `clientLaunchId` when absent and
3131
+ dryRunLaunch(req: LaunchRequest): Promise<DryRunResult | SelfLaunchDryRunResult>;
3132
+ /** Resolve only wallets explicitly named by this caller; server gates remain authoritative. */
3133
+ private prepareLaunch;
3134
+ /**
3135
+ * Launch from the named wallet (embedded by default), optionally with a whole-unit `buy`.
3136
+ * TEE wallets use selfLaunch()'s signing and recovery flow, including SelfLaunchOutcomeError
3137
+ * on Hood. Embedded launches use the idempotent retries described below.
3138
+ * Generates `clientLaunchId` when absent and
3162
3139
  * re-sends the SAME id on retryable failures; see the module doc for the exact policy.
3163
3140
  *
3164
3141
  * The id this call sent, yours or the generated one, is on the result
@@ -3236,9 +3213,10 @@ export declare class CandleClient {
3236
3213
  * `oldestMarkAt`: an unpriced position is counted there, never valued at zero.
3237
3214
  *
3238
3215
  * The figures are the key's share of the account's one P&L read, the console's figures to the
3239
- * cent (`pnl.totalUsd` is the console's P&L). Since 2026-10-02 the total is the sum of the key's
3240
- * wallets, not one pool across them, and `lookback` is the account's activity bound; see
3241
- * `ProfilePnlResult` for every meaning that changed.
3216
+ * cent (`pnl.totalUsd` is the console's P&L, plus the Hyperliquid net when `perpsInTotal`).
3217
+ * Since 2026-10-02 the total is the sum of the key's wallets, not one pool across them, and
3218
+ * `lookback` is the account's activity bound; see `ProfilePnlResult` for every meaning that
3219
+ * changed.
3242
3220
  *
3243
3221
  * Check `unvalued` and `truncated` before quoting the number: the first counts fills that had
3244
3222
  * no trusted USD price and were left out rather than counted as zero, the second says the
@@ -3386,6 +3364,8 @@ export declare class CandleClient {
3386
3364
  * recording anything; the `clientLaunchId` stays unused. Does not check the payer's balance, the
3387
3365
  * day cap, a `clientLaunchId` already used with another body or payer, or a Solana TEE wallet's
3388
3366
  * USD spend window; `buildSelfLaunch()` can still refuse for those.
3367
+ *
3368
+ * @deprecated Use dryRunLaunch({ ...fields, wallet }) for one release.
3389
3369
  */
3390
3370
  dryRunSelfLaunch(req: BuildSelfLaunchRequest): Promise<SelfLaunchDryRunResult>;
3391
3371
  /**
@@ -3400,6 +3380,8 @@ export declare class CandleClient {
3400
3380
  * round trip (build -> sign -> broadcast -> confirm) in one call for both Solana and Hood; call
3401
3381
  * this method directly only to drive the steps yourself. See "Self-signed launches" in
3402
3382
  * docs/headless-launch.md.
3383
+ *
3384
+ * @deprecated Use launch({ ...fields, wallet }) for one release.
3403
3385
  */
3404
3386
  buildSelfLaunch(req: BuildSelfLaunchRequest): Promise<BuildSelfLaunchResult>;
3405
3387
  /** buildSelfLaunch()'s request; selfLaunch() passes its `op` so its exits can expose the id. */
@@ -3669,6 +3651,8 @@ export declare class CandleClient {
3669
3651
  * error's doc describes for each `feeOutcome`. This method sends nothing a second time and
3670
3652
  * does not pay a fee again. An error from before the create-curve receipt is unchanged,
3671
3653
  * including a create-curve broadcast whose answer was lost: that case keeps no hash.
3654
+ *
3655
+ * @deprecated Use launch({ ...fields, wallet }) for one release.
3672
3656
  */
3673
3657
  selfLaunch(req: SelfLaunchRequest): Promise<ConfirmSelfLaunchResult>;
3674
3658
  /** selfLaunch()'s steps. Every error leaves through selfLaunch()'s runOperation(), which adds the id. */
@@ -4103,7 +4087,7 @@ export declare function __setEvmReceiptWaitForTest(opts: {
4103
4087
  pollMs?: number;
4104
4088
  } | null): void;
4105
4089
  /** This build's own version. Kept in lockstep with package.json by the release-bump CI guard. */
4106
- export declare const SDK_VERSION = "0.6.7";
4090
+ export declare const SDK_VERSION = "0.6.8";
4107
4091
  /** Test seam: the once-per-process latch would otherwise weld the suite's first case to the rest. */
4108
4092
  export declare function __resetSdkUpdateNoticeForTest(): void;
4109
4093
  //# sourceMappingURL=client.d.ts.map