@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/dist/client.d.ts CHANGED
@@ -26,6 +26,9 @@
26
26
  * validation error). Backoff is 250ms * 2^n, jittered to 50-100% of that, capped at 8s,
27
27
  * bounded by `maxRetries` (default 3 retries after the initial attempt).
28
28
  */
29
+ import { type HyperliquidNetwork, type HyperliquidTypedData } from "./hyperliquid";
30
+ import type { HyperliquidPnlSection } from "./hyperliquid-pnl";
31
+ import type { AgentPlansResult, PlanPrice, PlanTable } from "./plans";
29
32
  import type { SecretStore } from "./secret-store";
30
33
  import { type WalletChain } from "./wallet-import";
31
34
  export type Chain = "solana" | "hood";
@@ -83,6 +86,16 @@ export interface CandleClientOptions {
83
86
  * is unset, before any signing.
84
87
  */
85
88
  evmRpcUrl?: string;
89
+ /**
90
+ * Candle's Hyperliquid builder address, pinned by the caller. Every perps build is checked
91
+ * against it before signing: an order must name exactly this builder (or none, on a Max order),
92
+ * and setup must approve exactly it. Unset, the client uses `CANDLE_HYPERLIQUID_BUILDER_ADDRESS`
93
+ * when this release carries one, and otherwise trusts the builder `GET /agent/perps/config`
94
+ * reports the first time and holds every later build to that same address.
95
+ */
96
+ hyperliquidBuilder?: string;
97
+ /** The Hyperliquid network this client trades on. Default mainnet; a build for another is refused. */
98
+ hyperliquidNetwork?: HyperliquidNetwork;
86
99
  }
87
100
  /** The bonding-curve terms of one (chain, quote asset, tier) cell. */
88
101
  export interface CurveTerms {
@@ -398,21 +411,30 @@ export interface AgentProfile {
398
411
  */
399
412
  export interface AgentTierInfo {
400
413
  success: true;
401
- /** Display tier: max > pro > believer > free. */
414
+ /**
415
+ * Display tier: max > pro > believer > free. From the three-plan launch the server sends only
416
+ * `free`, `pro` or `max`; `believer` stays in this type for one release after it, then goes.
417
+ */
402
418
  tier: "free" | "believer" | "pro" | "max";
403
419
  /** Live-evaluated tier, independent of the Believer key-issuance label. */
404
420
  liveTier: "free" | "pro" | "max";
405
421
  stakedCndl: number;
406
422
  heldCndl: number;
423
+ /** `graceMs` is 0 from the three-plan launch: Pro through CNDL then has no grace window. */
407
424
  thresholds: {
408
425
  minStakedCndl: number;
409
426
  minHeldCndl: number;
410
427
  graceMs: number;
411
428
  };
412
- /** `startedAt` is null unless `active` (see the endpoint's own doc for why). */
429
+ /**
430
+ * `startedAt` is null unless `active` (see the endpoint's own doc for why). `endsAt` is the
431
+ * server's deadline for an open window; absent from an older server. Never active from the
432
+ * three-plan launch.
433
+ */
413
434
  grace: {
414
435
  active: boolean;
415
436
  startedAt: number | null;
437
+ endsAt?: number | null;
416
438
  };
417
439
  maxTierExpiresAt: number | null;
418
440
  /**
@@ -424,8 +446,12 @@ export interface AgentTierInfo {
424
446
  maxExpired: boolean;
425
447
  /** When the lapsed grant ended (ms). Present only when `maxExpired`. */
426
448
  maxExpiredAt?: number;
427
- /** Which kind of grant lapsed. Present only when `maxExpired`. */
428
- maxExpiredSource?: "subscription" | "trial" | "team";
449
+ /**
450
+ * Which kind of grant lapsed. Present only when `maxExpired`. `"promo"` is the Max that came free
451
+ * with a first Pro purchase; while the account still pays for Pro, that lapse is not reported.
452
+ * Treat an unknown value as a generic Max expiry.
453
+ */
454
+ maxExpiredSource?: "subscription" | "trial" | "team" | "promo";
429
455
  /**
430
456
  * The server's own sentence about the lapse, dated, with the renewal link. Relay it verbatim:
431
457
  * it is the same copy the CLI doctor row, the MCP notice, and the tier refusals use, so every
@@ -442,6 +468,21 @@ export interface AgentTierInfo {
442
468
  feeRawSum: string;
443
469
  count: number;
444
470
  }>;
471
+ /** The live tier's cap floors. Absent from an older server. */
472
+ tierCaps?: {
473
+ rateLimitPerMin: number;
474
+ dailyLaunchCap: number;
475
+ uploadsPerMin: number;
476
+ linkedWallets: number;
477
+ };
478
+ /** When the tier was evaluated (ms), so a caller can say how fresh it is. Absent from an older server. */
479
+ checkedAt?: number;
480
+ /** Max's price. Kept beside `planTable` for compatibility; read `planTable` for every plan. */
481
+ maxPricing?: PlanPrice;
482
+ /** Pro's price, null while Pro is not sold. Absent from a server before the plan table. */
483
+ proPricing?: PlanPrice | null;
484
+ /** The plan table in force, the same one `getPlans()` returns. Absent from an older server. */
485
+ planTable?: PlanTable;
445
486
  }
446
487
  /**
447
488
  * One per-transaction spend cap, mirroring `SpendLimit` in `apps/api/src/lib/agent-policy.ts`
@@ -537,13 +578,70 @@ export interface ProfileOpenPosition {
537
578
  unrealizedUsd?: number;
538
579
  /** The chain this position was traded on. Optional: a server that predates it omits it. */
539
580
  chain?: Chain;
581
+ /**
582
+ * The wallet holding it: positions live in wallets, so one token held in two wallets is two
583
+ * positions. `unknown:solana` or `unknown:hood` names the pool for fills no record places in a
584
+ * wallet, which is not an address. Optional: a server that predates 2026-10-02 omits it.
585
+ */
586
+ wallet?: string;
587
+ /**
588
+ * The key this position belongs to, by prefix: the wallet's bound key, else the key whose buy
589
+ * opened it; null for Manual (web-app trades). Optional: a server that predates 2026-10-02 omits it.
590
+ */
591
+ agent?: string | null;
592
+ /** When the round behind this position opened, epoch ms. Optional, as `wallet`. */
593
+ openedTs?: number;
594
+ /** Why there is no mark. Present exactly when `markPriceUsd` is absent, on a server that sends it. */
595
+ unpricedReason?: "no-market-row" | "unusable-price";
596
+ /**
597
+ * Worth under one cent at its mark. Still listed and still counted; `openPositionsExDust` leaves it
598
+ * out. An unpriced position is never dust. Optional: a server that predates 2026-10-02 omits it.
599
+ */
600
+ dust?: true;
601
+ }
602
+ /**
603
+ * Closed positions as one equation (P&L spec PNL-ED-8): `madeUsd + lostUsd + partialSellsUsd`
604
+ * equals the scope's `realizedNetUsd`. A position is closed when its wallet's quantity returns to
605
+ * zero through a sale.
606
+ */
607
+ export interface ProfileClosedSummary {
608
+ /** Closed positions, those with unknown cost included. */
609
+ closed: number;
610
+ /** Sum of the closed positions that made money, USD. */
611
+ madeUsd: number;
612
+ /** Sum of the closed positions that lost money, USD: zero or negative. */
613
+ lostUsd: number;
614
+ /**
615
+ * The rest of the realized net: partial sells of positions still open, and fees not in a closed
616
+ * position (a buy fee on an open position, a sell with nothing open).
617
+ */
618
+ partialSellsUsd: number;
619
+ /** Closed positions won and lost, leaving out those with unknown cost. */
620
+ wins: number;
621
+ losses: number;
622
+ /** Closed positions with unknown cost: listed in `closed`, left out of `wins` and `losses`. */
623
+ costUnknown: number;
624
+ }
625
+ /**
626
+ * Fields every scope of `ProfilePnlResult` gained on 2026-10-02 (the total, each `byChain` entry
627
+ * and each `byWallet` row). Each is optional: a server that predates it omits it.
628
+ */
629
+ export interface ProfilePnlEngineFields {
630
+ /** Realized net plus unrealized: the figure the console labels P&L, to the cent. */
631
+ totalUsd?: number;
632
+ /** Open positions that are not dust. */
633
+ openPositionsExDust?: number;
634
+ /** Closed positions this scope's sales closed. */
635
+ closedRounds?: number;
636
+ /** Money made, minus money lost, plus partial sells, equals `realizedNetUsd`. */
637
+ closed?: ProfileClosedSummary;
540
638
  }
541
639
  /**
542
640
  * One chain's share of a profile's P&L (`ProfilePnlResult.pnl.byChain`): the total's figures over
543
641
  * that chain's fills alone. `openPositions` is a COUNT here; the positions themselves are in
544
642
  * `pnl.openPositions`, each carrying its `chain`.
545
643
  */
546
- export interface ProfileChainPnl {
644
+ export interface ProfileChainPnl extends ProfilePnlEngineFields {
547
645
  realizedGrossUsd: number;
548
646
  feesUsd: number;
549
647
  realizedNetUsd: number;
@@ -564,7 +662,7 @@ export interface ProfileChainPnl {
564
662
  measured: number;
565
663
  unmeasured: number;
566
664
  };
567
- /** Confirmed trades on this chain in the window. */
665
+ /** This key's ledger fills on this chain in the window. */
568
666
  tradesConsidered: number;
569
667
  }
570
668
  /**
@@ -575,11 +673,27 @@ export interface ProfileChainPnl {
575
673
  * that could be marked. A position with no price is counted in `unmarkedPositions` rather than
576
674
  * valued at zero, and `oldestMarkAt` says how old the marks are, so a stale figure is visible.
577
675
  * Deposits and withdrawals are excluded entirely: funding a wallet is not trading profit.
676
+ *
677
+ * Since 2026-10-02 (P&L spec R2) the figures are this key's share of the account's one P&L read,
678
+ * the read the console, the dashboard, `/books` and `/keys/pnl` share, so they agree with the
679
+ * console to the cent for the same moment:
680
+ * - realized and fees are on the fills this key placed; an open position belongs to the wallet's
681
+ * bound key, else to the key whose buy opened it; a closed position to the key whose sale closed it;
682
+ * - each wallet is its own average-cost pool, and the total is the sum of `byWallet`
683
+ * (it used to pool every wallet of the key);
684
+ * - a recorded move between two of the account's wallets carries its cost and realizes nothing;
685
+ * tokens that arrive with no cost anyone can state realize nothing when sold;
686
+ * - `openPositions` counts one per wallet and token, dust included;
687
+ * - `tradesConsidered` counts this key's ledger fills, and `lookback` / `truncated` are the
688
+ * account's activity bound, not 500 of this key's trades.
689
+ * Every account's realized figure can move on the day a server ships this.
578
690
  */
579
691
  export interface ProfilePnlResult {
692
+ /** Optional while Hyperliquid is enabled; separate from spot totals. */
693
+ hyperliquid?: HyperliquidPnlSection;
580
694
  success: true;
581
695
  keyPrefix: string;
582
- pnl: {
696
+ pnl: ProfilePnlEngineFields & {
583
697
  realizedGrossUsd: number;
584
698
  /** Candle fees over the counted fills. Reported separately, netted only into realizedNetUsd. */
585
699
  feesUsd: number;
@@ -598,32 +712,51 @@ export interface ProfilePnlResult {
598
712
  /** Fills counted, and fills that had no trusted USD price and so were left out entirely. */
599
713
  counted: number;
600
714
  unvalued: number;
715
+ /** Fills held out because their token has a fill of unknown size. Part of `unvalued`. Optional. */
716
+ unresolved?: number;
717
+ /** The tokens those fills belong to: their P&L is unknown, not zero. Optional. */
718
+ unresolvedMints?: string[];
719
+ /** Fees and measured slippage, reported and never netted a second time. Optional. */
720
+ friction?: {
721
+ feesUsd: number;
722
+ slippageUsd: number;
723
+ slippageBpsAvg?: number;
724
+ measured: number;
725
+ unmeasured: number;
726
+ };
727
+ /** This key's ledger fills in the window. */
601
728
  tradesConsidered: number;
729
+ /** The account's activity bound, shared by every private P&L read (it was 500 of this key's trades). */
602
730
  lookback: number;
603
731
  /** True when the lookback window was full, so this is not a lifetime figure. */
604
732
  truncated: boolean;
605
733
  /**
606
- * The same fills divided by the wallet that paid for each trade, ordered by
607
- * `tradesConsidered` then address. Optional: a server that predates it omits it.
734
+ * The same figures divided by wallet, ordered by `tradesConsidered` then address. Optional: a
735
+ * server that predates it omits it.
608
736
  *
609
- * Each row is an independent average-cost pool over its own fills, so the rows need not sum to
610
- * the total above, which pools all fills and stays correct. A token bought in one wallet and
611
- * sold from another leaves the buyer holding it and the seller with a sale that realizes
612
- * nothing; and even with no transfer, A buying 100 X for $100, B buying 100 X for $200 and A
613
- * selling 100 X for $300 realizes $150 in total but $200 summed over the wallets.
737
+ * Each wallet is its own average-cost pool, and the total above is the sum of its wallets: A
738
+ * buying 100 X for $100, B buying 100 X for $200 and A selling 100 X for $300 realizes $200.
739
+ * (Before 2026-10-02 the total pooled every wallet and realized $150 here.) A token moved
740
+ * between two of the account's wallets carries its cost once the move is recorded; until then
741
+ * the buyer still holds it and the seller's sale realizes nothing.
614
742
  */
615
743
  byWallet?: ProfileWalletPnl[];
616
744
  /**
617
- * The same figures split by the chain each trade was on, both chains always present. Each is
618
- * its own average-cost pool, so the two need not sum exactly to the total above, for the
619
- * reason `byWallet` rows need not. Optional: a server that predates it omits it.
745
+ * The same figures split by chain, both chains always present. A token lives on one chain, so
746
+ * the two sum to the total above. Optional: a server that predates it omits it.
620
747
  */
621
748
  byChain?: Record<Chain, ProfileChainPnl>;
622
749
  };
623
750
  }
624
- /** One row of `ProfilePnlResult.pnl.byWallet`: one paying wallet's share of a profile's P&L. */
625
- export interface ProfileWalletPnl {
626
- /** The paying wallet's address as stored: base58, or EIP-55 on Hood. */
751
+ /**
752
+ * One row of `ProfilePnlResult.pnl.byWallet`: one wallet's share of a profile's P&L. A wallet two
753
+ * keys trade carries this key's share only.
754
+ */
755
+ export interface ProfileWalletPnl extends ProfilePnlEngineFields {
756
+ /**
757
+ * The wallet's address as stored: base58, or EIP-55 on Hood. `unknown:solana` or `unknown:hood`
758
+ * is the pool for fills no record places in a wallet: a row, not an address.
759
+ */
627
760
  wallet: string;
628
761
  payerType: "main" | "linked";
629
762
  /**
@@ -657,7 +790,7 @@ export interface ProfileWalletPnl {
657
790
  measured: number;
658
791
  unmeasured: number;
659
792
  };
660
- /** Confirmed trades in the window this wallet paid for. */
793
+ /** This key's ledger fills in the window from this wallet. */
661
794
  tradesConsidered: number;
662
795
  }
663
796
  /**
@@ -895,6 +1028,20 @@ export interface TradeFee {
895
1028
  /** Solana "built" artifacts: one unsigned transaction, the fee (if any) already embedded inside it. */
896
1029
  export interface SolanaTradeArtifacts {
897
1030
  venue: "curve" | "jupiter";
1031
+ /**
1032
+ * Which quoter built the transaction. On the `jupiter` venue Candle also asks DFlow for a quote and
1033
+ * uses it only when its output is strictly larger; otherwise this is `jupiter`. `curve` on the curve venue.
1034
+ */
1035
+ quoteSource?: "curve" | "jupiter" | "dflow";
1036
+ /**
1037
+ * The Jupiter/DFlow race on a `jupiter` venue build: Jupiter's quoted output, DFlow's when it gave an
1038
+ * accepted quote, and why DFlow did not build the transaction when it did not. Absent on the curve venue.
1039
+ */
1040
+ race?: {
1041
+ jupiterOutRaw: string;
1042
+ dflowOutRaw?: string;
1043
+ dflowRefusal?: string;
1044
+ };
898
1045
  transactionBase64: string;
899
1046
  quoteAsset: string;
900
1047
  quoteMint: string;
@@ -1051,6 +1198,16 @@ export interface ExecutedTradeResult {
1051
1198
  * server had already read. Present on the executed response since 2026-09-04.
1052
1199
  */
1053
1200
  route?: TradeRoute;
1201
+ /**
1202
+ * Solana `jupiter` venue only: which quoter built the transaction that executed (`jupiter` or `dflow`),
1203
+ * and the Jupiter/DFlow race behind it. Absent on the curve venue, on Hood, and on an idempotent replay.
1204
+ */
1205
+ quoteSource?: "jupiter" | "dflow";
1206
+ race?: {
1207
+ jupiterOutRaw: string;
1208
+ dflowOutRaw?: string;
1209
+ dflowRefusal?: string;
1210
+ };
1054
1211
  }
1055
1212
  /** POST /api/v1/trade/agent/build response: "built" for a linked payer, "executed" for a main payer (or an idempotent replay of an already-confirmed trade under the same clientTradeId). */
1056
1213
  export type BuildTradeResult = BuildTradeBuiltResult | ExecutedTradeResult;
@@ -1161,6 +1318,249 @@ export interface SignLinkedTransactionResult {
1161
1318
  signedTransaction: string;
1162
1319
  encoding: string;
1163
1320
  }
1321
+ /** The EVM TEE wallet a perps action signs from: its row id and its Privy wallet id. */
1322
+ export interface PerpsWalletRef {
1323
+ /** The linked wallet's row id (the relay's :id, and the secretStore key). */
1324
+ walletId: string;
1325
+ /** The same wallet's Privy wallet id, the authorization signature's URL target. */
1326
+ privyWalletId: string;
1327
+ /** Sign and submit (default), or stop after the build and its check and return the build. */
1328
+ submit?: boolean;
1329
+ }
1330
+ export type PerpsSide = "long" | "short";
1331
+ export interface PerpsOpenParams extends PerpsWalletRef {
1332
+ coin: string;
1333
+ side: PerpsSide;
1334
+ /** Size in the coin, a decimal string. */
1335
+ size: string;
1336
+ /** `market` (IOC at the mid moved by the slippage) or `limit`. Default: limit when `price` is set. */
1337
+ type?: "market" | "limit";
1338
+ price?: string;
1339
+ tif?: "Gtc" | "Alo" | "Ioc";
1340
+ slippageBps?: number;
1341
+ /** Optional reduce-only take-profit trigger price. */
1342
+ takeProfit?: string;
1343
+ /** Optional reduce-only stop-loss trigger price. */
1344
+ stopLoss?: string;
1345
+ }
1346
+ export interface PerpsCloseParams extends PerpsWalletRef {
1347
+ coin: string;
1348
+ /** Part of the position to close; the whole position when omitted. */
1349
+ size?: string;
1350
+ slippageBps?: number;
1351
+ }
1352
+ export interface PerpsCancelParams extends PerpsWalletRef {
1353
+ /** The cloid of an order Candle built (an open, or one of its take-profit / stop-loss legs). */
1354
+ cloid: string;
1355
+ }
1356
+ export interface PerpsModifyParams extends PerpsWalletRef {
1357
+ cloid: string;
1358
+ price?: string;
1359
+ size?: string;
1360
+ slippageBps?: number;
1361
+ }
1362
+ export interface PerpsLeverageParams extends PerpsWalletRef {
1363
+ coin: string;
1364
+ leverage: number;
1365
+ mode?: "cross" | "isolated";
1366
+ }
1367
+ export interface PerpsMarginParams extends PerpsWalletRef {
1368
+ coin: string;
1369
+ /** USD, up to 6 decimals; negative removes isolated margin. */
1370
+ amount: string;
1371
+ }
1372
+ /** What a perps build route returns: the plaintext action, its nonce, and the stamped typed data. */
1373
+ export interface PerpsBuild {
1374
+ success: true;
1375
+ perpOrderId: string;
1376
+ kind: "open" | "close" | "modify" | "cancel" | "leverage" | "margin" | "setup";
1377
+ network: HyperliquidNetwork;
1378
+ walletId: string;
1379
+ address: string;
1380
+ nonce: number;
1381
+ action: Record<string, unknown>;
1382
+ typedData: HyperliquidTypedData;
1383
+ claimHash: string;
1384
+ cloid?: string;
1385
+ childCloids?: string[];
1386
+ targetCloid?: string;
1387
+ notionalUsdMicros: number | null;
1388
+ reservedUsdMicros: number;
1389
+ windowKey: string | null;
1390
+ builder: {
1391
+ address: string;
1392
+ feeTenthsBps: number;
1393
+ } | null;
1394
+ exchangeUrl: string;
1395
+ preview: Record<string, unknown>;
1396
+ }
1397
+ /**
1398
+ * The outcome of one perps action. `signature` is present once the relay signed; it stays valid
1399
+ * for resubmission until the nonce leaves Hyperliquid's two-day window, so a failed submit keeps
1400
+ * it. `exchange` is Hyperliquid's own answer, unchanged (`status: "ok"` or `"err"`, and per-order
1401
+ * statuses for an order).
1402
+ */
1403
+ export interface PerpsActionResult {
1404
+ build: PerpsBuild;
1405
+ signature: string | null;
1406
+ submitted: boolean;
1407
+ exchange: unknown | null;
1408
+ submitError?: string;
1409
+ }
1410
+ export interface PerpsAccountStatus {
1411
+ walletId: string;
1412
+ address: string;
1413
+ network: HyperliquidNetwork;
1414
+ mode: string;
1415
+ standardMode: boolean;
1416
+ accountValue: string;
1417
+ withdrawable: string;
1418
+ builder: string;
1419
+ approvedFeeTenthsBps: number;
1420
+ }
1421
+ /** `ready: true` when the builder approval is already on Hyperliquid; otherwise the setup action's outcome. */
1422
+ export type PerpsSetupResult = PerpsAccountStatus & {
1423
+ ready: boolean;
1424
+ action?: PerpsActionResult;
1425
+ };
1426
+ export interface PerpsConfig {
1427
+ success: true;
1428
+ network: HyperliquidNetwork;
1429
+ exchangeUrl: string;
1430
+ builder: string | null;
1431
+ builderFeeTenthsBps: number;
1432
+ maxBuilderFeeRate: string;
1433
+ allowedActionTypes: string[];
1434
+ limits: Record<string, unknown>;
1435
+ }
1436
+ export interface PerpsPositions {
1437
+ success: true;
1438
+ walletId: string;
1439
+ address: string;
1440
+ network: HyperliquidNetwork;
1441
+ mode: string;
1442
+ standardMode: boolean;
1443
+ account: Record<string, string>;
1444
+ withdrawable: string;
1445
+ positions: Record<string, unknown>[];
1446
+ }
1447
+ export interface PerpsOrderRecord {
1448
+ perpOrderId: string;
1449
+ kind: PerpsBuild["kind"];
1450
+ actionType: string;
1451
+ coin: string | null;
1452
+ nonce: number;
1453
+ cloid: string | null;
1454
+ childCloids: string[];
1455
+ targetCloid: string | null;
1456
+ status: string;
1457
+ venueStatus: string | null;
1458
+ filledSz: string | null;
1459
+ notionalUsdMicros: number | null;
1460
+ reservedUsdMicros: number;
1461
+ releasedUsdMicros: number;
1462
+ windowKey: string | null;
1463
+ builtAt: number;
1464
+ settledAt: number | null;
1465
+ }
1466
+ export interface PerpsOrders {
1467
+ success: true;
1468
+ walletId: string;
1469
+ address: string;
1470
+ network: HyperliquidNetwork;
1471
+ /** Hyperliquid's open orders for the wallet's address. */
1472
+ open: Record<string, unknown>[];
1473
+ /** Candle's record of every action it built for this wallet, newest first. */
1474
+ recorded: PerpsOrderRecord[];
1475
+ settled: {
1476
+ perpOrderId: string;
1477
+ status: string;
1478
+ releasedUsdMicros: number;
1479
+ }[];
1480
+ }
1481
+ /**
1482
+ * Perps C (BE-647, HL-ED-8): `perpsDeposit()`. Relay moves funds from the key's Hood or Solana TEE
1483
+ * wallet onto Hyperliquid perps USDC at the key's EVM TEE wallet's own address. The asset decides
1484
+ * the paying chain: SOL or USDC from the Solana TEE wallet, ETH or USDG from the Hood one. Needs
1485
+ * `swap:write` and a raw cap on the asset. There is no withdrawal yet.
1486
+ */
1487
+ export interface PerpsDepositParams {
1488
+ /** Idempotency id, 1 to 128 of `A-Za-z0-9._:-`. Rebuilding under the same id answers its job. */
1489
+ clientDepositId: string;
1490
+ asset: "SOL" | "USDC" | "ETH" | "USDG";
1491
+ /** Raw base units of `asset`, as a decimal string. */
1492
+ amountRaw: string;
1493
+ /** The paying TEE wallet's row id (the relay's :id, and the secretStore key). */
1494
+ walletId: string;
1495
+ /** The paying wallet's Privy wallet id. */
1496
+ privyWalletId: string;
1497
+ /** The Hyperliquid account: the EVM TEE wallet's address. The build is refused if it names another. */
1498
+ account: string;
1499
+ /** From Solana only: the EVM TEE wallet whose Hyperliquid account receives. Omit from Hood. */
1500
+ perpsWalletId?: string;
1501
+ /** Relay slippage, 1 to 1000 bps (default 100). */
1502
+ maxSlippageBps?: number;
1503
+ /** Sign and submit (default), or stop after the build and its check. */
1504
+ submit?: boolean;
1505
+ }
1506
+ /** What `POST /agent/perps/deposit` builds. A Hood build also carries the first sequenced leg. */
1507
+ export interface PerpsDepositBuild {
1508
+ success: true;
1509
+ status: "built";
1510
+ clientDepositId: string;
1511
+ depositId: string;
1512
+ chain: "solana" | "hood";
1513
+ venue: "relay";
1514
+ network: HyperliquidNetwork;
1515
+ asset: PerpsDepositParams["asset"];
1516
+ amountRaw: string;
1517
+ walletId: string;
1518
+ walletAddress: string;
1519
+ destination: {
1520
+ walletId: string;
1521
+ address: string;
1522
+ chainId: number;
1523
+ currency: string;
1524
+ };
1525
+ firstDeposit: boolean;
1526
+ expectedOutRaw: string;
1527
+ minimumOutRaw: string;
1528
+ outDecimals: number;
1529
+ floorUsdcMicros: string;
1530
+ minimumCreditUsdcMicros: string;
1531
+ fee: {
1532
+ bps: number;
1533
+ feeRaw: string;
1534
+ };
1535
+ statusChecks: string[];
1536
+ requestId: string | null;
1537
+ expiresAt: number;
1538
+ /** Solana: the one unsigned deposit. */
1539
+ transactionsBase64?: string[];
1540
+ /** Hood: the sequenced leg protocol's first body. */
1541
+ mode?: "sequenced";
1542
+ operationId?: string;
1543
+ legKind?: string;
1544
+ plannedLegCount?: number;
1545
+ nextLeg?: {
1546
+ chainId: number;
1547
+ nonce: number;
1548
+ gas: string;
1549
+ maxFeePerGas: string;
1550
+ maxPriorityFeePerGas: string;
1551
+ to: string;
1552
+ data: string;
1553
+ value: string;
1554
+ };
1555
+ }
1556
+ export interface PerpsDepositResult {
1557
+ build: PerpsDepositBuild;
1558
+ submitted: boolean;
1559
+ /** `/perps/deposit/submit`'s final answer: `status: "submitted"` and the chain hashes. */
1560
+ result: Record<string, unknown> | null;
1561
+ }
1562
+ /** Why a deposit build must not be signed, or null. */
1563
+ export declare function perpsDepositProblem(build: PerpsDepositBuild, params: PerpsDepositParams): string | null;
1164
1564
  /**
1165
1565
  * The base assets `swap()` converts between. Inlined rather than imported from `@candle/shared`'s
1166
1566
  * `BaseAssetKey`, for the same reason `packages/mcp` inlines its curve constants: this SDK is
@@ -1560,6 +1960,8 @@ export declare class CandleClient {
1560
1960
  private readonly secretStore?;
1561
1961
  private readonly solanaRpcUrl?;
1562
1962
  private readonly evmRpcUrl?;
1963
+ private readonly hyperliquidNetwork;
1964
+ private hyperliquidBuilder?;
1563
1965
  /** Reads scoped to what this key may spend: a one-shot swap's receipt, and spendable balances. */
1564
1966
  readonly wallets: CandleWallets;
1565
1967
  constructor(opts: CandleClientOptions);
@@ -1589,6 +1991,14 @@ export declare class CandleClient {
1589
1991
  * with (possibly none) and lets the server's own auth middleware decide.
1590
1992
  */
1591
1993
  getAgentTier(): Promise<AgentTierInfo>;
1994
+ /**
1995
+ * The plan table in force on this deployment (`GET /api/v1/agent/plans`, no credential): each
1996
+ * plan's price, agent fee, perps builder fee, the limits a new key gets, what it can do
1997
+ * (`capabilities`), and `promoMaxDays`. Quote prices and fees from here rather than hard-coding
1998
+ * them: they differ by deployment and change at the three-plan launch. `planTableRows()` renders
1999
+ * it. A server that predates the table answers 404 (`CandleApiError`).
2000
+ */
2001
+ getPlans(): Promise<AgentPlansResult>;
1592
2002
  dryRunLaunch(req: LaunchRequest): Promise<DryRunResult>;
1593
2003
  /**
1594
2004
  * Blocking launch with idempotent retries. Generates `clientLaunchId` when absent and
@@ -1652,6 +2062,11 @@ export declare class CandleClient {
1652
2062
  * (GET /api/v1/agent/keys/{prefix}/pnl). Read `unrealizedUsd` with `unmarkedPositions` and
1653
2063
  * `oldestMarkAt`: an unpriced position is counted there, never valued at zero.
1654
2064
  *
2065
+ * The figures are the key's share of the account's one P&L read, the console's figures to the
2066
+ * cent (`pnl.totalUsd` is the console's P&L). Since 2026-10-02 the total is the sum of the key's
2067
+ * wallets, not one pool across them, and `lookback` is the account's activity bound; see
2068
+ * `ProfilePnlResult` for every meaning that changed.
2069
+ *
1655
2070
  * Check `unvalued` and `truncated` before quoting the number: the first counts fills that had
1656
2071
  * no trusted USD price and were left out rather than counted as zero, the second says the
1657
2072
  * lookback window was full and this is not a lifetime figure.
@@ -2019,6 +2434,68 @@ export declare class CandleClient {
2019
2434
  * depends on an earlier leg already being mined.
2020
2435
  */
2021
2436
  private signBroadcastAndWaitEvmLeg;
2437
+ /** The server's perps settings: network, Candle's builder, this key's fee, and its limits. */
2438
+ perpsConfig(): Promise<PerpsConfig>;
2439
+ /**
2440
+ * One-time setup (R1): approves Candle's builder fee at 0.1% unless Hyperliquid already shows
2441
+ * it, and reports the account's mode and balance. Idempotent.
2442
+ */
2443
+ perpsSetup(params: PerpsWalletRef): Promise<PerpsSetupResult>;
2444
+ /** Open (or add to) a position: build, check, sign through the relay, submit to Hyperliquid. */
2445
+ perpsOpen(params: PerpsOpenParams): Promise<PerpsActionResult>;
2446
+ /** Close all or part of a position with a reduce-only IOC order. Reserves nothing. */
2447
+ perpsClose(params: PerpsCloseParams): Promise<PerpsActionResult>;
2448
+ /** Cancel an order Candle built, by its cloid. */
2449
+ perpsCancel(params: PerpsCancelParams): Promise<PerpsActionResult>;
2450
+ /** Change a resting order's price or size. The replacement gets a new cloid. */
2451
+ perpsModify(params: PerpsModifyParams): Promise<PerpsActionResult>;
2452
+ /** Set a market's leverage and margin mode on the account, within the key's maxLeverage. */
2453
+ perpsLeverage(params: PerpsLeverageParams): Promise<PerpsActionResult>;
2454
+ /** Add (positive) or remove (negative) isolated margin on an isolated position. */
2455
+ perpsMargin(params: PerpsMarginParams): Promise<PerpsActionResult>;
2456
+ /** Positions and account value, read live from Hyperliquid by the wallet's address. */
2457
+ perpsPositions(walletId: string): Promise<PerpsPositions>;
2458
+ /** Open orders on Hyperliquid, and Candle's record of every action it built, settled first. */
2459
+ perpsOrders(walletId: string, opts?: {
2460
+ limit?: number;
2461
+ }): Promise<PerpsOrders>;
2462
+ /** Fills, read live from Hyperliquid by the wallet's address. */
2463
+ perpsFills(walletId: string): Promise<{
2464
+ success: true;
2465
+ fills: Record<string, unknown>[];
2466
+ }>;
2467
+ /** Funding payments since `startTime` (epoch ms; default the last 7 days). */
2468
+ perpsFunding(walletId: string, startTime?: number): Promise<{
2469
+ success: true;
2470
+ startTime: number;
2471
+ funding: Record<string, unknown>[];
2472
+ }>;
2473
+ /**
2474
+ * Deposit onto the key's Hyperliquid account through Relay (Perps C, HL-ED-8): build, check the
2475
+ * build names `account` on chain 1337 with no Candle fee, then sign through the relay and submit.
2476
+ * From Solana that is one deposit transaction; from Hood each sequenced leg (approve, then the
2477
+ * deposit) is signed and submitted in turn. The fill is Relay's, after the deposit lands: read it
2478
+ * with `perpsDepositStatus()`. Candle checks Relay's steps before it stamps them; `candle perps
2479
+ * deposit` additionally decodes them on the caller's machine.
2480
+ */
2481
+ perpsDeposit(params: PerpsDepositParams): Promise<PerpsDepositResult>;
2482
+ /** A deposit's job: what was built and submitted, the Hood operation, and Relay's fill status. */
2483
+ perpsDepositStatus(clientDepositId: string): Promise<{
2484
+ success: true;
2485
+ job: Record<string, unknown>;
2486
+ }>;
2487
+ /** The builder every perps build is checked against (see `hyperliquidBuilder` in the options). */
2488
+ private perpsBuilder;
2489
+ /**
2490
+ * Check, sign, submit (HL-ED-2, HL-ED-5). The check runs before the relay is called; a build
2491
+ * that fails it is refused with nothing signed.
2492
+ */
2493
+ private perpsComplete;
2494
+ /**
2495
+ * Sign EIP-712 typed data with a linked EVM TEE wallet through the relay
2496
+ * (`eth_signTypedData_v4`). The relay signs only typed data a perps build stamped.
2497
+ */
2498
+ private signLinkedTypedData;
2022
2499
  private requireKey;
2023
2500
  private headers;
2024
2501
  private requestJson;
@@ -2046,7 +2523,7 @@ export declare class CandleClient {
2046
2523
  private jsonRpcCallRaw;
2047
2524
  }
2048
2525
  /** This build's own version. Kept in lockstep with package.json by the release-bump CI guard. */
2049
- export declare const SDK_VERSION = "0.4.5";
2526
+ export declare const SDK_VERSION = "0.4.7";
2050
2527
  /** Test seam: the once-per-process latch would otherwise weld the suite's first case to the rest. */
2051
2528
  export declare function __resetSdkUpdateNoticeForTest(): void;
2052
2529
  //# sourceMappingURL=client.d.ts.map