@candledottv/agent-sdk 0.4.10 → 0.5.0

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/dist/client.d.ts CHANGED
@@ -26,11 +26,23 @@
26
26
  * validation error), and it never retries a launch whose stage is `executed` or `unconfirmed`
27
27
  * or whose error already names a mint. Backoff is 250ms * 2^n, jittered to 50-100% of that,
28
28
  * capped at 8s, bounded by `maxRetries` (default 3 retries after the initial attempt).
29
+ * - The id on every outcome. The six one-call write methods (`trade()`, `launch()`,
30
+ * `launchAsync()`, `selfLaunch()`, `buildAtomicLaunch()`, `launchAtomic()`) send one idempotency
31
+ * id per call, the caller's or a generated one, and once the first request carrying it has been
32
+ * sent, every exit exposes that id: on the returned value, and on the thrown error
33
+ * (`operationIds(error)`). A `CandleApiError` or `JsonRpcError` keeps its class and gains the id;
34
+ * anything else (a rejected fetch, a 2xx body that is not JSON, a plain Error from one of the
35
+ * method's own steps) is wrapped once, at the outermost method, in a `CandleOperationError` with
36
+ * the original as `cause`. An error raised before anything was sent (no API key) carries no id
37
+ * and is not wrapped. The SDK never reuses an id between calls and adds no retry of its own: a
38
+ * call that passes no id is a new operation. The retry is the caller's, with the id passed back.
39
+ * The README's "Retrying a write that failed or timed out" is the caller-facing procedure.
29
40
  */
30
41
  import { type HyperliquidNetwork, type HyperliquidTypedData } from "./hyperliquid";
31
42
  import type { HyperliquidPnlSection } from "./hyperliquid-pnl";
32
43
  import type { AgentPlansResult, PlanPrice, PlanTable } from "./plans";
33
44
  import type { SecretStore } from "./secret-store";
45
+ import type { CandleStaking } from "./staking";
34
46
  import { type WalletChain } from "./wallet-import";
35
47
  export type Chain = "solana" | "hood";
36
48
  /**
@@ -277,9 +289,15 @@ export interface SelfLaunchDryRunResult extends Omit<DryRunResult, "launchWallet
277
289
  launchWallet: string;
278
290
  launchWalletId: string;
279
291
  }
280
- /** POST /api/v1/launch/headless blocking (or replayed) success response. */
292
+ /**
293
+ * POST /api/v1/launch/headless blocking (or replayed) success response, plus `clientLaunchId`.
294
+ * The server's body does not carry the id: `launch()`, `selfLaunch()` and `confirmSelfLaunch()`
295
+ * set it from the request they sent, so a caller who let the SDK generate it still has it.
296
+ */
281
297
  export interface LaunchResult {
282
298
  success: true;
299
+ /** The idempotency id this launch was sent under, the caller's or the generated one. */
300
+ clientLaunchId: string;
283
301
  chain: Chain;
284
302
  mint: string;
285
303
  pool: string | null;
@@ -462,6 +480,51 @@ export interface AgentProfile {
462
480
  launches: number;
463
481
  launchesViaApi: number;
464
482
  }
483
+ /** How `listAgents` orders the directory, each largest first. */
484
+ export type AgentDirectorySort = "newest" | "active" | "pnl";
485
+ /** One published agent, as `listAgents` returns it. Identity and three aggregates: no wallet, no position. */
486
+ export interface AgentDirectoryEntry {
487
+ /** The stable id, `prof_` and 16 hex. `GET /api/v1/agent/records/:profileId` reads its record. */
488
+ profileId: string;
489
+ /** The short address of the agent's page, `/agents/profile/<slug>`, or null. */
490
+ slug: string | null;
491
+ name: string;
492
+ avatarUrl: string | null;
493
+ bio: string | null;
494
+ owner: {
495
+ username: string | null;
496
+ };
497
+ strategy: string | null;
498
+ /** What the owner declared the agent runs on. Shown only: the directory has no model filter. */
499
+ models: string[];
500
+ /** Unix ms. */
501
+ publishedAt: number;
502
+ /** The newest trade or launch, unix ms. Null for an agent that has done neither. */
503
+ lastActiveAt: number | null;
504
+ /** All-time realized plus unrealized, USD, refreshed about every ten minutes. Null until first computed. */
505
+ totalPnlUsd: number | null;
506
+ tradeCount: number;
507
+ launchCount: number;
508
+ /** More launches exist than `launchCount` counted. */
509
+ launchesCapped: boolean;
510
+ }
511
+ /** One page of the directory. `cursor` is null on the last page, and always for a search. */
512
+ export interface AgentDirectoryPage {
513
+ entries: AgentDirectoryEntry[];
514
+ cursor: string | null;
515
+ }
516
+ export interface ListAgentsOptions {
517
+ /** `newest` (default), `active` or `pnl`. */
518
+ sort?: AgentDirectorySort;
519
+ /** Keep one strategy category, such as `momentum`. An unknown one is refused with 400. */
520
+ strategy?: string;
521
+ /** Match the name, the slug or the owner's handle. At most 25 agents, unpaged. */
522
+ query?: string;
523
+ /** Agents per page, 1 to 48. Default 24. */
524
+ limit?: number;
525
+ /** The previous page's `cursor`. */
526
+ cursor?: string;
527
+ }
465
528
  /**
466
529
  * GET /api/v1/agent/tier response, returned whole (same convention as `verify()`: the top-level
467
530
  * body IS the useful object, no envelope to unwrap). Dual auth: an agent key works here, and so
@@ -1402,6 +1465,42 @@ export type ConfirmTradeRequest = {
1402
1465
  };
1403
1466
  /** POST /api/v1/trade/agent/confirm response. Always "executed": confirm only ever verifies and records a trade that already happened on-chain. */
1404
1467
  export type ConfirmTradeResult = ExecutedTradeResult;
1468
+ /**
1469
+ * One trade from the idempotency ledger, from GET /api/v1/trade/agent/jobs/:clientTradeId
1470
+ * (`getTradeJob()`). `amountRaw` is raw units: the quote asset's on a buy, the token's on a sell.
1471
+ * `status` is `built` (in flight, or built and never confirmed), `confirmed` (landed; `signature`
1472
+ * is set) or `failed` (`errorCode` says why; `TRADE_REVERTED` means it landed and reverted).
1473
+ */
1474
+ export interface TradeJob {
1475
+ clientTradeId: string;
1476
+ chain: Chain;
1477
+ side: TradeSide;
1478
+ mint: string;
1479
+ quoteAsset: string;
1480
+ amountRaw: string;
1481
+ status: "built" | "confirmed" | "failed";
1482
+ signature?: string;
1483
+ errorCode?: string;
1484
+ createdAt: number;
1485
+ updatedAt: number;
1486
+ /** A Hood TEE trade only: its sequenced operation, leg by leg. `kind` and `status` are open strings. */
1487
+ operation?: {
1488
+ operationId: string;
1489
+ kind: string;
1490
+ status: string;
1491
+ plannedLegCount: number;
1492
+ currentLegIndex: number;
1493
+ legs: Array<{
1494
+ kind: string;
1495
+ status: string;
1496
+ hash?: string;
1497
+ nonce?: number;
1498
+ }>;
1499
+ expiresAt: number;
1500
+ /** The fee a trade that landed after its lock expired still owes, once the read has recorded it. */
1501
+ feeOwed?: Record<string, unknown>;
1502
+ };
1503
+ }
1405
1504
  /**
1406
1505
  * POST /api/v1/trade/agent/submit request body. `signedTransactions` is the ordered signed legs:
1407
1506
  * one for Solana; one to four for Hood in the fixed approval, permit2Approval, trade, feeTransfer
@@ -2093,7 +2192,10 @@ export interface TradeRequest {
2093
2192
  * The server defaults it when omitted, which is `sol` on Solana and ETH settlement on Hood.
2094
2193
  */
2095
2194
  quoteAsset?: "sol" | "usdc" | "cndl" | "eth" | "usdg";
2096
- /** Idempotency key shared by the build and confirm calls; generated ("sdk-" + UUID) when omitted. */
2195
+ /**
2196
+ * Idempotency key shared by the build and confirm calls; generated ("sdk-" + UUID) when omitted.
2197
+ * Pass your own for anything that moves funds and store it before the call: see `trade()`.
2198
+ */
2097
2199
  clientTradeId?: string;
2098
2200
  }
2099
2201
  /** selfLaunch()'s one-call request: BuildSelfLaunchRequest plus the linked wallet's Privy wallet id. */
@@ -2145,8 +2247,14 @@ export interface AtomicBundleResponseLeg {
2145
2247
  amountOutRaw: string;
2146
2248
  };
2147
2249
  }
2148
- /** POST /api/v1/launch/atomic/build response. */
2250
+ /**
2251
+ * POST /api/v1/launch/atomic/build response, plus `clientLaunchId`. The server's body does not
2252
+ * carry the id: `buildAtomicLaunch()` sets it from the request it sent. It is the launch's
2253
+ * identity (`bundleId` is single-use), so a caller driving build and submit by hand keeps it.
2254
+ */
2149
2255
  export interface BuildAtomicLaunchResult {
2256
+ /** The idempotency id this build was sent under, the caller's or the generated one. */
2257
+ clientLaunchId: string;
2150
2258
  bundleId: string;
2151
2259
  legs: AtomicBundleResponseLeg[];
2152
2260
  expiresAt: number;
@@ -2165,14 +2273,21 @@ export interface SubmitAtomicLaunchRequest {
2165
2273
  * are the 502 body -- all three are NORMAL, expected outcomes of submitting a Jito bundle that
2166
2274
  * this route documents as part of its own response surface, so `submitAtomicLaunch()`/
2167
2275
  * `launchAtomic()` return them here rather than throwing `CandleApiError` (every OTHER non-2xx
2168
- * status still throws, same as every other method). `retryable` is always `false` for `"failed"`;
2169
- * for `"timeout"` it is `true` only when the bundle's shared blockhash was proven to have expired
2170
- * with no confirmation -- `false` means the resolution window simply ran out with no definitive
2171
- * answer and the bundle MIGHT STILL LAND, so the caller should wait rather than immediately
2172
- * rebuild under a fresh `clientLaunchId`. In every case, `bundleId` itself is dead once this
2173
- * response arrives: it is consumed on the first `/submit` call regardless of outcome, so recovery
2174
- * is always a fresh `buildAtomicLaunch()`/`launchAtomic()` call, never a retried `submit` with the
2175
- * same id. See "Atomic launch with first buys" in docs/headless-launch.md for the full model.
2276
+ * status still throws, same as every other method).
2277
+ *
2278
+ * `retryable` is `false` on every `"failed"` and on every `"timeout"` the server returns today.
2279
+ * It is not permission to relaunch, whatever its value: a `"timeout"` means the resolution window
2280
+ * ran out with no definitive answer and the bundle MIGHT STILL LAND. Treat every `"timeout"` as
2281
+ * unresolved and never rebuild under a new `clientLaunchId` because of one: that is a second
2282
+ * token. (This comment used to describe a `true` case meaning "the blockhash expired, relaunch".
2283
+ * No server path returns it.)
2284
+ *
2285
+ * `bundleId` itself is dead once this response arrives: it is consumed on the first `/submit`
2286
+ * call regardless of outcome and is never resubmitted. The launch's identity is the
2287
+ * `clientLaunchId` the build was sent under, and recovery goes through it: read
2288
+ * `getLaunchJob(clientLaunchId)`, then call `launchAtomic()` again with the SAME id when the job
2289
+ * says to (the steps are on `launchAtomic()`). See "Atomic launch with first buys" in
2290
+ * docs/headless-launch.md for the full model.
2176
2291
  */
2177
2292
  export type SubmitAtomicLaunchResult = {
2178
2293
  status: "landed";
@@ -2188,6 +2303,14 @@ export type SubmitAtomicLaunchResult = {
2188
2303
  bundleId: string;
2189
2304
  retryable: boolean;
2190
2305
  };
2306
+ /**
2307
+ * What `launchAtomic()` returns: `submitAtomicLaunch()`'s outcome plus the `clientLaunchId` the
2308
+ * launch was sent under, on all three of `landed`, `failed` and `timeout`. `submitAtomicLaunch()`
2309
+ * itself is given only a `bundleId` and cannot know the launch id.
2310
+ */
2311
+ export type LaunchAtomicResult = SubmitAtomicLaunchResult & {
2312
+ clientLaunchId: string;
2313
+ };
2191
2314
  /** Who pays for one leg of launchAtomic()'s one-call request. Mirrors AtomicLaunchPayer, but a "linked" payer also carries the privyWalletId signLinkedTransaction() needs to sign that leg -- mirrors TradeRequest's `from` field. */
2192
2315
  export type LaunchAtomicPayer = {
2193
2316
  type: "main";
@@ -2220,6 +2343,9 @@ export declare class CandleClient {
2220
2343
  readonly wallets: CandleWallets;
2221
2344
  /** The creator fees this account's launched tokens can pay, and the claim (FE-438). */
2222
2345
  readonly fees: CandleFees;
2346
+ /** Solana staking. The server supplies the pool wait and wallet eligibility notes. */
2347
+ readonly staking: CandleStaking;
2348
+ private stakingBuild;
2223
2349
  constructor(opts: CandleClientOptions);
2224
2350
  getQuotePairs(chain?: Chain): Promise<QuotePairsPayload>;
2225
2351
  getPresets(): Promise<PresetsPayload>;
@@ -2239,6 +2365,13 @@ export declare class CandleClient {
2239
2365
  getFeed(bucket: FeedBucket, chain?: Chain): Promise<FeedResult>;
2240
2366
  verify(chain: Chain, mint: string): Promise<VerifyResult>;
2241
2367
  getAgentProfile(idOrWallet: string): Promise<AgentProfile>;
2368
+ /**
2369
+ * The agent directory (`GET /api/v1/agent/directory`, no credential): every agent its owner
2370
+ * published, one page at a time, including one that has never traded. Pass the returned
2371
+ * `cursor` to read the next page; a page can be shorter than `limit` and still carry one. A
2372
+ * server that predates the directory answers 404 (`CandleApiError`).
2373
+ */
2374
+ listAgents(options?: ListAgentsOptions): Promise<AgentDirectoryPage>;
2242
2375
  /**
2243
2376
  * The calling account's tier snapshot: display/live tier, staked/held CNDL, qualification
2244
2377
  * thresholds, grace window state, resolved fee bps, and lifetime fee totals by chain/asset.
@@ -2259,12 +2392,27 @@ export declare class CandleClient {
2259
2392
  /**
2260
2393
  * Blocking launch with idempotent retries. Generates `clientLaunchId` when absent and
2261
2394
  * re-sends the SAME id on retryable failures; see the module doc for the exact policy.
2395
+ *
2396
+ * The id this call sent, yours or the generated one, is on the result
2397
+ * (`result.clientLaunchId`) and on every error thrown after the first request was sent
2398
+ * (`operationIds(error).clientLaunchId`), including the one thrown when the retries run out.
2399
+ * The built-in retries are safe only inside this one call. To retry after it throws, call
2400
+ * `launch()` again with that SAME id and the same body, or read `getLaunchJob(id)`. Never retry
2401
+ * without the id: a call with no id, or a new one, is a second launch. Pass your own id and
2402
+ * store it before the call when you can: an error can carry the id only if the process is
2403
+ * still running to catch it.
2262
2404
  */
2263
2405
  launch(req: LaunchRequest): Promise<LaunchResult>;
2264
2406
  /**
2265
2407
  * Fire-and-poll launch: sends `async: true`, returns the 202 body. Single attempt (poll
2266
2408
  * `waitForLaunch` instead of retrying the POST). Generates `clientLaunchId` like `launch()`
2267
2409
  * so the returned body always carries the id to poll.
2410
+ *
2411
+ * An error thrown after the request was sent carries that id too
2412
+ * (`operationIds(error).clientLaunchId`): the launch may have been accepted. Poll
2413
+ * `getLaunchJob(id)` / `waitForLaunch(id)`, or call again with the SAME id and body. Never
2414
+ * retry without the id: a call with no id, or a new one, is a second launch. Pass your own id
2415
+ * and store it before the call when you can.
2268
2416
  */
2269
2417
  launchAsync(req: LaunchRequest): Promise<AcceptedJob>;
2270
2418
  getLaunchJob(clientLaunchId: string): Promise<LaunchJob>;
@@ -2465,11 +2613,14 @@ export declare class CandleClient {
2465
2613
  * docs/headless-launch.md.
2466
2614
  */
2467
2615
  buildSelfLaunch(req: BuildSelfLaunchRequest): Promise<BuildSelfLaunchResult>;
2616
+ /** buildSelfLaunch()'s request; selfLaunch() passes its `op` so its exits can expose the id. */
2617
+ private postSelfLaunchBuild;
2468
2618
  /**
2469
2619
  * Self-signed launch confirm: verifies the agent's own broadcast on-chain, then records the
2470
2620
  * launch identically to the headless path. Signature is the transaction hash from the agent's
2471
2621
  * own broadcast. devBuySignature (Hood only) is the optional follow-up dev-buy transaction. See
2472
- * selfLaunch() below for the one-call version of this whole flow (Solana).
2622
+ * selfLaunch() below for the one-call version of this whole flow (Solana). The result carries
2623
+ * the `clientLaunchId` from the request (the server's body does not).
2473
2624
  */
2474
2625
  confirmSelfLaunch(req: ConfirmSelfLaunchRequest): Promise<ConfirmSelfLaunchResult>;
2475
2626
  /**
@@ -2521,6 +2672,30 @@ export declare class CandleClient {
2521
2672
  * `built | confirmed | failed`.
2522
2673
  */
2523
2674
  buildTrade(req: BuildTradeRequest): Promise<BuildTradeResult>;
2675
+ /** buildTrade()'s request; trade() passes its `op` so its exits can expose the id. */
2676
+ private postTradeBuild;
2677
+ /**
2678
+ * Reads one trade from the idempotency ledger by its `clientTradeId`, without sending
2679
+ * anything: the read to make after a `trade()` that threw or timed out, before deciding whether
2680
+ * to send again. Needs `swap:write` (the scope the trade itself needed) and answers during a
2681
+ * kill switch.
2682
+ *
2683
+ * - 404 `JOB_NOT_FOUND` (a thrown `CandleApiError`): the write never began. Call again with the
2684
+ * same id.
2685
+ * - `confirmed`: the trade landed; `signature` is on the job. A same-id `trade()` replays it.
2686
+ * - `failed` with `errorCode: "TRADE_REVERTED"`: it landed and reverted. A new trade needs a
2687
+ * new id.
2688
+ * - `failed`, other: not confirmed. A row with broadcast evidence may still be on chain; a
2689
+ * same-id `trade()` is the check, and answers `IDEMPOTENCY_CONFLICT` with
2690
+ * `stage: "unconfirmed"` for it.
2691
+ * - `built`: in flight or unresolved. A same-id `trade()` answers `IDEMPOTENCY_CONFLICT`; if it
2692
+ * carries `stage: "unconfirmed"` and `retryable: false`, check its `signature` on chain and
2693
+ * do not retry.
2694
+ *
2695
+ * For a linked payer, also check the wallet's recent transactions before sending again: see
2696
+ * `trade()`.
2697
+ */
2698
+ getTradeJob(clientTradeId: string): Promise<TradeJob>;
2524
2699
  /**
2525
2700
  * Confirm a LINKED payer's own broadcast trade: Candle verifies it landed on-chain, that it was
2526
2701
  * actually signed/sent by the declared linked wallet, that it moved this trade's own mint in
@@ -2620,8 +2795,30 @@ export declare class CandleClient {
2620
2795
  * opt-in, but only for a caller that has already confirmed the build carries neither an
2621
2796
  * `approval` nor a `permit2Approval` leg. Requires `evmRpcUrl`; throws a clear error
2622
2797
  * naming it when unset, before any RPC read or signing.
2798
+ *
2799
+ * ## The id, and retrying
2800
+ *
2801
+ * The `clientTradeId` this call sent, yours or the generated one, is on the result and on every
2802
+ * error thrown after the build request was sent (`operationIds(error).clientTradeId`): a
2803
+ * `CandleApiError` or `JsonRpcError` gains it, and a lost response or any other failure is a
2804
+ * `CandleOperationError` carrying it, with the original as `cause`. Pass your own id for
2805
+ * anything that moves funds and store it before the call: an error can carry the id only if
2806
+ * the process is still running to catch it. Never retry without the id: a call with no id, or a
2807
+ * new one, is a second, independent trade. This method does not retry on its own.
2808
+ *
2809
+ * - **Main payer** (`from: "main"`): the trade executes inside the build call, so a lost
2810
+ * response can sit on a trade that already moved funds. With the id, read `getTradeJob(id)`
2811
+ * or call `trade()` again with the same id and body. Both are safe: the same-id call is a
2812
+ * replay, not a second trade. `getTradeJob()`'s jsdoc says what each job state means.
2813
+ * - **Linked payer**: the id is necessary and NOT sufficient. The caller's side signs and
2814
+ * broadcasts here, so an error after the broadcast may sit on a transaction that landed, and
2815
+ * calling again under the same id can build and broadcast a second one. Read
2816
+ * `getTradeJob(id)` first; if it is not `confirmed`, check the wallet's recent transactions
2817
+ * before sending again.
2623
2818
  */
2624
2819
  trade(req: TradeRequest): Promise<ExecutedTradeResult>;
2820
+ /** trade()'s steps. Every error leaves through trade()'s runOperation(), which adds the id. */
2821
+ private tradeSteps;
2625
2822
  /**
2626
2823
  * One-call self-signed launch. Solana: `buildSelfLaunch` -> `signLinkedTransaction` ->
2627
2824
  * `broadcastSignedTransaction` -> `confirmSelfLaunch` (`built.transaction` is a base64 unsigned
@@ -2634,8 +2831,23 @@ export declare class CandleClient {
2634
2831
  * send a dev buy: a Hood self-launch's dev buy is a separate transaction the caller sends itself
2635
2832
  * and reports to `confirmSelfLaunch` as `devBuySignature`. The build response never includes a
2636
2833
  * dev-buy leg, and this method does not assemble one.
2834
+ *
2835
+ * ## The id, and retrying
2836
+ *
2837
+ * The `clientLaunchId` this call sent, yours or the generated one, is on the result and on every
2838
+ * error thrown after the build request was sent (`operationIds(error).clientLaunchId`). Pass
2839
+ * your own id and store it before the call when you can. Never retry without the id: a call
2840
+ * with no id, or a new one, is a second, independent launch.
2841
+ *
2842
+ * Here the id is necessary and NOT sufficient. This method signs and broadcasts on the caller's
2843
+ * side, so an error after the broadcast may sit on a launch transaction that landed, and
2844
+ * calling `selfLaunch()` again under the same id can build and broadcast a second one. Read
2845
+ * `getLaunchJob(id)` first; if it is not `confirmed`, check the wallet's recent transactions
2846
+ * before sending again.
2637
2847
  */
2638
2848
  selfLaunch(req: SelfLaunchRequest): Promise<ConfirmSelfLaunchResult>;
2849
+ /** selfLaunch()'s steps. Every error leaves through selfLaunch()'s runOperation(), which adds the id. */
2850
+ private selfLaunchSteps;
2639
2851
  /**
2640
2852
  * Builds an atomic launch bundle: a Solana launch transaction plus 1-4 first-buy transactions,
2641
2853
  * all sharing one recent blockhash so Jito lands them together or not at all. Returns the
@@ -2646,8 +2858,22 @@ export declare class CandleClient {
2646
2858
  * the full model: Pro/Max tier, `launch:write` + `swap:write` scopes, Solana only, the 1-4 buy
2647
2859
  * cap (Jito's 5-transaction bundle limit), and why every buy leg's own on-chain `minAmountOut` is
2648
2860
  * "0" inside the bundle (`expectedFill` on the returned legs is the real consent surface).
2861
+ *
2862
+ * The result carries the `clientLaunchId` the build was sent under (the server's body does
2863
+ * not), and so does every error thrown after the request was sent
2864
+ * (`operationIds(error).clientLaunchId`). Keep it: `bundleId` is single-use, and the launch's
2865
+ * identity for any later read or retry is the `clientLaunchId`. Retry a failed build with the
2866
+ * SAME id and body, or read `getLaunchJob(id)`; a call with no id, or a new one, is a second
2867
+ * launch. After a submit, follow the steps on `launchAtomic()`. Pass your own id and store it
2868
+ * before the call when you can.
2649
2869
  */
2650
2870
  buildAtomicLaunch(req: BuildAtomicLaunchRequest): Promise<BuildAtomicLaunchResult>;
2871
+ /**
2872
+ * The atomic build request itself. Sets `clientLaunchId` on the result from the request, since
2873
+ * the server's body omits it. Shared by buildAtomicLaunch() and launchAtomic(), each of which
2874
+ * runs it inside its OWN runOperation(), so an error is wrapped once, by the outermost method.
2875
+ */
2876
+ private postAtomicBuild;
2651
2877
  /**
2652
2878
  * Submits an already-built bundle's client-signer legs (EXACTLY the ones
2653
2879
  * `BuildAtomicLaunchResult.legs` named `signer: "client"`, in leg order -- omit every "server"
@@ -2667,7 +2893,15 @@ export declare class CandleClient {
2667
2893
  * roughly 150-160s in the worst case (Jito's own ~60s poll budget plus a further ~90s resolution
2668
2894
  * phase), since Candle checks the launch signature's own on-chain status before answering. Set a
2669
2895
  * client-side timeout no shorter than ~160s (or none) for this call, or you risk abandoning a
2670
- * request that was about to return a normal, if late, response.
2896
+ * request that was about to return a normal, if late, response. A same-id
2897
+ * `buildAtomicLaunch()`/`launchAtomic()` after a send can itself take up to about 95 seconds to
2898
+ * answer, because the server resolves the first attempt against the chain before doing anything
2899
+ * new: allow for that too.
2900
+ *
2901
+ * This method is given only a `bundleId`, so its result cannot carry the launch's
2902
+ * `clientLaunchId`. Keep the one `buildAtomicLaunch()` returned: after a `"failed"` or
2903
+ * `"timeout"`, recovery goes through it (the steps are on `launchAtomic()`), never through
2904
+ * this `bundleId` and never through a new id.
2671
2905
  */
2672
2906
  submitAtomicLaunch(req: SubmitAtomicLaunchRequest): Promise<SubmitAtomicLaunchResult>;
2673
2907
  /**
@@ -2681,11 +2915,44 @@ export declare class CandleClient {
2681
2915
  * bundle with no linked payer at all (every leg "main") skips the signing round entirely and
2682
2916
  * goes straight from build to submit.
2683
2917
  *
2684
- * Returns `submitAtomicLaunch()`'s own result untouched -- see that method's jsdoc for why
2685
- * `"failed"`/`"timeout"` are returned here rather than thrown, and for the recommended
2686
- * client-side timeout.
2687
- */
2688
- launchAtomic(req: LaunchAtomicRequest): Promise<SubmitAtomicLaunchResult>;
2918
+ * Returns `submitAtomicLaunch()`'s outcome plus the `clientLaunchId` the launch was sent under
2919
+ * (`LaunchAtomicResult`), on `"landed"`, `"failed"` and `"timeout"` alike -- see that method's
2920
+ * jsdoc for why `"failed"`/`"timeout"` are returned here rather than thrown, and for the
2921
+ * recommended client-side timeout. A thrown error carries `clientLaunchId` too, and `bundleId`
2922
+ * once the build has answered (`operationIds(error)`). Pass your own id and store it before the
2923
+ * call when you can: an error can carry the id only if the process is still running to catch it.
2924
+ *
2925
+ * ## After a `timeout`, a `failed`, or an error that carries `clientLaunchId`
2926
+ *
2927
+ * `bundleId` is dead once `/submit` has been called and is never resubmitted; it is for log
2928
+ * correlation only. The launch's identity is `clientLaunchId`:
2929
+ *
2930
+ * 1. Read `getLaunchJob(clientLaunchId)`. It needs `launch:read` on the key; a key whose scopes
2931
+ * were named by hand holds it only if it was named. A scope refusal is not "not found".
2932
+ * 2. `confirmed`: the bundle landed. The mint is on the job. Stop.
2933
+ * 3. 404 `JOB_NOT_FOUND`: the build never began. Call `launchAtomic()` again with the same id.
2934
+ * 4. `failed`: the bundle did not land. Call `launchAtomic()` again with the SAME id; the server
2935
+ * starts a clean attempt under it.
2936
+ * 5. Any other status: the bundle may still land. Wait, then read the job again or call
2937
+ * `launchAtomic()` again with the SAME id and the same body. The server resolves the first
2938
+ * attempt before doing anything new. It answers 409 `IDEMPOTENCY_CONFLICT` while the first
2939
+ * attempt is unresolved or has just been found landed, so on that 409 read the job again. It
2940
+ * builds a fresh bundle only when the first is proven reverted. This same-id call can take
2941
+ * about 95 seconds to answer, because the server waits on the chain.
2942
+ * 6. Never send a new id while the job is not `failed`: that is a second token. This includes
2943
+ * the 409 whose message says "use a new clientLaunchId to launch again": read the job first,
2944
+ * because that message is also what a caller sees for a launch it does not yet know landed.
2945
+ * 7. One state has no terminal answer today. The same-id call keeps answering 409 "This launch
2946
+ * was sent; its original attempt must be resolved" and the job is neither `confirmed` nor
2947
+ * `failed`, still, a few minutes after the submit (a blockhash lives about 90 seconds and the
2948
+ * rebuild itself can take about 95). Stop: do not send a new id on a timer, and report the
2949
+ * `clientLaunchId` and `bundleId` to whoever operates the key.
2950
+ * 8. Treat every `timeout` as unresolved. `retryable` is `false` on every one the server returns
2951
+ * today, and it is never permission to relaunch under a new id.
2952
+ */
2953
+ launchAtomic(req: LaunchAtomicRequest): Promise<LaunchAtomicResult>;
2954
+ /** launchAtomic()'s steps. Every error leaves through launchAtomic()'s runOperation(), which adds the ids. */
2955
+ private launchAtomicSteps;
2689
2956
  /**
2690
2957
  * The `EvmRpc` seam packages/sdk/src/evm-tx.ts's helpers are built against, built from this
2691
2958
  * client's own `jsonRpcCall`/`jsonRpcCallRaw` closed over `evmRpcUrl`. Callers must have already
@@ -2769,6 +3036,17 @@ export declare class CandleClient {
2769
3036
  private signLinkedTypedData;
2770
3037
  private requireKey;
2771
3038
  private headers;
3039
+ /**
3040
+ * Runs a one-call write method's steps so that every exit exposes the idempotency id it sent
3041
+ * (see the module doc, "The id on every outcome"). The steps pass `op` to the request that
3042
+ * carries the id. Until that request is handed to fetch, an error leaves unchanged: nothing
3043
+ * reached the server, so there is nothing to replay. After it, `withOperationIds()` puts the
3044
+ * ids on a `CandleApiError`/`JsonRpcError` and wraps anything else in a `CandleOperationError`.
3045
+ *
3046
+ * Called once per public method, never nested: an inner step that is itself a one-call method
3047
+ * (launchAtomic()'s build) runs its plain request, so the error is wrapped once, here.
3048
+ */
3049
+ private runOperation;
2772
3050
  private requestJson;
2773
3051
  private parseResponse;
2774
3052
  /**
@@ -2799,7 +3077,7 @@ export declare function __setEvmReceiptWaitForTest(opts: {
2799
3077
  pollMs?: number;
2800
3078
  } | null): void;
2801
3079
  /** This build's own version. Kept in lockstep with package.json by the release-bump CI guard. */
2802
- export declare const SDK_VERSION = "0.4.10";
3080
+ export declare const SDK_VERSION = "0.5.0";
2803
3081
  /** Test seam: the once-per-process latch would otherwise weld the suite's first case to the rest. */
2804
3082
  export declare function __resetSdkUpdateNoticeForTest(): void;
2805
3083
  //# sourceMappingURL=client.d.ts.map