@totalis/hip4-client 0.74.0 → 0.76.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/CHANGELOG.md CHANGED
@@ -3,6 +3,93 @@
3
3
  `@totalis/hip4-client` follows [semantic versioning](https://semver.org).
4
4
  The contract version the generated types come from is `sdkVersion` in `./version`.
5
5
 
6
+ ## 0.76.0
7
+
8
+ Vault agents (TT-2554), one Combo leg per question (TT-2605) and no legs on
9
+ unpriced markets (TT-2606). Generated from contract
10
+ `205.0.0-device-vault-agents`. Additive: 0.75 code runs unchanged, but
11
+ `createRfq` now refuses two legs from one question and legs with a null
12
+ `chance`.
13
+
14
+ ### Added
15
+
16
+ - Vault agents (TT-2554). `agent` in `createTotalis` takes a key the account
17
+ granted; it then signs the account's `TakerAccept`, `SellBack`,
18
+ `CashoutTransfer` and Exits to HyperCore or the account's wallet instead of
19
+ `signer`, so those need no wallet prompt. `signer` still names the account
20
+ and signs USDC authorizations, HyperCore actions, grants and run-off claims.
21
+ - `grantVaultAgent({ agent, validUntil })` has the account sign an
22
+ `AgentGrant` and relays it (`POST /v1/me/vault-agents`); `revokeVaultAgent`
23
+ sends `validUntil` 0, and `vaultAgents()` iterates the live agents.
24
+ - `agentGrantTypedData` in `typed-data`, checked against the vault's vectors.
25
+ - A grant or revoke's default nonce rises past any nonce this client sent
26
+ explicitly for that agent, so it isn't refused for not exceeding it.
27
+
28
+ ### Changed
29
+
30
+ - `createRfq` refuses a Combo with two legs from one native question
31
+ (TT-2605): the second such leg is named in `field_violations` as
32
+ `/legs/{i}/outcome_id` with reason `SAME_QUESTION` (`400
33
+ INVALID_REQUEST`). Makers never quoted these legs, so such an RFQ used
34
+ to open and get no quotes. Allow one leg per `native_question_id` in your
35
+ slip; standalone markets have none and always combine.
36
+ - `createRfq` refuses a leg whose market has a side with a null `chance`
37
+ (an empty, dust or one-sided book with no recent evidence), with reason
38
+ `CHANCE_UNAVAILABLE` on `/legs/{i}/outcome_id` (`400 INVALID_REQUEST`).
39
+ Makers price from the book, and on such a book one small order sets the
40
+ price. Show `chance`, not `value`, and treat `chance: null` as unpriced
41
+ (TT-2606).
42
+
43
+ ## 0.75.0
44
+
45
+ Maker capital on the stream (TT-2584), a stream that cannot hang in
46
+ `connecting` (TT-2585), maker keys reading their own positions and
47
+ performance (TT-2583) and external wallets for embedded-wallet binding
48
+ (TT-2549). Generated from contract `204.0.0-maker-capital-stream`. Additive:
49
+ 0.74 code runs unchanged; a maker stream now sets `publication_freshness`
50
+ unless told not to.
51
+
52
+ ### Added
53
+
54
+ - A maker subscription can set `capital: true` (TT-2584). The stream then
55
+ emits `capital` with the maker's capital, the same body as
56
+ `GET /v1/makers/{maker_id}/capital`: once on subscribe, whenever it changes
57
+ (a fill, a hold or a vault change), and at least every 5 s. A bot keeps the
58
+ latest one instead of reading capital before it quotes; without one for
59
+ 15 s, read capital over HTTP. It needs `vault:read`. Contract
60
+ `204.0.0-maker-capital-stream`.
61
+ - `grantVaultAgent` (`POST /v1/me/vault-agents`): relay the account's signed
62
+ `AgentGrant` to a key one of its devices holds, or its revoke
63
+ (`valid_until: "0"`), so Combo accepts, cash-outs and Exits to the account's
64
+ own wallet or Core need no wallet prompt (TT-2550). Answers `202` with the
65
+ `setAgent` operation. Contract `205.0.0-device-vault-agents`.
66
+ - `getVaultAgents` (`GET /v1/me/vault-agents`): the account's live vault
67
+ agents, each with `valid_until`, `nonce` and `copy_agent`, paged with
68
+ `cursor` and `limit`.
69
+
70
+ ### Changed
71
+
72
+ - A maker key with `vault:read` can now read its own maker's positions
73
+ (`/v1/makers/{maker_id}/positions` and a single position), exposure and
74
+ `getMakerPerformance` (TT-2583); before, only a dashboard session could.
75
+ Another maker's ID answers 404.
76
+
77
+ - `TotalisStream` no longer hangs in `connecting` (TT-2585). A connect that
78
+ has not subscribed within `connectTimeoutMs` (new, default 10000), including
79
+ while `accessToken` resolves, emits `error` and reconnects. A maker
80
+ subscription now defaults to `publication_freshness: true`, as an account
81
+ does, so its 1 s heartbeats keep the 5 s silence timeout armed; pass
82
+ `publication_freshness: false` for the old 15 s profile, which has no
83
+ watchdog once subscribed. A silent socket now also emits `error` before it
84
+ reconnects.
85
+
86
+ - `bindEmbeddedWallet` can make the Ethereum wallet a Privy user signed in
87
+ with the account's wallet (`wallet_kind: "EXTERNAL"`) when they have no
88
+ embedded wallet (TT-2549). An existing account keeps its wallet.
89
+ `operationErrors` adds `WALLET_CONTRACT_UNSUPPORTED` (422) for a smart
90
+ contract wallet. `SIGN_IN_REQUIRED` now refuses only a Privy user with no
91
+ Google, email, X or Ethereum wallet login, such as a Solana-only one.
92
+
6
93
  ## 0.74.0
7
94
 
8
95
  Execution admission (TT-1355) and a follower's copied Combos (TT-2486,
@@ -227,7 +227,7 @@ export type paths = {
227
227
  readonly path?: never;
228
228
  readonly cookie?: never;
229
229
  };
230
- /** @description Performance of this maker per period. Complete periods aggregate the positions that closed economically in them; incomplete periods return unavailable metrics. Gas stays unavailable until the payer of every transaction receipt is attributed. The credential selects the deployment, and access is checked against its current permissions on every request. The maker is always the one named in the path, never inferred from the caller's account. */
230
+ /** @description Get your maker's trading P&L per period between `from` and `through`. */
231
231
  readonly get: operations["getMakerPerformance"];
232
232
  readonly put?: never;
233
233
  readonly post?: never;
@@ -261,7 +261,7 @@ export type paths = {
261
261
  readonly path?: never;
262
262
  readonly cookie?: never;
263
263
  };
264
- /** @description This maker's open book by outcome at the vault projection checkpoint: per outcome its YES and NO exposure, gross and net, worst case and what offsetting saves, and what awaits settlement; book totals count each ticket once. Legs resolve as a position's do. Dashboard sessions only, like positions. */
264
+ /** @description This maker's open book by outcome at the vault projection checkpoint: per outcome its YES and NO exposure, gross and net, worst case and what offsetting saves, and what awaits settlement; book totals count each ticket once. Legs resolve as a position's do. A maker key reads only its own maker. */
265
265
  readonly get: operations["getMakerExposure"];
266
266
  readonly put?: never;
267
267
  readonly post?: never;
@@ -1848,7 +1848,7 @@ export interface operations {
1848
1848
  };
1849
1849
  readonly requestBody?: never;
1850
1850
  readonly responses: {
1851
- /** @description Scoped read with one freshness status; amounts are atomic USDC strings or null. No shared caching. */
1851
+ /** @description Complete periods aggregate the positions that closed economically in them; incomplete periods return unavailable metrics. Gas stays unavailable until the payer of every transaction receipt is attributed. Scoped read with one freshness status; amounts are atomic USDC strings or null. No shared caching. */
1852
1852
  readonly 200: {
1853
1853
  headers: {
1854
1854
  readonly "Cache-Control": components["headers"]["CacheControl"];
@@ -49,6 +49,7 @@ export type paths = {
49
49
  readonly "/v1/me/copy-agents": Pick<SharedPaths["/v1/me/copy-agents"], "parameters" | "get">;
50
50
  readonly "/v1/me/copy-agents/core": Pick<SharedPaths["/v1/me/copy-agents/core"], "parameters" | "post" | "delete">;
51
51
  readonly "/v1/me/copy-agents/combo": Pick<SharedPaths["/v1/me/copy-agents/combo"], "parameters" | "post" | "delete">;
52
+ readonly "/v1/me/vault-agents": Pick<SharedPaths["/v1/me/vault-agents"], "parameters" | "get" | "post">;
52
53
  readonly "/v1/me/copy-budget": Pick<SharedPaths["/v1/me/copy-budget"], "parameters" | "get" | "put">;
53
54
  readonly "/v1/me/copy-agents/combo/confirm": Pick<SharedPaths["/v1/me/copy-agents/combo/confirm"], "parameters" | "post">;
54
55
  readonly "/v1/me/copy-agents/combo/grant": Pick<SharedPaths["/v1/me/copy-agents/combo/grant"], "parameters" | "post">;
@@ -102,4 +103,4 @@ export type paths = {
102
103
  readonly "/v1/makers/{maker_id}/exposure": Pick<SharedPaths["/v1/makers/{maker_id}/exposure"], "parameters" | "get">;
103
104
  readonly "/v1/makers/{maker_id}/performance": Pick<SharedPaths["/v1/makers/{maker_id}/performance"], "parameters" | "get">;
104
105
  };
105
- export type operations = Pick<SharedOperations, "abandonCoreExit" | "acceptQuote" | "activeCoreExits" | "admitOwnMaker" | "admitPartnerWallet" | "bindEmbeddedWallet" | "cancelRfq" | "confirmComboCopyAgent" | "confirmCoreCopyAgent" | "createCashout" | "createComment" | "createCoreExit" | "createDeposit" | "createRfq" | "createRunOffClaim" | "createWalletChallenge" | "createWalletSession" | "createWithdrawal" | "deleteComment" | "editComment" | "endWalletSession" | "followTrader" | "getAcceptance" | "getAccountActivity" | "getAccountPnl" | "getAccountPosition" | "getBalances" | "getCopyAgents" | "getCopyBudget" | "getCopySettings" | "getCopySummary" | "getCoreExit" | "getDeployment" | "getHypercoreBalance" | "getHypercorePortfolio" | "getHypercoreSettlementCredits" | "getIdentity" | "getMakerActivity" | "getMakerCapital" | "getMakerExposure" | "getMakerPerformance" | "getMakerPosition" | "getMakerQuotes" | "getMakerTelemetry" | "getMakerVaultFundingTransaction" | "getMakerWithdrawal" | "getMarket" | "getMarketDataConfig" | "getMarketDefinitions" | "getMarketHistory" | "getMarketRecurringRound" | "getMarketReferenceCloses" | "getMarketScoreTimeline" | "getMarketStats" | "getOperation" | "getOwnMaker" | "getPartnerReport" | "getPerpMarks" | "getProfitLeaderboard" | "getQuestion" | "getQuestionRecurringRound" | "getQuestionScoreTimeline" | "getRfq" | "getSeries" | "getSuggestedCombo" | "getTaxonomy" | "getTrader" | "getTraderPnl" | "getUsernameAvailability" | "getVolumeLeaderboard" | "getWithdrawal" | "grantComboCopyAgent" | "likeComment" | "listAccountActivity" | "listAccountPositions" | "listComboCopies" | "listCommentReplies" | "listComments" | "listControlledMakers" | "listCopiedFills" | "listCopyTrades" | "listDiscovery" | "listFollows" | "listMakerActivity" | "listMakerPositions" | "listMakerQuoteHistory" | "listMarkets" | "listOperations" | "listQuotes" | "listTraderPositions" | "listTraderTrades" | "reactComment" | "recordAcquisition" | "refreshPicture" | "requestComboCopyAgent" | "requestCoreCopyAgent" | "revokeComboCopyAgent" | "searchCatalog" | "setAvatar" | "setCopyAllocation" | "setCopySettings" | "setPublicProfile" | "setUsername" | "stream" | "streamMarkets" | "switchOffComboCopyAgent" | "switchOffCoreCopyAgent" | "unfollowTrader" | "unlikeComment" | "unreactComment">;
106
+ export type operations = Pick<SharedOperations, "abandonCoreExit" | "acceptQuote" | "activeCoreExits" | "admitOwnMaker" | "admitPartnerWallet" | "bindEmbeddedWallet" | "cancelRfq" | "confirmComboCopyAgent" | "confirmCoreCopyAgent" | "createCashout" | "createComment" | "createCoreExit" | "createDeposit" | "createRfq" | "createRunOffClaim" | "createWalletChallenge" | "createWalletSession" | "createWithdrawal" | "deleteComment" | "editComment" | "endWalletSession" | "followTrader" | "getAcceptance" | "getAccountActivity" | "getAccountPnl" | "getAccountPosition" | "getBalances" | "getCopyAgents" | "getCopyBudget" | "getCopySettings" | "getCopySummary" | "getCoreExit" | "getDeployment" | "getHypercoreBalance" | "getHypercorePortfolio" | "getHypercoreSettlementCredits" | "getIdentity" | "getMakerActivity" | "getMakerCapital" | "getMakerExposure" | "getMakerPerformance" | "getMakerPosition" | "getMakerQuotes" | "getMakerTelemetry" | "getMakerVaultFundingTransaction" | "getMakerWithdrawal" | "getMarket" | "getMarketDataConfig" | "getMarketDefinitions" | "getMarketHistory" | "getMarketRecurringRound" | "getMarketReferenceCloses" | "getMarketScoreTimeline" | "getMarketStats" | "getOperation" | "getOwnMaker" | "getPartnerReport" | "getPerpMarks" | "getProfitLeaderboard" | "getQuestion" | "getQuestionRecurringRound" | "getQuestionScoreTimeline" | "getRfq" | "getSeries" | "getSuggestedCombo" | "getTaxonomy" | "getTrader" | "getTraderPnl" | "getUsernameAvailability" | "getVaultAgents" | "getVolumeLeaderboard" | "getWithdrawal" | "grantComboCopyAgent" | "grantVaultAgent" | "likeComment" | "listAccountActivity" | "listAccountPositions" | "listComboCopies" | "listCommentReplies" | "listComments" | "listControlledMakers" | "listCopiedFills" | "listCopyTrades" | "listDiscovery" | "listFollows" | "listMakerActivity" | "listMakerPositions" | "listMakerQuoteHistory" | "listMarkets" | "listOperations" | "listQuotes" | "listTraderPositions" | "listTraderTrades" | "reactComment" | "recordAcquisition" | "refreshPicture" | "requestComboCopyAgent" | "requestCoreCopyAgent" | "revokeComboCopyAgent" | "searchCatalog" | "setAvatar" | "setCopyAllocation" | "setCopySettings" | "setPublicProfile" | "setUsername" | "stream" | "streamMarkets" | "switchOffComboCopyAgent" | "switchOffCoreCopyAgent" | "unfollowTrader" | "unlikeComment" | "unreactComment">;
@@ -333,7 +333,7 @@ export declare const operationErrors: {
333
333
  readonly activeCoreExits: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "DEPENDENCY_STALE", "RATE_LIMITED"];
334
334
  readonly admitOwnMaker: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "DEPENDENCY_STALE", "RATE_LIMITED", "ORIGIN_REQUIRED", "INVALID_REQUEST", "NOT_FOUND", "STATE_CONFLICT"];
335
335
  readonly admitPartnerWallet: readonly ["INVALID_REQUEST", "INVALID_IDEMPOTENCY_KEY", "UNAUTHENTICATED", "FORBIDDEN", "STATE_CONFLICT", "INVALID_SIGNATURE", "RATE_LIMITED", "AUTHORIZATION_UNAVAILABLE"];
336
- readonly bindEmbeddedWallet: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "DEPENDENCY_STALE", "RATE_LIMITED", "INVALID_REQUEST", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSED", "EMBEDDED_WALLET_CONFLICT", "ACCESS_REQUIRED", "SIGN_IN_REQUIRED", "ORIGIN_REQUIRED"];
336
+ readonly bindEmbeddedWallet: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "DEPENDENCY_STALE", "RATE_LIMITED", "INVALID_REQUEST", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSED", "EMBEDDED_WALLET_CONFLICT", "ACCESS_REQUIRED", "SIGN_IN_REQUIRED", "WALLET_CONTRACT_UNSUPPORTED", "ORIGIN_REQUIRED"];
337
337
  readonly cancelQuote: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "DEPENDENCY_STALE", "RATE_LIMITED", "INVALID_REQUEST", "NOT_FOUND", "STATE_CONFLICT"];
338
338
  readonly cancelRfq: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "DEPENDENCY_STALE", "RATE_LIMITED", "INVALID_REQUEST", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSED", "NOT_FOUND", "RFQ_NOT_CANCELLABLE", "STATE_CONFLICT", "ORIGIN_REQUIRED"];
339
339
  readonly confirmComboCopyAgent: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "RATE_LIMITED", "ORIGIN_REQUIRED", "IDENTITY_NOT_FOUND", "CONTRACT_UNAVAILABLE", "NOT_FOUND", "STATE_CONFLICT", "DEPENDENCY_STALE", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSED"];
@@ -410,9 +410,11 @@ export declare const operationErrors: {
410
410
  readonly getTrader: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "RATE_LIMITED", "INVALID_QUERY", "ORIGIN_REQUIRED", "NOT_FOUND", "SOURCE_UNAVAILABLE", "CONTRACT_UNAVAILABLE"];
411
411
  readonly getTraderPnl: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "RATE_LIMITED", "INVALID_QUERY", "ORIGIN_REQUIRED", "NOT_FOUND", "SOURCE_UNAVAILABLE", "CONTRACT_UNAVAILABLE"];
412
412
  readonly getUsernameAvailability: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "DEPENDENCY_STALE", "RATE_LIMITED", "INVALID_QUERY", "IDENTITY_NOT_FOUND", "ORIGIN_REQUIRED"];
413
+ readonly getVaultAgents: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "RATE_LIMITED", "ORIGIN_REQUIRED", "IDENTITY_NOT_FOUND", "INVALID_QUERY", "DEPENDENCY_STALE"];
413
414
  readonly getVolumeLeaderboard: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "DEPENDENCY_STALE", "RATE_LIMITED", "INVALID_QUERY", "CONTRACT_UNAVAILABLE"];
414
415
  readonly getWithdrawal: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "DEPENDENCY_STALE", "RATE_LIMITED", "INVALID_REQUEST", "NOT_FOUND"];
415
416
  readonly grantComboCopyAgent: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "RATE_LIMITED", "ORIGIN_REQUIRED", "IDENTITY_NOT_FOUND", "CONTRACT_UNAVAILABLE", "NOT_FOUND", "INVALID_REQUEST", "FINANCIAL_ACTIONS_DISABLED", "DEPENDENCY_STALE", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSED"];
417
+ readonly grantVaultAgent: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "RATE_LIMITED", "ORIGIN_REQUIRED", "IDENTITY_NOT_FOUND", "INVALID_REQUEST", "FINANCIAL_ACTIONS_DISABLED", "DEPENDENCY_STALE", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSED"];
416
418
  readonly likeComment: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "DEPENDENCY_STALE", "RATE_LIMITED", "ORIGIN_REQUIRED", "IDENTITY_NOT_FOUND", "NOT_FOUND", "INVALID_IDEMPOTENCY_KEY"];
417
419
  readonly listAccountActivity: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "DEPENDENCY_STALE", "RATE_LIMITED", "INVALID_QUERY", "ORIGIN_REQUIRED", "NOT_FOUND", "SOURCE_UNAVAILABLE", "CONTRACT_UNAVAILABLE", "CURSOR_EXPIRED"];
418
420
  readonly listAccountPositions: readonly ["UNAUTHENTICATED", "FORBIDDEN", "AUTHORIZATION_UNAVAILABLE", "DEPENDENCY_STALE", "RATE_LIMITED", "INVALID_QUERY", "ORIGIN_REQUIRED", "NOT_FOUND", "SOURCE_UNAVAILABLE", "CONTRACT_UNAVAILABLE", "CURSOR_EXPIRED"];
@@ -405,6 +405,7 @@ export const operationErrors = {
405
405
  "EMBEDDED_WALLET_CONFLICT",
406
406
  "ACCESS_REQUIRED",
407
407
  "SIGN_IN_REQUIRED",
408
+ "WALLET_CONTRACT_UNSUPPORTED",
408
409
  "ORIGIN_REQUIRED"
409
410
  ],
410
411
  "cancelQuote": [
@@ -1196,6 +1197,16 @@ export const operationErrors = {
1196
1197
  "IDENTITY_NOT_FOUND",
1197
1198
  "ORIGIN_REQUIRED"
1198
1199
  ],
1200
+ "getVaultAgents": [
1201
+ "UNAUTHENTICATED",
1202
+ "FORBIDDEN",
1203
+ "AUTHORIZATION_UNAVAILABLE",
1204
+ "RATE_LIMITED",
1205
+ "ORIGIN_REQUIRED",
1206
+ "IDENTITY_NOT_FOUND",
1207
+ "INVALID_QUERY",
1208
+ "DEPENDENCY_STALE"
1209
+ ],
1199
1210
  "getVolumeLeaderboard": [
1200
1211
  "UNAUTHENTICATED",
1201
1212
  "FORBIDDEN",
@@ -1229,6 +1240,19 @@ export const operationErrors = {
1229
1240
  "INVALID_IDEMPOTENCY_KEY",
1230
1241
  "IDEMPOTENCY_KEY_REUSED"
1231
1242
  ],
1243
+ "grantVaultAgent": [
1244
+ "UNAUTHENTICATED",
1245
+ "FORBIDDEN",
1246
+ "AUTHORIZATION_UNAVAILABLE",
1247
+ "RATE_LIMITED",
1248
+ "ORIGIN_REQUIRED",
1249
+ "IDENTITY_NOT_FOUND",
1250
+ "INVALID_REQUEST",
1251
+ "FINANCIAL_ACTIONS_DISABLED",
1252
+ "DEPENDENCY_STALE",
1253
+ "INVALID_IDEMPOTENCY_KEY",
1254
+ "IDEMPOTENCY_KEY_REUSED"
1255
+ ],
1232
1256
  "likeComment": [
1233
1257
  "UNAUTHENTICATED",
1234
1258
  "FORBIDDEN",
@@ -426,7 +426,7 @@ export type paths = {
426
426
  readonly put?: never;
427
427
  /**
428
428
  * Bind embedded wallet
429
- * @description Idempotently binds the one Ethereum wallet attested by the authenticated user's signed Privy identity token. BYOW and multiple wallets are rejected. Creating a new account needs a Google, email or X login linked in the identity token, or this answers SIGN_IN_REQUIRED (a Privy user with only an external wallet, such as one from another app on the same Privy app, is refused), and, while the closed launch is on, an invite code redeemed with the access service first, or this answers ACCESS_REQUIRED. Existing accounts are unaffected.
429
+ * @description Idempotently makes a wallet attested by the authenticated user's signed Privy identity token the account's: the account's current wallet if it has one, else the Privy embedded wallet, else the one Ethereum wallet the user signed in with. The account's wallet never changes once bound; several external wallets on a new account, or a wallet another account holds, answer EMBEDDED_WALLET_CONFLICT, and a smart contract wallet answers WALLET_CONTRACT_UNSUPPORTED. Creating a new account needs a Google, email, X or Ethereum wallet login linked in the identity token, or this answers SIGN_IN_REQUIRED (a Privy user with only a Solana wallet, such as one from the Solana app on the same Privy app, is refused), and, while the closed launch is on, an invite code redeemed with the access service first, or this answers ACCESS_REQUIRED. Existing accounts are unaffected.
430
430
  */
431
431
  readonly post: operations["bindEmbeddedWallet"];
432
432
  readonly delete?: never;
@@ -1031,6 +1031,30 @@ export type paths = {
1031
1031
  readonly patch?: never;
1032
1032
  readonly trace?: never;
1033
1033
  };
1034
+ readonly "/v1/me/vault-agents": {
1035
+ readonly parameters: {
1036
+ readonly query?: never;
1037
+ readonly header?: never;
1038
+ readonly path?: never;
1039
+ readonly cookie?: never;
1040
+ };
1041
+ /**
1042
+ * Get my vault agents
1043
+ * @description The authenticated account's vault agents whose latest AgentGrant on chain is still live, by agent address, a page at a time: each agent may sign the account's named TakerAccept, owner-side SellBack, seller-side CashoutTransfer and Exit to the account's own wallet or Core spot until valid_until. copy_agent marks a server-held copy agent (managed under /v1/me/copy-agents) rather than a key one of the account's devices holds. A grant appears once the chain-agent projects it, after its operation completes. nonce is the agent's last grant, which a new grant or revoke must exceed.
1044
+ */
1045
+ readonly get: operations["getVaultAgents"];
1046
+ readonly put?: never;
1047
+ /**
1048
+ * Relay the account's grant or revoke of a device's vault agent
1049
+ * @description Relays the account's EIP-712 signature over AgentGrant(account, agent, valid_until, nonce) to setAgent; Totalis pays the gas. agent is a key one of the account's devices holds, so it can sign the account's named Combo accepts, cash-outs and Exits to its own wallet or Core spot without a wallet prompt. valid_until is unix seconds, in the future and at most 180 days away (the vault's limit); 0 revokes at once. nonce must exceed the agent's last grant (GET /v1/me/vault-agents), so a client uses the current unix time. Only the account's own signature (or its ERC-1271 verdict) grants. 403 FORBIDDEN for a copy agent, whose grants go through /v1/me/copy-agents. While financial actions run off only a revoke is relayed. A retry with the same Idempotency-Key returns the same operation.
1050
+ */
1051
+ readonly post: operations["grantVaultAgent"];
1052
+ readonly delete?: never;
1053
+ readonly options?: never;
1054
+ readonly head?: never;
1055
+ readonly patch?: never;
1056
+ readonly trace?: never;
1057
+ };
1034
1058
  readonly "/v1/me/copy-budget": {
1035
1059
  readonly parameters: {
1036
1060
  readonly query?: never;
@@ -2429,7 +2453,7 @@ export type paths = {
2429
2453
  };
2430
2454
  /**
2431
2455
  * Get maker exposure
2432
- * @description This maker's open book by outcome at the vault projection checkpoint: per outcome its YES and NO exposure, gross and net, worst case and what offsetting saves, and what awaits settlement; book totals count each ticket once. Legs resolve as a position's do. Dashboard sessions only, like positions.
2456
+ * @description This maker's open book by outcome at the vault projection checkpoint: per outcome its YES and NO exposure, gross and net, worst case and what offsetting saves, and what awaits settlement; book totals count each ticket once. Legs resolve as a position's do. A maker key reads only its own maker.
2433
2457
  */
2434
2458
  readonly get: operations["getMakerExposure"];
2435
2459
  readonly put?: never;
@@ -2449,7 +2473,7 @@ export type paths = {
2449
2473
  };
2450
2474
  /**
2451
2475
  * Get maker performance
2452
- * @description Performance of this maker per period. Complete periods aggregate the positions that closed economically in them; incomplete periods return unavailable metrics. Gas stays unavailable until the payer of every transaction receipt is attributed. The credential selects the deployment, and access is checked against its current permissions on every request. The maker is always the one named in the path, never inferred from the caller's account.
2476
+ * @description Get your maker's trading P&L per period between `from` and `through`.
2453
2477
  */
2454
2478
  readonly get: operations["getMakerPerformance"];
2455
2479
  readonly put?: never;
@@ -2560,6 +2584,38 @@ export type components = {
2560
2584
  /** @description The account's EIP-712 signature over AgentGrant(account, agent, 0, nonce). */
2561
2585
  readonly signature: components["schemas"]["Signature65"];
2562
2586
  };
2587
+ /** VaultAgentGrant */
2588
+ readonly VaultAgentGrant: {
2589
+ /** @description The key a device of the account holds; not the account, not a copy agent. */
2590
+ readonly agent: components["schemas"]["LowercaseNonZeroAddress"];
2591
+ /** @description Unix seconds the grant lasts until, at most 180 days away; 0 revokes. */
2592
+ readonly valid_until: components["schemas"]["UInt64String"];
2593
+ /** @description Above the agent's last grant; the current unix time works. */
2594
+ readonly nonce: components["schemas"]["UInt64String"];
2595
+ /** @description The account's EIP-712 signature over AgentGrant(account, agent, valid_until, nonce) in the vault's domain. */
2596
+ readonly signature: components["schemas"]["Signature65"];
2597
+ };
2598
+ /** VaultAgents */
2599
+ readonly VaultAgents: {
2600
+ /** @description The account wallet the agents sign for. */
2601
+ readonly account: components["schemas"]["Address"];
2602
+ /** @description Live grants, by agent address. */
2603
+ readonly agents: readonly components["schemas"]["VaultAgent"][];
2604
+ readonly next_cursor: components["schemas"]["NextCursor"];
2605
+ /** @description Whether more agents follow next_cursor. */
2606
+ readonly has_more: boolean;
2607
+ };
2608
+ /** VaultAgent */
2609
+ readonly VaultAgent: {
2610
+ /** @description The agent key. */
2611
+ readonly agent: components["schemas"]["Address"];
2612
+ /** @description Unix seconds the grant lasts until. */
2613
+ readonly valid_until: components["schemas"]["UInt64String"];
2614
+ /** @description The grant's nonce; a new grant or revoke must exceed it. */
2615
+ readonly nonce: components["schemas"]["UInt64String"];
2616
+ /** @description A server-held copy agent rather than a device's key. */
2617
+ readonly copy_agent: boolean;
2618
+ };
2563
2619
  /** AgentGrantRelayed */
2564
2620
  readonly AgentGrantRelayed: {
2565
2621
  /** @description The relayed setAgent operation. */
@@ -2787,7 +2843,7 @@ export type components = {
2787
2843
  readonly CreateRfqCommand: {
2788
2844
  /** @description Stake in atomic USDC (6 decimals), before taker fees; must be positive. Quotes carry the same stake. */
2789
2845
  readonly stake: components["schemas"]["$defs-Amount"];
2790
- /** @description 1 to 5 legs in strictly increasing outcome_id order. */
2846
+ /** @description 1 to 5 legs in strictly increasing outcome_id order, at most one per native question. Every leg's market must have eligibility ENABLED and combo OPEN, and a chance on each side. */
2791
2847
  readonly legs: readonly components["schemas"]["$defs-Leg"][];
2792
2848
  /** @description Optional partner attribution code, from any credential. From an account a partner admitted, it must be one of that partner's active codes and needs no signature; with none, the partner's account code is recorded. From any other account it needs builder_authorization_expiry and builder_signature from the partner's registered signer and is honoured only from the code's registered browser origin, so an API-key request (no Origin) from such an account cannot send one. A refused code returns INVALID_REQUEST naming /builder_code. Revocation rejects new RFQs without vetoing an already-created RFQ. Partners get codes from Totalis. */
2793
2849
  readonly builder_code?: string;
@@ -7112,7 +7168,7 @@ export interface operations {
7112
7168
  };
7113
7169
  readonly requestBody?: never;
7114
7170
  readonly responses: {
7115
- /** @description Embedded wallet is bound */
7171
+ /** @description Account wallet is bound */
7116
7172
  readonly 204: {
7117
7173
  headers: {
7118
7174
  readonly [name: string]: unknown;
@@ -7123,6 +7179,7 @@ export interface operations {
7123
7179
  readonly 401: components["responses"]["Error"];
7124
7180
  readonly 403: components["responses"]["Error"];
7125
7181
  readonly 409: components["responses"]["Error"];
7182
+ readonly 422: components["responses"]["Error"];
7126
7183
  readonly 429: components["responses"]["RateLimited"];
7127
7184
  readonly 503: components["responses"]["Unavailable"];
7128
7185
  };
@@ -8507,6 +8564,81 @@ export interface operations {
8507
8564
  readonly 503: components["responses"]["Unavailable"];
8508
8565
  };
8509
8566
  };
8567
+ readonly getVaultAgents: {
8568
+ readonly parameters: {
8569
+ readonly query?: {
8570
+ /**
8571
+ * @description Omit for the first page; then send the previous response's next_cursor unchanged.
8572
+ * @example eyJ2IjoxLCJzIjoiMTIzNDUifQ
8573
+ */
8574
+ readonly cursor?: components["parameters"]["Cursor"];
8575
+ /**
8576
+ * @description Maximum items per page, 1 to 200, default 50. A page may hold fewer, even none, while has_more is true.
8577
+ * @example 50
8578
+ */
8579
+ readonly limit?: components["parameters"]["Limit"];
8580
+ };
8581
+ readonly header?: never;
8582
+ readonly path?: never;
8583
+ readonly cookie?: never;
8584
+ };
8585
+ readonly requestBody?: never;
8586
+ readonly responses: {
8587
+ /** @description The account's live vault agents */
8588
+ readonly 200: {
8589
+ headers: {
8590
+ readonly "Cache-Control"?: "no-store";
8591
+ readonly [name: string]: unknown;
8592
+ };
8593
+ content: {
8594
+ readonly "application/json": components["schemas"]["VaultAgents"];
8595
+ };
8596
+ };
8597
+ readonly 400: components["responses"]["Error"];
8598
+ readonly 401: components["responses"]["Error"];
8599
+ readonly 403: components["responses"]["Error"];
8600
+ readonly 404: components["responses"]["Error"];
8601
+ readonly 429: components["responses"]["RateLimited"];
8602
+ readonly 503: components["responses"]["Unavailable"];
8603
+ };
8604
+ };
8605
+ readonly grantVaultAgent: {
8606
+ readonly parameters: {
8607
+ readonly query?: never;
8608
+ readonly header: {
8609
+ /**
8610
+ * @description Lowercase UUIDv7 naming this command, unique per caller and route. A retry with the same key and body returns the original result; the same key with a different body returns `409 IDEMPOTENCY_KEY_REUSED`.
8611
+ * @example 0198a6f6-82a5-7abc-9f2a-4f0fb437493e
8612
+ */
8613
+ readonly "Idempotency-Key": components["parameters"]["IdempotencyKey"];
8614
+ };
8615
+ readonly path?: never;
8616
+ readonly cookie?: never;
8617
+ };
8618
+ readonly requestBody: {
8619
+ readonly content: {
8620
+ readonly "application/json": components["schemas"]["VaultAgentGrant"];
8621
+ };
8622
+ };
8623
+ readonly responses: {
8624
+ /** @description Relayed, not yet on chain. Follow the operation with `GET /v1/me/operations/{operation_id}`. */
8625
+ readonly 202: {
8626
+ headers: {
8627
+ readonly [name: string]: unknown;
8628
+ };
8629
+ content: {
8630
+ readonly "application/json": components["schemas"]["AgentGrantRelayed"];
8631
+ };
8632
+ };
8633
+ readonly 400: components["responses"]["Error"];
8634
+ readonly 401: components["responses"]["Error"];
8635
+ readonly 403: components["responses"]["Error"];
8636
+ readonly 404: components["responses"]["Error"];
8637
+ readonly 409: components["responses"]["Error"];
8638
+ readonly 429: components["responses"]["RateLimited"];
8639
+ readonly 503: components["responses"]["Unavailable"];
8640
+ };
8641
+ };
8510
8642
  readonly getCopyBudget: {
8511
8643
  readonly parameters: {
8512
8644
  readonly query?: never;
@@ -9426,7 +9558,7 @@ export interface operations {
9426
9558
  readonly "application/json": components["schemas"]["RfqCreated"];
9427
9559
  };
9428
9560
  };
9429
- /** @description `INVALID_REQUEST`: the body is malformed, or a leg's market refuses new positions now. A refused leg is named in `field_violations` as `/legs/{i}/outcome_id`, and the message gives the reason, such as `REFERENCE_UNAVAILABLE` or `OUTSIDE_WINDOW`; the market's `eligibility` and `combo` show when it clears. */
9561
+ /** @description `INVALID_REQUEST`: the body is malformed, or a leg's market refuses new positions now. A refused leg is named in `field_violations` as `/legs/{i}/outcome_id`, and the message gives the reason, such as `REFERENCE_UNAVAILABLE`, `OUTSIDE_WINDOW`, `CHANCE_UNAVAILABLE` for a side whose `chance` is null, or `SAME_QUESTION` for a leg whose `native_question_id` an earlier leg already has; the market's `eligibility` and `combo` show when it clears. */
9430
9562
  readonly 400: components["responses"]["Error"];
9431
9563
  readonly 401: components["responses"]["Error"];
9432
9564
  readonly 403: components["responses"]["Error"];
@@ -10955,7 +11087,7 @@ export interface operations {
10955
11087
  };
10956
11088
  readonly requestBody?: never;
10957
11089
  readonly responses: {
10958
- /** @description Scoped read with one freshness status; amounts are atomic USDC strings or null. No shared caching. */
11090
+ /** @description Complete periods aggregate the positions that closed economically in them; incomplete periods return unavailable metrics. Gas stays unavailable until the payer of every transaction receipt is attributed. Scoped read with one freshness status; amounts are atomic USDC strings or null. No shared caching. */
10959
11091
  readonly 200: {
10960
11092
  headers: {
10961
11093
  readonly "Cache-Control": components["headers"]["CacheControl"];
@@ -371,6 +371,15 @@ export type components = {
371
371
  /** @description Publication coverage, sent each heartbeat to subscriptions that set publication_freshness. Null when no checkpoint is available; treat freshness as unproven. */
372
372
  readonly data: components["schemas"]["PublicationCheckpoint"] | null;
373
373
  };
374
+ readonly CapitalFrame: {
375
+ /**
376
+ * @description Frame discriminator, always capital. Sent to maker subscriptions that set capital: once on subscribe, again whenever the capital changes, and at least every 5000 ms.
377
+ * @constant
378
+ */
379
+ readonly channel: "capital";
380
+ /** @description The same body as GET /v1/makers/{maker_id}/capital, read when the frame was published; its context says how fresh it is. Without a frame for 15 s, read capital over HTTP. */
381
+ readonly data: components["schemas"]["MakerCapital"];
382
+ };
374
383
  readonly Snapshot: {
375
384
  /** @description Stream cursor the snapshot is consistent with. Events after it follow on the stream; reconnect with it to replay them. */
376
385
  readonly cursor: components["schemas"]["Cursor"];
@@ -413,6 +422,8 @@ export type components = {
413
422
  readonly account_reads?: boolean;
414
423
  /** @description Opt in to publication checkpoints and a 1000 ms authenticated heartbeat. */
415
424
  readonly publication_freshness?: boolean;
425
+ /** @description Opt in to capital frames: the maker's capital read, pushed when it changes and at least every 5 s. Needs vault:read; without it the server closes with SUBSCRIPTION_DENIED. */
426
+ readonly capital?: boolean;
416
427
  };
417
428
  readonly Subscribe: {
418
429
  /**
@@ -461,6 +472,8 @@ export type components = {
461
472
  readonly account_reads?: boolean;
462
473
  /** @description Opt in to publication checkpoints and a 1000 ms authenticated heartbeat. */
463
474
  readonly publication_freshness?: boolean;
475
+ /** @description Opt in to capital frames: the maker's capital read, pushed when it changes and at least every 5 s. Needs vault:read; without it the server closes with SUBSCRIPTION_DENIED. */
476
+ readonly capital?: boolean;
464
477
  };
465
478
  /**
466
479
  * Format: uuid
@@ -990,6 +1003,88 @@ export type components = {
990
1003
  /** @description When the withdrawal last changed, RFC3339 UTC. */
991
1004
  readonly updated_at: components["schemas"]["Timestamp"];
992
1005
  };
1006
+ /** Format: date-time */
1007
+ readonly "$defs-Timestamp": string;
1008
+ /** @description Freshness of the read. Pages of one list share the snapshot bound into their cursor. */
1009
+ readonly ReadContext: {
1010
+ /** @description RFC3339 observation time of the oldest source this read used. */
1011
+ readonly as_of: components["schemas"]["$defs-Timestamp"];
1012
+ /**
1013
+ * @description Freshness of the whole read. CURRENT: every source is fresh and reconciled. STALE: a source lags or has not reconciled, such as a catching-up projection, a pending reorg rescan or a period not fully covered; amounts may be displayed with their age but never authorize an action. UNAVAILABLE: a required source could not be read, so the amounts it backs are null.
1014
+ * @enum {string}
1015
+ */
1016
+ readonly status: "CURRENT" | "STALE" | "UNAVAILABLE";
1017
+ };
1018
+ readonly "$defs-Amount": string;
1019
+ /** @description Non-negative amount in atomic USDC (6 decimals, "1000000" = 1 USDC); null when it could not be established, never zero in its place. */
1020
+ readonly UnsignedMetric: components["schemas"]["$defs-Amount"] | null;
1021
+ readonly SignedAmount: string;
1022
+ /** @description Signed amount in atomic USDC (6 decimals, "1000000" = 1 USDC); null when it could not be established, never zero in its place. */
1023
+ readonly Metric: components["schemas"]["SignedAmount"] | null;
1024
+ readonly ActionAvailability: {
1025
+ /**
1026
+ * @description Action this decision covers: MAKER_WITHDRAW or MAKER_QUOTE.
1027
+ * @enum {string}
1028
+ */
1029
+ readonly action: "MAKER_WITHDRAW" | "MAKER_QUOTE";
1030
+ /** @description Funding route the decision covers, e.g. MAKER_VAULT. */
1031
+ readonly route: string;
1032
+ /** @description Amount available for this action and route in atomic USDC (6 decimals, "1000000" = 1 USDC); null with blockers when unavailable. */
1033
+ readonly available: components["schemas"]["UnsignedMetric"];
1034
+ /** @description Machine-readable codes blocking the action, e.g. MAKER_WITHDRAW_PENDING or RECONCILIATION_MISMATCH; at least one when available is null. */
1035
+ readonly blockers: readonly string[];
1036
+ };
1037
+ /** @description A venue admission reservation on the maker vault. */
1038
+ readonly Reservation: {
1039
+ /** @description Stable reservation identifier. */
1040
+ readonly reservation_id: string;
1041
+ /** @description Operations holding this reservation. */
1042
+ readonly operation_ids: readonly string[];
1043
+ /** @description Reserved amount in atomic USDC (6 decimals, "1000000" = 1 USDC). */
1044
+ readonly value: components["schemas"]["$defs-Amount"];
1045
+ /**
1046
+ * @description ACTIVE: held and not yet reflected on-chain; UNKNOWN: outcome unknown, still counted as held.
1047
+ * @enum {string}
1048
+ */
1049
+ readonly status: "ACTIVE" | "UNKNOWN";
1050
+ };
1051
+ /** @description Maker capital lanes and derived collateral, in atomic USDC (6 decimals, "1000000" = 1 USDC). Amounts are null when unavailable; context.status is their freshness. */
1052
+ readonly MakerCapital: {
1053
+ /** @description Freshness of this read: the oldest source observation and one status for every amount in the response. */
1054
+ readonly context: components["schemas"]["ReadContext"];
1055
+ /** @description Maker owner (its controller) from the same indexed vault row as the lanes. */
1056
+ readonly owner: components["schemas"]["LowercaseNonZeroAddress"];
1057
+ /** @description Maker signer (its quote signer) from the same indexed vault row as the lanes. The zero address means the maker was opened without one and cannot quote. */
1058
+ readonly signer: string;
1059
+ /** @description Maker vault lane V from the vault contract, including escrow and payables. */
1060
+ readonly vault_gross: components["schemas"]["UnsignedMetric"];
1061
+ /** @description Bettor net stakes escrowed in this maker's open tickets (E). */
1062
+ readonly stake_escrow: components["schemas"]["UnsignedMetric"];
1063
+ /** @description Settled winnings owed to ticket holders and not yet claimed (P). */
1064
+ readonly payable_owed: components["schemas"]["UnsignedMetric"];
1065
+ /** @description Original open maker exposure G: payout minus net stake summed over open tickets. */
1066
+ readonly gross_open: components["schemas"]["UnsignedMetric"];
1067
+ /** @description Maker discount lane D from the vault contract, which offsets gross_open in the requirement. */
1068
+ readonly discount: components["schemas"]["UnsignedMetric"];
1069
+ /** @description Collateral requirement R = max(G - min(D, G), ceil(G * floor_bps / 10000)) under the pinned release; null when floor_bps is null or an input is null. */
1070
+ readonly requirement: components["schemas"]["UnsignedMetric"];
1071
+ /** @description Collateral headroom F = max(V - E - P - R, 0). Not a guarantee of quote acceptance. */
1072
+ readonly free_collateral: components["schemas"]["UnsignedMetric"];
1073
+ /** @description Signed C = V - E - P. Excludes open-ticket valuation; not equity or NAV. */
1074
+ readonly capital_net_of_senior_liabilities: components["schemas"]["Metric"];
1075
+ /** @description Admission reservations H the venue holds for this maker that are not yet reflected on-chain; the sum of reservations. */
1076
+ readonly pending_commitments: components["schemas"]["UnsignedMetric"];
1077
+ /** @description max(F - H, 0): free collateral after unreflected commitments. Not private bot capacity. */
1078
+ readonly free_after_pending: components["schemas"]["UnsignedMetric"];
1079
+ /** @description Requirement floor K in basis points from the pinned release; null when the on-chain comparison mismatches, which makes requirement UNAVAILABLE. */
1080
+ readonly floor_bps: number | null;
1081
+ /** @description SHA-256 of the exact pinned artifact that names this deployment's chain and vault: the release artifact on chain 999, the environment's deployment manifest on 998. A client compares it with its own pinned artifact to bind the read to its deployment. */
1082
+ readonly deployment_digest: string;
1083
+ /** @description Decisions for MAKER_WITHDRAW and MAKER_QUOTE on the MAKER_VAULT route. MAKER_WITHDRAW is the amount a new withdrawal request may ask for: free_after_pending, so it never takes collateral from fills already admitted. The vault re-checks free collateral when the request executes after its delay; it is null with MAKER_WITHDRAW_PENDING while a request is live, or with a reconciliation blocker. MAKER_QUOTE is always null with one blocker, because quoting capacity depends on state only the maker's bot holds, such as its other live quotes. PRIVATE_QUOTE_CAPACITY_UNAVAILABLE means only that Totalis cannot compute that amount; it does not mean quoting is off, and the maker can keep quoting. A reconciliation blocker replaces it while the vault read and venue records disagree. */
1084
+ readonly actions: readonly components["schemas"]["ActionAvailability"][];
1085
+ /** @description Venue reservations on MAKER_VAULT that make up pending_commitments. */
1086
+ readonly reservations: readonly components["schemas"]["Reservation"][];
1087
+ } & unknown;
993
1088
  readonly ReadSubscription: {
994
1089
  /**
995
1090
  * @description Account-read contract version of the subscription; always "1".
@@ -1,12 +1,12 @@
1
- export declare const sdkVersion = "203.0.0-execution-admission";
2
- export declare const openapiSha256 = "2304ae546fe97a86cbb1147dccdebe50f5bb44080c26b88503356ac9dd1aa096";
3
- export declare const realtimeSha256 = "6491fe1d9b5fdcfefcbee71716401effa181e7bcdf1fa4623fbb83dc5b2975cd";
1
+ export declare const sdkVersion = "205.0.0-device-vault-agents";
2
+ export declare const openapiSha256 = "93141e0bf50949fc37ebceef7c64555eb50a70f69c71c89c8fdc12780e0dd168";
3
+ export declare const realtimeSha256 = "1cac740e108e84ad1979f6ccc71089efd840404cb72d1612a86edc02769637e3";
4
4
  export declare const jsonSchemaSha256: {
5
5
  readonly "account.schema.json": "5106e2d53abef190990eff113f6692dd27df5848439cf5a80a42c11e89f2bef6";
6
6
  readonly "comments.schema.json": "18f4addcfa4e31c2c833fce8b8beca61d2e2ee5b6318c2ed0b479698ff56b65e";
7
7
  readonly "common.schema.json": "04f51deb3cbea448e59195e26ede3212598d58a7940fe67eb2123fd9161c5edb";
8
8
  readonly "core-exit.schema.json": "c7f617e815225cdcac95c236f8b73fbe288ee5713ff444c3be90eb915fc3a401";
9
- readonly "error.schema.json": "85b2e13d449f137322779086c96d1355d0e70708647eb67b62c9b4070ed6530e";
9
+ readonly "error.schema.json": "56b1e1c4ea26078cb8ce7ab3c554c0415c8c82eec45821180fc0d5e891046c1e";
10
10
  readonly "hypercore.schema.json": "5b89b2bbff7ec8cc1b8717375d12ce9cd5ab6aa5af03c4fdc6cc753ef9583a2c";
11
11
  readonly "identity.schema.json": "94534b768030736f4fd1fad285f1312454ca5fbff0b1eb5fab70416a78923bd0";
12
12
  readonly "maker-access.schema.json": "49698ee0235e42064aae0397db1e0f646bdc10d9dfa10121714ba06dd69fee3b";
@@ -15,10 +15,10 @@ export declare const jsonSchemaSha256: {
15
15
  readonly "market-data.schema.json": "85db33fac6a29b0fa87a500bfda947d0ab3913b13f1c26663d4a7c0484c35786";
16
16
  readonly "product-metadata.schema.json": "7c8ffbde878a0aedaed16814fcfd2e80038054b140886cc8736bb7b508042631";
17
17
  readonly "quote.schema.json": "5616260d399d022bde2d0130cc9f8a09f71a3dc877276adf796c7a174d21b59a";
18
- readonly "realtime.schema.json": "6491fe1d9b5fdcfefcbee71716401effa181e7bcdf1fa4623fbb83dc5b2975cd";
18
+ readonly "realtime.schema.json": "1cac740e108e84ad1979f6ccc71089efd840404cb72d1612a86edc02769637e3";
19
19
  };
20
20
  export declare const operations: {
21
- readonly client: readonly ["abandonCoreExit", "acceptQuote", "activeCoreExits", "admitOwnMaker", "admitPartnerWallet", "bindEmbeddedWallet", "cancelRfq", "confirmComboCopyAgent", "confirmCoreCopyAgent", "createCashout", "createComment", "createCoreExit", "createDeposit", "createRfq", "createRunOffClaim", "createWalletChallenge", "createWalletSession", "createWithdrawal", "deleteComment", "editComment", "endWalletSession", "followTrader", "getAcceptance", "getAccountActivity", "getAccountPnl", "getAccountPosition", "getBalances", "getCopyAgents", "getCopyBudget", "getCopySettings", "getCopySummary", "getCoreExit", "getDeployment", "getHypercoreBalance", "getHypercorePortfolio", "getHypercoreSettlementCredits", "getIdentity", "getMakerActivity", "getMakerCapital", "getMakerExposure", "getMakerPerformance", "getMakerPosition", "getMakerQuotes", "getMakerTelemetry", "getMakerVaultFundingTransaction", "getMakerWithdrawal", "getMarket", "getMarketDataConfig", "getMarketDefinitions", "getMarketHistory", "getMarketRecurringRound", "getMarketReferenceCloses", "getMarketScoreTimeline", "getMarketStats", "getOperation", "getOwnMaker", "getPartnerReport", "getPerpMarks", "getProfitLeaderboard", "getQuestion", "getQuestionRecurringRound", "getQuestionScoreTimeline", "getRfq", "getSeries", "getSuggestedCombo", "getTaxonomy", "getTrader", "getTraderPnl", "getUsernameAvailability", "getVolumeLeaderboard", "getWithdrawal", "grantComboCopyAgent", "likeComment", "listAccountActivity", "listAccountPositions", "listComboCopies", "listCommentReplies", "listComments", "listControlledMakers", "listCopiedFills", "listCopyTrades", "listDiscovery", "listFollows", "listMakerActivity", "listMakerPositions", "listMakerQuoteHistory", "listMarkets", "listOperations", "listQuotes", "listTraderPositions", "listTraderTrades", "reactComment", "recordAcquisition", "refreshPicture", "requestComboCopyAgent", "requestCoreCopyAgent", "revokeComboCopyAgent", "searchCatalog", "setAvatar", "setCopyAllocation", "setCopySettings", "setPublicProfile", "setUsername", "stream", "streamMarkets", "switchOffComboCopyAgent", "switchOffCoreCopyAgent", "unfollowTrader", "unlikeComment", "unreactComment"];
21
+ readonly client: readonly ["abandonCoreExit", "acceptQuote", "activeCoreExits", "admitOwnMaker", "admitPartnerWallet", "bindEmbeddedWallet", "cancelRfq", "confirmComboCopyAgent", "confirmCoreCopyAgent", "createCashout", "createComment", "createCoreExit", "createDeposit", "createRfq", "createRunOffClaim", "createWalletChallenge", "createWalletSession", "createWithdrawal", "deleteComment", "editComment", "endWalletSession", "followTrader", "getAcceptance", "getAccountActivity", "getAccountPnl", "getAccountPosition", "getBalances", "getCopyAgents", "getCopyBudget", "getCopySettings", "getCopySummary", "getCoreExit", "getDeployment", "getHypercoreBalance", "getHypercorePortfolio", "getHypercoreSettlementCredits", "getIdentity", "getMakerActivity", "getMakerCapital", "getMakerExposure", "getMakerPerformance", "getMakerPosition", "getMakerQuotes", "getMakerTelemetry", "getMakerVaultFundingTransaction", "getMakerWithdrawal", "getMarket", "getMarketDataConfig", "getMarketDefinitions", "getMarketHistory", "getMarketRecurringRound", "getMarketReferenceCloses", "getMarketScoreTimeline", "getMarketStats", "getOperation", "getOwnMaker", "getPartnerReport", "getPerpMarks", "getProfitLeaderboard", "getQuestion", "getQuestionRecurringRound", "getQuestionScoreTimeline", "getRfq", "getSeries", "getSuggestedCombo", "getTaxonomy", "getTrader", "getTraderPnl", "getUsernameAvailability", "getVaultAgents", "getVolumeLeaderboard", "getWithdrawal", "grantComboCopyAgent", "grantVaultAgent", "likeComment", "listAccountActivity", "listAccountPositions", "listComboCopies", "listCommentReplies", "listComments", "listControlledMakers", "listCopiedFills", "listCopyTrades", "listDiscovery", "listFollows", "listMakerActivity", "listMakerPositions", "listMakerQuoteHistory", "listMarkets", "listOperations", "listQuotes", "listTraderPositions", "listTraderTrades", "reactComment", "recordAcquisition", "refreshPicture", "requestComboCopyAgent", "requestCoreCopyAgent", "revokeComboCopyAgent", "searchCatalog", "setAvatar", "setCopyAllocation", "setCopySettings", "setPublicProfile", "setUsername", "stream", "streamMarkets", "switchOffComboCopyAgent", "switchOffCoreCopyAgent", "unfollowTrader", "unlikeComment", "unreactComment"];
22
22
  readonly maker: readonly ["cancelQuote", "confirmQuote", "createCollateralReduction", "createQuote", "getAccountActivity", "getAccountPosition", "getCollateralReduction", "getDeployment", "getMakerActivity", "getMakerCapital", "getMakerExposure", "getMakerPerformance", "getMakerPosition", "getMakerQuotes", "getMakerTelemetry", "getMakerTelemetryPublication", "getMakerVaultFundingTransaction", "getMakerWithdrawal", "getMarket", "getMarketHistory", "getMarketRecurringRound", "getMarketReferenceCloses", "getOperation", "getQuestion", "getQuestionRecurringRound", "getRfq", "getSeries", "getTaxonomy", "listAccountActivity", "listAccountPositions", "listDiscovery", "listMakerAcceptances", "listMakerActivity", "listMakerPositions", "listMakerQuoteHistory", "listMarkets", "listOperations", "listRfqs", "publishMakerTelemetry", "releaseQuoteLease", "renewQuoteLease", "searchCatalog", "stream", "submitMakerSelfFundedTransaction"];
23
23
  readonly operator: readonly ["live", "ready"];
24
24
  };
@@ -1,13 +1,13 @@
1
1
  // Generated by scripts/generate.mjs; do not edit.
2
- export const sdkVersion = "203.0.0-execution-admission";
3
- export const openapiSha256 = "2304ae546fe97a86cbb1147dccdebe50f5bb44080c26b88503356ac9dd1aa096";
4
- export const realtimeSha256 = "6491fe1d9b5fdcfefcbee71716401effa181e7bcdf1fa4623fbb83dc5b2975cd";
2
+ export const sdkVersion = "205.0.0-device-vault-agents";
3
+ export const openapiSha256 = "93141e0bf50949fc37ebceef7c64555eb50a70f69c71c89c8fdc12780e0dd168";
4
+ export const realtimeSha256 = "1cac740e108e84ad1979f6ccc71089efd840404cb72d1612a86edc02769637e3";
5
5
  export const jsonSchemaSha256 = {
6
6
  "account.schema.json": "5106e2d53abef190990eff113f6692dd27df5848439cf5a80a42c11e89f2bef6",
7
7
  "comments.schema.json": "18f4addcfa4e31c2c833fce8b8beca61d2e2ee5b6318c2ed0b479698ff56b65e",
8
8
  "common.schema.json": "04f51deb3cbea448e59195e26ede3212598d58a7940fe67eb2123fd9161c5edb",
9
9
  "core-exit.schema.json": "c7f617e815225cdcac95c236f8b73fbe288ee5713ff444c3be90eb915fc3a401",
10
- "error.schema.json": "85b2e13d449f137322779086c96d1355d0e70708647eb67b62c9b4070ed6530e",
10
+ "error.schema.json": "56b1e1c4ea26078cb8ce7ab3c554c0415c8c82eec45821180fc0d5e891046c1e",
11
11
  "hypercore.schema.json": "5b89b2bbff7ec8cc1b8717375d12ce9cd5ab6aa5af03c4fdc6cc753ef9583a2c",
12
12
  "identity.schema.json": "94534b768030736f4fd1fad285f1312454ca5fbff0b1eb5fab70416a78923bd0",
13
13
  "maker-access.schema.json": "49698ee0235e42064aae0397db1e0f646bdc10d9dfa10121714ba06dd69fee3b",
@@ -16,7 +16,7 @@ export const jsonSchemaSha256 = {
16
16
  "market-data.schema.json": "85db33fac6a29b0fa87a500bfda947d0ab3913b13f1c26663d4a7c0484c35786",
17
17
  "product-metadata.schema.json": "7c8ffbde878a0aedaed16814fcfd2e80038054b140886cc8736bb7b508042631",
18
18
  "quote.schema.json": "5616260d399d022bde2d0130cc9f8a09f71a3dc877276adf796c7a174d21b59a",
19
- "realtime.schema.json": "6491fe1d9b5fdcfefcbee71716401effa181e7bcdf1fa4623fbb83dc5b2975cd"
19
+ "realtime.schema.json": "1cac740e108e84ad1979f6ccc71089efd840404cb72d1612a86edc02769637e3"
20
20
  };
21
21
  export const operations = {
22
22
  "client": [
@@ -89,9 +89,11 @@ export const operations = {
89
89
  "getTrader",
90
90
  "getTraderPnl",
91
91
  "getUsernameAvailability",
92
+ "getVaultAgents",
92
93
  "getVolumeLeaderboard",
93
94
  "getWithdrawal",
94
95
  "grantComboCopyAgent",
96
+ "grantVaultAgent",
95
97
  "likeComment",
96
98
  "listAccountActivity",
97
99
  "listAccountPositions",
package/dist/stream.d.ts CHANGED
@@ -9,6 +9,8 @@ export type StreamEventOf<T extends StreamEventType> = StreamEvent extends infer
9
9
  } ? T extends K ? E : never : never : never;
10
10
  export type StreamSnapshot = Schemas["Snapshot"];
11
11
  export type StreamEventFrame = Schemas["EventFrame"];
12
+ /** A maker's capital, the same body as `GET /v1/makers/{maker_id}/capital`. */
13
+ export type StreamCapital = Schemas["CapitalFrame"]["data"];
12
14
  /** What a stream follows: the account (optionally with every open RFQ), or one maker. The client manages the cursor. */
13
15
  export type StreamSubscription = Omit<Schemas["AccountSubscription"], "cursor"> | Omit<Schemas["MakerSubscription"], "cursor">;
14
16
  /** A server frame: `channel` names what `data` carries. */
@@ -36,7 +38,11 @@ export type StreamOptions = {
36
38
  /** The WebSocket origin, such as `wss://hip4-ws.totalis.trade`. Defaults to `baseUrl`, else the environment's stream host. */
37
39
  readonly streamBaseUrl?: string;
38
40
  readonly accessToken: AccessToken;
39
- /** `publication_freshness` (1 s heartbeats and publication checkpoints) defaults on for an account, off for a maker. */
41
+ /**
42
+ * `publication_freshness` (1 s heartbeats and publication checkpoints) defaults on. Its
43
+ * heartbeats are what the silence timeout watches: a stream without it has no watchdog
44
+ * once subscribed, because WebSocket pings are invisible to clients.
45
+ */
40
46
  readonly subscription: StreamSubscription;
41
47
  /**
42
48
  * Resume after this cursor, for example one a bot persisted from `event.cursor`:
@@ -52,16 +58,25 @@ export type StreamOptions = {
52
58
  };
53
59
  /** Reconnect after this long without a frame. Default 5000 ms with publication freshness, otherwise off. */
54
60
  readonly silenceTimeoutMs?: number;
61
+ /** Reconnect when a connect has not subscribed after this long, including while `accessToken` resolves. Default 10000 ms. */
62
+ readonly connectTimeoutMs?: number;
55
63
  };
56
64
  type Listeners = {
57
65
  /** A new event, in order and deduplicated, with the frame that carried it. */
58
66
  event: (event: StreamEvent, frame: StreamEventFrame) => void;
59
67
  snapshot: (snapshot: StreamSnapshot) => void;
68
+ /**
69
+ * A maker subscription that set `capital`: its capital on subscribe, on every change and at
70
+ * least every 5 s, so a bot need not read capital before it quotes. Without one for 15 s,
71
+ * read capital over HTTP.
72
+ */
73
+ capital: (capital: StreamCapital) => void;
60
74
  /** Local state built from earlier events is void; replace it from the snapshot that follows. */
61
75
  reset: () => void;
62
76
  status: (status: StreamStatus) => void;
63
77
  /** Every parsed frame, including publication checkpoints, market refreshes and read invalidations. */
64
78
  frame: (frame: StreamFrame) => void;
79
+ /** A failure. The stream reconnects unless it is a StreamClosedError, so a run of these means it cannot get back. */
65
80
  error: (error: unknown) => void;
66
81
  };
67
82
  /**
@@ -107,6 +122,9 @@ export declare class TotalisStream {
107
122
  private nextDelayMs;
108
123
  private timer;
109
124
  private silence;
125
+ private connecting;
126
+ /** Counts connects, so one abandoned while its token resolved never opens a socket. */
127
+ private generation;
110
128
  private reauthorized;
111
129
  /** A REPLAY resume with publication freshness: live waits for the first publication frame, which follows the replayed events. */
112
130
  private replaying;
@@ -138,5 +156,7 @@ export declare class TotalisStream {
138
156
  private onClose;
139
157
  private disconnected;
140
158
  private watchSilence;
159
+ /** Gives up on the current connect or socket, reports why and reconnects. */
160
+ private abandon;
141
161
  }
142
162
  export {};
package/dist/stream.js CHANGED
@@ -63,12 +63,15 @@ export class TotalisStream {
63
63
  nextDelayMs;
64
64
  timer;
65
65
  silence;
66
+ connecting;
67
+ /** Counts connects, so one abandoned while its token resolved never opens a socket. */
68
+ generation = 0;
66
69
  reauthorized = false;
67
70
  /** A REPLAY resume with publication freshness: live waits for the first publication frame, which follows the replayed events. */
68
71
  replaying = false;
69
72
  seen = [];
70
73
  listeners = {
71
- event: new Set(), snapshot: new Set(), reset: new Set(), status: new Set(), frame: new Set(), error: new Set(),
74
+ event: new Set(), snapshot: new Set(), capital: new Set(), reset: new Set(), status: new Set(), frame: new Set(), error: new Set(),
72
75
  };
73
76
  constructor(options) {
74
77
  this.options = options;
@@ -87,6 +90,7 @@ export class TotalisStream {
87
90
  this.setStatus("closed");
88
91
  clearTimeout(this.timer);
89
92
  clearTimeout(this.silence);
93
+ clearTimeout(this.connecting);
90
94
  const socket = this.socket;
91
95
  this.socket = undefined;
92
96
  socket?.close(1000);
@@ -172,17 +176,20 @@ export class TotalisStream {
172
176
  this.emit("event", event, frame);
173
177
  }
174
178
  freshness() {
175
- const { type, publication_freshness = type === "account" } = this.options.subscription;
179
+ const { publication_freshness = true } = this.options.subscription;
176
180
  return publication_freshness;
177
181
  }
178
182
  async connect() {
179
183
  this.replaying = false;
180
184
  this.setStatus("connecting");
181
- const { accessToken, environment = "production", baseUrl, streamBaseUrl } = this.options;
185
+ const generation = ++this.generation;
186
+ const { accessToken, environment = "production", baseUrl, streamBaseUrl, connectTimeoutMs = 10_000 } = this.options;
187
+ clearTimeout(this.connecting);
188
+ this.connecting = setTimeout(() => this.abandon("unsubscribed", `stream not subscribed after ${connectTimeoutMs} ms`), connectTimeoutMs);
182
189
  let socket;
183
190
  try {
184
191
  const token = typeof accessToken === "function" ? await accessToken() : accessToken;
185
- if (this.status === "closed")
192
+ if (this.status === "closed" || generation !== this.generation)
186
193
  return;
187
194
  const open = this.options.webSocket ?? openWebSocket;
188
195
  const url = realtimeUrl(environment, baseUrl, streamBaseUrl);
@@ -191,6 +198,9 @@ export class TotalisStream {
191
198
  : open(url, [realtimeProtocol], { ...this.options.headers, Authorization: `Bearer ${token}` });
192
199
  }
193
200
  catch (error) {
201
+ if (generation !== this.generation)
202
+ return;
203
+ clearTimeout(this.connecting);
194
204
  this.emit("error", error);
195
205
  this.disconnected();
196
206
  return;
@@ -221,7 +231,7 @@ export class TotalisStream {
221
231
  this.watchSilence();
222
232
  }
223
233
  subscribe() {
224
- const { publication_freshness = this.options.subscription.type === "account", ...subscription } = this.options.subscription;
234
+ const { publication_freshness = true, ...subscription } = this.options.subscription;
225
235
  return {
226
236
  method: "subscribe",
227
237
  subscription: { ...subscription, ...(publication_freshness ? { publication_freshness } : {}), ...(this.cursor === undefined ? {} : { cursor: this.cursor }) },
@@ -242,6 +252,7 @@ export class TotalisStream {
242
252
  }
243
253
  break;
244
254
  case "subscriptionResponse": {
255
+ clearTimeout(this.connecting);
245
256
  const ready = frame.data;
246
257
  this.clockOffsetMs = Date.parse(ready.server_time) - Date.now();
247
258
  if (ready.resume === "REPLAY") {
@@ -271,6 +282,9 @@ export class TotalisStream {
271
282
  case "event":
272
283
  this.apply(frame.data, frame);
273
284
  break;
285
+ case "capital":
286
+ this.emit("capital", frame.data);
287
+ break;
274
288
  case "reset":
275
289
  this.reset();
276
290
  break;
@@ -287,6 +301,7 @@ export class TotalisStream {
287
301
  onClose(code, reason) {
288
302
  this.socket = undefined;
289
303
  clearTimeout(this.silence);
304
+ clearTimeout(this.connecting);
290
305
  if (this.status === "closed")
291
306
  return;
292
307
  const retry = errorRegistry[reason]?.retry ?? "BACKOFF";
@@ -321,11 +336,17 @@ export class TotalisStream {
321
336
  clearTimeout(this.silence);
322
337
  if (silenceTimeoutMs === undefined)
323
338
  return;
324
- this.silence = setTimeout(() => {
325
- const socket = this.socket;
326
- this.socket = undefined;
327
- socket?.close(4000, "silent");
328
- this.disconnected();
329
- }, silenceTimeoutMs);
339
+ this.silence = setTimeout(() => this.abandon("silent", `stream silent for ${silenceTimeoutMs} ms`), silenceTimeoutMs);
340
+ }
341
+ /** Gives up on the current connect or socket, reports why and reconnects. */
342
+ abandon(reason, message) {
343
+ this.generation++;
344
+ clearTimeout(this.silence);
345
+ clearTimeout(this.connecting);
346
+ const socket = this.socket;
347
+ this.socket = undefined;
348
+ socket?.close(4000, reason);
349
+ this.emit("error", new Error(message));
350
+ this.disconnected();
330
351
  }
331
352
  }
package/dist/totalis.d.ts CHANGED
@@ -185,6 +185,15 @@ export type TotalisOptions = Omit<ApiClientOptions, "accessToken"> & {
185
185
  readonly accessToken: AccessToken;
186
186
  /** The account's signer (GET /v1/me `wallet`); required for flows that sign. Never stored. */
187
187
  readonly signer?: SignerInput;
188
+ /**
189
+ * A key the account granted as a vault agent (`grantVaultAgent`). When set,
190
+ * it signs the account's TakerAccept, SellBack, CashoutTransfer and Exits to
191
+ * its wallet or HyperCore instead of `signer`, so those need no wallet
192
+ * prompt. `signer` still names the account and signs everything else: USDC
193
+ * authorizations, HyperCore actions, grants and run-off claims. The venue
194
+ * refuses an agent whose grant ends before the signed expiry.
195
+ */
196
+ readonly agent?: SignerInput;
188
197
  /** Stream options; `subscription` adds account subscription fields such as `open_rfqs`. */
189
198
  readonly stream?: Omit<StreamOptions, "subscription" | "accessToken" | "environment" | "baseUrl" | "streamBaseUrl"> & {
190
199
  readonly subscription?: Omit<Extract<StreamSubscription, {
@@ -638,6 +647,27 @@ export declare function createTotalis(options: TotalisOptions): {
638
647
  readonly signal?: AbortSignal;
639
648
  }) => Promise<CoreExit>;
640
649
  directDepositCalls: (amount: Amount) => Promise<readonly WalletCall[]>;
650
+ grantVaultAgent: (request: {
651
+ readonly agent: string;
652
+ readonly validUntil: number | string;
653
+ readonly nonce?: number | string;
654
+ readonly idempotencyKey?: string;
655
+ }) => Promise<{
656
+ readonly operation_id: import("./generated/openapi.js").components["schemas"]["Hash32"];
657
+ }>;
658
+ revokeVaultAgent: (request: {
659
+ readonly agent: string;
660
+ readonly nonce?: number | string;
661
+ readonly idempotencyKey?: string;
662
+ }) => Promise<{
663
+ readonly operation_id: import("./generated/openapi.js").components["schemas"]["Hash32"];
664
+ }>;
665
+ vaultAgents: (limit?: number) => AsyncGenerator<{
666
+ readonly agent: import("./generated/openapi.js").components["schemas"]["Address"];
667
+ readonly valid_until: import("./generated/openapi.js").components["schemas"]["UInt64String"];
668
+ readonly nonce: import("./generated/openapi.js").components["schemas"]["UInt64String"];
669
+ readonly copy_agent: boolean;
670
+ }, void, any>;
641
671
  /** Render an RFQ's live quotes (entry or cash-out) from the stream; `[]` while the stream is down. */
642
672
  watchQuotes: (rfqId: string, listener: (quotes: readonly Quote[], serverNowMs: number) => void) => () => void;
643
673
  /** Issue a personal `ttk_` key; the signer must be the account wallet (embedded, or a wallet-only account's own). */
package/dist/totalis.js CHANGED
@@ -7,7 +7,8 @@ import { spendableCash } from "./money.js";
7
7
  import { ApiError, backoffDelay, envelope, NetworkError, randomBytes32, resendable, retryingFetch, sendOnce, singleFetch, sleep, unwrap, uuidv7 } from "./request.js";
8
8
  import { toTotalisSigner } from "./signer.js";
9
9
  import { TotalisStream } from "./stream.js";
10
- import { address, cashoutTransferTypedData, exitTypedData, receiveWithAuthorizationTypedData, sellBackTypedData, takerAcceptTypedData, payoutNonce, transferWithAuthorizationTypedData, } from "./typed-data.js";
10
+ import { items } from "./pagination.js";
11
+ import { address, agentGrantTypedData, cashoutTransferTypedData, exitTypedData, receiveWithAuthorizationTypedData, sellBackTypedData, takerAcceptTypedData, payoutNonce, transferWithAuthorizationTypedData, } from "./typed-data.js";
11
12
  /**
12
13
  * What an entry's bridge may have moved to its wallet, by its state: nothing
13
14
  * before it is sent, once discarded or refused. Only `LANDED` proves it
@@ -314,7 +315,7 @@ function streamQuotes(stream, read) {
314
315
  * stream; HTTP reads recover after a reconnect or answer a doorbell.
315
316
  */
316
317
  export function createTotalis(options) {
317
- const { environment, signer: signerInput, stream: streamOptions, streamBaseUrl, accessToken, ...clientOptions } = options;
318
+ const { environment, signer: signerInput, agent: agentInput, stream: streamOptions, streamBaseUrl, accessToken, ...clientOptions } = options;
318
319
  const client = audienceClient(environment, { ...clientOptions, accessToken });
319
320
  const keys = createApiKeyClient(environment, { ...clientOptions, accessToken });
320
321
  const stream = new TotalisStream({
@@ -337,6 +338,22 @@ export function createTotalis(options) {
337
338
  };
338
339
  const signer = signerInput === undefined ? undefined : toTotalisSigner(signerInput);
339
340
  const requireSigner = () => signer ?? Promise.reject(new Error("this flow needs a signer"));
341
+ const agent = agentInput === undefined ? undefined : toTotalisSigner(agentInput);
342
+ // The vault reverts a grant whose nonce does not exceed the agent's last, so
343
+ // two grants for one agent in one second (a grant, then its revoke) must not
344
+ // share one, and a default after an explicit nonce must exceed it too. The
345
+ // vault counts per agent, so the mark is per agent.
346
+ const lastGrantNonce = new Map();
347
+ const grantNonce = (agentAddress, explicit) => {
348
+ const last = lastGrantNonce.get(agentAddress) ?? 0n;
349
+ const clock = BigInt(now());
350
+ const nonce = explicit !== undefined ? BigInt(explicit) : clock > last ? clock : last + 1n;
351
+ if (nonce < 1n || nonce > 2n ** 64n - 1n)
352
+ throw new Error(`grant nonce ${nonce} is outside 1..2^64-1`);
353
+ if (nonce > last)
354
+ lastGrantNonce.set(agentAddress, nonce);
355
+ return String(nonce);
356
+ };
340
357
  let deploymentRead;
341
358
  const deployment = () => (deploymentRead ??= client.GET("/v1/deployment").then(unwrap).catch((error) => {
342
359
  deploymentRead = undefined;
@@ -585,7 +602,7 @@ export function createTotalis(options) {
585
602
  const signer = await requireSigner();
586
603
  const account = await signer.address();
587
604
  const chain = await deployment();
588
- return { signer, account, chain, scope: { account, chainId: chain.chain_id, vault: address(chain.vault_address.toLowerCase()) } };
605
+ return { signer, vaultSigner: agent ?? signer, account, chain, scope: { account, chainId: chain.chain_id, vault: address(chain.vault_address.toLowerCase()) } };
589
606
  }
590
607
  /** A stored record signs nothing more, so without a signer the session's wallet (GET /v1/me) stands for the account. */
591
608
  async function checkScope(signed) {
@@ -626,14 +643,14 @@ export function createTotalis(options) {
626
643
  }
627
644
  async function signEntryWith(request, funding) {
628
645
  const { quote, cash } = request;
629
- const { signer, account, chain, scope } = await recordScope();
646
+ const { signer, vaultSigner, account, chain, scope } = await recordScope();
630
647
  if (quote.entry.taker.toLowerCase() !== account)
631
648
  throw new Error("the quote is for another taker");
632
649
  const stake = BigInt(quote.entry.stake);
633
650
  const core = request.core === undefined || request.core === null ? request.core : BigInt(request.core);
634
651
  // Known cash is planned before any prompt, so a plan that fails asks the wallet for nothing.
635
652
  let plan = funding === "plan" && cash !== undefined ? planEntry(stake, core, cash) : undefined;
636
- const signing = signer.signTypedData(takerAcceptTypedData(chain, quote.entry));
653
+ const signing = vaultSigner.signTypedData(takerAcceptTypedData(chain, quote.entry));
637
654
  if (funding === "plan" && cash === undefined) {
638
655
  // The quote signature names no amount, so the wallet signs it while the balances are read; a refusal stops the read and is the call's error.
639
656
  const reading = new AbortController();
@@ -682,12 +699,12 @@ export function createTotalis(options) {
682
699
  /** Sign a cash-out quote as the position's owner without sending it: the same SellBack or CashoutTransfer digest the maker signs. */
683
700
  async function signCashout(request) {
684
701
  const { quote } = request;
685
- const { signer, account, chain, scope } = await recordScope();
702
+ const { vaultSigner, account, chain, scope } = await recordScope();
686
703
  const seller = quote.kind === "SELL_BACK" ? quote.sell_back.owner : quote.transfer.seller;
687
704
  if (seller.toLowerCase() !== account)
688
705
  throw new Error("the quote sells another owner's position");
689
706
  const typedData = quote.kind === "SELL_BACK" ? sellBackTypedData(chain, quote.sell_back) : cashoutTransferTypedData(chain, quote.transfer);
690
- const taker_signature = await signer.signTypedData(typedData);
707
+ const taker_signature = await vaultSigner.signTypedData(typedData);
691
708
  return {
692
709
  kind: "CASHOUT", acceptanceId: request.acceptanceId ?? uuidv7(), rfqId: quote.rfq_id, quoteId: quote.quote_id, ...scope,
693
710
  positionId: termsOf(quote).position_id, command: { taker_signature },
@@ -913,7 +930,7 @@ export function createTotalis(options) {
913
930
  let vault_withdrawal;
914
931
  if (shortfall > 0n) {
915
932
  const exit = { amount: shortfall.toString(), expiry: String(issued + 600), salt: BigInt(randomBytes32()).toString() };
916
- vault_withdrawal = { ...exit, signature: await signer.signTypedData(exitTypedData(chain, { account, to: account, ...exit })) };
933
+ vault_withdrawal = { ...exit, signature: await (agent ?? signer).signTypedData(exitTypedData(chain, { account, to: account, ...exit })) };
917
934
  deadline = issued + 600;
918
935
  }
919
936
  // The venue requires the payout to outlive the vault leg by 300 s; a minute more absorbs clock skew.
@@ -1065,7 +1082,7 @@ export function createTotalis(options) {
1065
1082
  const to = address(route.router_address.toLowerCase());
1066
1083
  // A minute inside the venue's maximum life absorbs clock skew.
1067
1084
  const exit = { amount: BigInt(request.amount).toString(), expiry: String(now() + Math.min(route.maximum_life_seconds - 60, 600)), salt: BigInt(randomBytes32()).toString() };
1068
- const signature = await signer.signTypedData(exitTypedData(chain, { account, to, ...exit }));
1085
+ const signature = await (agent ?? signer).signTypedData(exitTypedData(chain, { account, to, ...exit }));
1069
1086
  const body = envelope({ account, to, ...exit, signature, purpose: request.purpose ?? "ORDER", ...(request.activationFeeAccepted ? { activation_fee_accepted: true } : {}) });
1070
1087
  return { exitId, account, body };
1071
1088
  }
@@ -1190,6 +1207,36 @@ export function createTotalis(options) {
1190
1207
  throw new Error(`core exit ${exitId} ended ${exit.status}, not credited on HyperCore`);
1191
1208
  return exit;
1192
1209
  }
1210
+ /**
1211
+ * Grant `agent`, a key one of the account's devices holds, as a vault agent
1212
+ * until `validUntil` (unix seconds, at most 180 days away): the account's
1213
+ * `signer` signs the AgentGrant and Totalis relays it to the vault, paying
1214
+ * the gas. Pass that key as `agent` to sign accepts, cash-outs and Exits
1215
+ * back to the account without a wallet prompt. The nonce defaults to the
1216
+ * venue's clock in seconds, and rises past this client's last grant, so a
1217
+ * later grant or revoke supersedes an earlier one. The
1218
+ * 202 is admission: follow `operation_id` with `waitForOperation`; the agent
1219
+ * signs once it lands. A resend of the same `idempotencyKey` returns the
1220
+ * same operation.
1221
+ */
1222
+ async function grantVaultAgent(request) {
1223
+ const signer = await requireSigner();
1224
+ const account = address((await signer.address()).toLowerCase());
1225
+ const agentAddress = address(request.agent.toLowerCase());
1226
+ const grant = { account, agent: agentAddress, valid_until: String(request.validUntil), nonce: grantNonce(agentAddress, request.nonce) };
1227
+ const signature = await signer.signTypedData(agentGrantTypedData(await deployment(), grant));
1228
+ const key = request.idempotencyKey ?? uuidv7();
1229
+ return sendOnce(() => client.POST("/v1/me/vault-agents", { params: { header: idempotency(key) },
1230
+ body: { agent: grant.agent, valid_until: grant.valid_until, nonce: grant.nonce, signature } }));
1231
+ }
1232
+ /** The agent keeps signing until the revoke's operation lands; `waitForOperation` before treating it as gone. */
1233
+ function revokeVaultAgent(request) {
1234
+ return grantVaultAgent({ ...request, validUntil: 0 });
1235
+ }
1236
+ /** The account's live vault agents, every page; `copy_agent` marks a Combo copy agent's key. */
1237
+ function vaultAgents(limit = 200) {
1238
+ return items((query) => client.GET("/v1/me/vault-agents", { params: { query: { ...query, limit } } }).then(unwrap), (page) => page.agents);
1239
+ }
1193
1240
  /**
1194
1241
  * The transactions a wallet sends itself to deposit USDC from HyperEVM into
1195
1242
  * its vault balance, paying its own gas: approve the vault for `amount`, then
@@ -1239,6 +1286,9 @@ export function createTotalis(options) {
1239
1286
  sendReturnToCore,
1240
1287
  returnToCore,
1241
1288
  directDepositCalls,
1289
+ grantVaultAgent,
1290
+ revokeVaultAgent,
1291
+ vaultAgents,
1242
1292
  /** Render an RFQ's live quotes (entry or cash-out) from the stream; `[]` while the stream is down. */
1243
1293
  watchQuotes,
1244
1294
  /** Issue a personal `ttk_` key; the signer must be the account wallet (embedded, or a wallet-only account's own). */
@@ -127,15 +127,34 @@ export declare const totalisTypes: {
127
127
  readonly name: "salt";
128
128
  readonly type: "uint256";
129
129
  }];
130
+ readonly AgentGrant: readonly [{
131
+ readonly name: "account";
132
+ readonly type: "address";
133
+ }, {
134
+ readonly name: "agent";
135
+ readonly type: "address";
136
+ }, {
137
+ readonly name: "validUntil";
138
+ readonly type: "uint64";
139
+ }, {
140
+ readonly name: "nonce";
141
+ readonly type: "uint64";
142
+ }];
130
143
  };
131
144
  export type TotalisPrimaryType = Exclude<keyof typeof totalisTypes, "Leg">;
132
- /** Who signs each struct: the maker's signer, the taker's signer, or either side of a cash-out. */
145
+ /**
146
+ * Who signs each struct: the maker's signer, the taker's signer, or either
147
+ * side of a cash-out. A vault agent the account granted may sign the taker's
148
+ * TakerAccept, SellBack and CashoutTransfer, and an Exit back to the account;
149
+ * only the account itself signs an AgentGrant.
150
+ */
133
151
  export declare const signedBy: {
134
152
  readonly Quote: "maker";
135
153
  readonly TakerAccept: "taker";
136
154
  readonly SellBack: "maker_and_taker";
137
155
  readonly CashoutTransfer: "maker_and_taker";
138
156
  readonly Exit: "taker";
157
+ readonly AgentGrant: "taker";
139
158
  };
140
159
  /** The vault deployment a signature binds to: GET /v1/deployment. */
141
160
  export type TotalisDeployment = Pick<Schemas["Deployment"], "chain_id" | "vault_address">;
@@ -201,6 +220,17 @@ export declare function exitTypedData(deployment: TotalisDeployment, exit: {
201
220
  expiry: string;
202
221
  salt: string;
203
222
  }): TotalisTypedData<"Exit">;
223
+ /**
224
+ * The account's grant to a vault agent: a key it holds signs for the account
225
+ * until `valid_until` (unix seconds, at most 180 days away; 0 revokes). The
226
+ * nonce must exceed the agent's last grant. Relay it with POST /v1/me/vault-agents.
227
+ */
228
+ export declare function agentGrantTypedData(deployment: TotalisDeployment, grant: {
229
+ account: Hex;
230
+ agent: Hex;
231
+ valid_until: string;
232
+ nonce: string;
233
+ }): TotalisTypedData<"AgentGrant">;
204
234
  export declare const domainTypes: {
205
235
  readonly EIP712Domain: readonly [{
206
236
  readonly name: "name";
@@ -47,14 +47,26 @@ export const totalisTypes = {
47
47
  { name: "expiry", type: "uint64" },
48
48
  { name: "salt", type: "uint256" },
49
49
  ],
50
+ AgentGrant: [
51
+ { name: "account", type: "address" },
52
+ { name: "agent", type: "address" },
53
+ { name: "validUntil", type: "uint64" },
54
+ { name: "nonce", type: "uint64" },
55
+ ],
50
56
  };
51
- /** Who signs each struct: the maker's signer, the taker's signer, or either side of a cash-out. */
57
+ /**
58
+ * Who signs each struct: the maker's signer, the taker's signer, or either
59
+ * side of a cash-out. A vault agent the account granted may sign the taker's
60
+ * TakerAccept, SellBack and CashoutTransfer, and an Exit back to the account;
61
+ * only the account itself signs an AgentGrant.
62
+ */
52
63
  export const signedBy = {
53
64
  Quote: "maker",
54
65
  TakerAccept: "taker",
55
66
  SellBack: "maker_and_taker",
56
67
  CashoutTransfer: "maker_and_taker",
57
68
  Exit: "taker",
69
+ AgentGrant: "taker",
58
70
  };
59
71
  /** A 20-byte hex address, or a TypeError. */
60
72
  export function address(value) {
@@ -122,6 +134,17 @@ export function exitTypedData(deployment, exit) {
122
134
  message: { account: exit.account, to: exit.to, amount: BigInt(exit.amount), expiry: BigInt(exit.expiry), salt: BigInt(exit.salt) },
123
135
  };
124
136
  }
137
+ /**
138
+ * The account's grant to a vault agent: a key it holds signs for the account
139
+ * until `valid_until` (unix seconds, at most 180 days away; 0 revokes). The
140
+ * nonce must exceed the agent's last grant. Relay it with POST /v1/me/vault-agents.
141
+ */
142
+ export function agentGrantTypedData(deployment, grant) {
143
+ return {
144
+ domain: domain(deployment), types: { AgentGrant: totalisTypes.AgentGrant }, primaryType: "AgentGrant",
145
+ message: { account: address(grant.account), agent: address(grant.agent), validUntil: BigInt(grant.valid_until), nonce: BigInt(grant.nonce) },
146
+ };
147
+ }
125
148
  // ---------------------------------------------------------------------------
126
149
  // EIP-712 hashing, so makers can compute quote_digest and every signer can be
127
150
  // checked against the contract's vectors without a wallet library.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@totalis/hip4-client",
3
- "version": "0.74.0",
3
+ "version": "0.76.0",
4
4
  "description": "Totalis HIP-4 SDK: typed HTTP clients, signer-agnostic typed data, a retrying request layer, pagination, a realtime stream and taker/maker flows",
5
5
  "type": "module",
6
6
  "files": [