diff --git a/apps/docs/content/docs/clients.md b/apps/docs/content/docs/clients.md index 6efc2d30..a8d24523 100644 --- a/apps/docs/content/docs/clients.md +++ b/apps/docs/content/docs/clients.md @@ -799,12 +799,22 @@ wallet or transport calls. The input remains owned by the caller. Reuse a built resolve coin symbols to asset IDs before building. Time-dependent constraints such as scheduled cancellation are checked when building, so rebuild those actions before reuse. An explicit `buildNoop({ nonce })` retains that nonce rather than allocating a fresh one on reuse. +Reuse is where the speedup comes from: a reused L1 action skips validation, copying, and MessagePack encoding on every +signature. Building a fresh action for each call costs slightly more than the raw method, because the builder also +copies and freezes its input, so keep using raw methods for one-off actions. Signing consumes one nonce and produces an immutable signed request. Submission preserves the operation's response type and does not sign again. Submit promptly: expiration, the protocol timestamp range, and the signer's 100-highest nonce window still apply. Signed ownership and network checks are in-process; serialize for storage only if you intend to use the legacy `submitPrepared` wire-payload API. Reconstructed canonical actions must be rebuilt through a builder. +Each stage accepts a `signal`. Aborting before signing starts consumes no nonce. Aborting while the wallet signs +rejects the call without posting anything; the allocated nonce is skipped, which the exchange tolerates as a gap. A +signed request does not hold on to the signal it was signed with: to cancel it, drop it and let its nonce go stale. +Aborting `submit` (or `execute` after signing) stops waiting for the response, but it cannot recall a request that has +already been sent, so the exchange may still apply it. Resubmitting the same signed request is safe, because the +exchange rejects a nonce it has already seen and the action cannot be applied twice. + The standalone `signAction`, `submitAction`, and `executeAction` functions in `@bloxwap/hyperliquid/actions/execution` accept the same exchange config. Existing client methods and `prepareRequest` / `submitPrepared` continue to work. diff --git a/packages/hyperliquid/.dev/perf/canonical_reuse.ts b/packages/hyperliquid/.dev/perf/canonical_reuse.ts new file mode 100644 index 00000000..81900530 --- /dev/null +++ b/packages/hyperliquid/.dev/perf/canonical_reuse.ts @@ -0,0 +1,120 @@ +/** + * Paired offline comparison of fresh versus reused canonical actions. + * .dev/perf/canonical_reuse.ts [--filter real_viem] [--out /tmp/canonical-reuse.json] + * + * Each group times one complete exchange call per iteration. The `memory` wire returns a fixed response + * without serializing; the `http` wire is the real `HttpTransport` over a mocked `fetch`, so the SDK's + * wire serialization stays in the measurement. Variants: + * - `direct`: the existing raw `order` function (validate → sign → submit). + * - `fresh`: `buildOrder` on every call, then `executeAction`. + * - `reused`: one `buildOrder` reused by `executeAction`. + * - `staged`: one `buildOrder` reused by `signAction` then `submitAction`. + * + * Wallets: `stub` returns a constant signature (isolates SDK overhead), `real_viem` is viem's local + * account and `real_fast` is the SDK's WASM-accelerated local wallet. Cases rotate inside every + * round so machine drift hits each one equally. Numbers are CPU time with mocks, not network latency. + * @module + */ +import { writeFile } from "node:fs/promises"; +import { cpus } from "node:os"; +import { privateKeyToAccount } from "viem/accounts"; +import type { ExchangeConfig } from "../../src/api/exchange/_methods/_base/_config.ts"; +import { buildOrder, order, type OrderParameters } from "../../src/api/exchange/_methods/order.ts"; +import { executeAction, signAction, submitAction } from "../../src/actions/execution.ts"; +import { createFastLocalWallet } from "../../src/signing/mod.ts"; +import { HttpTransport } from "../../src/transport/http/mod.ts"; +import type { AbstractViemLocalAccount } from "../../src/signing/mod.ts"; + +const filterIndex = process.argv.indexOf("--filter"); +const filter = filterIndex >= 0 ? process.argv[filterIndex + 1] : undefined; +const outIndex = process.argv.indexOf("--out"); +const sampleCount = 11; +const privateKey = `0x${"11".repeat(32)}` as const; +const signature = `0x${"11".repeat(64)}1b` as const; +const input = { a: 0, b: true, p: "30000", s: "0.1", r: false, t: { limit: { tif: "Gtc" as const } } }; + +let sink = 0; +const wallets: Record Promise> = { + stub: async () => ({ address: privateKeyToAccount(privateKey).address, signTypedData: async () => signature }), + real_viem: async () => privateKeyToAccount(privateKey), + real_fast: () => createFastLocalWallet(privateKey), +}; + +function config(wallet: AbstractViemLocalAccount, wire: string, count: number): ExchangeConfig { + let nonce = 1_700_000_000_000; + const statuses = Array.from({ length: count }, (_, i) => ({ resting: { oid: i + 1 } })); + const response = { status: "ok", response: { type: "order", data: { statuses } } }; + if (wire === "http") { + const body = JSON.stringify(response); + globalThis.fetch = (async (_url: unknown, init: RequestInit) => { + sink ^= (init.body as string).length; + return new Response(body, { headers: { "Content-Type": "application/json" } }); + }) as typeof fetch; + } + return { + wallet, + nonceManager: () => ++nonce, + transport: + wire === "http" + ? new HttpTransport({ isTestnet: true, timeout: null }) + : { + isTestnet: true, + request: async (): Promise => response as T, + }, + }; +} + +function median(values: number[]): number { + const sorted = [...values].sort((a, b) => a - b); + return sorted[Math.floor(sorted.length / 2)]; +} + +const originalFetch = globalThis.fetch; +const results: { scenario: string; variant: string; medianUs: number; vsDirect: number; roundsUs: number[] }[] = []; +for (const [walletName, createWallet] of Object.entries(wallets)) + for (const wire of ["memory", "http"]) + for (const count of [1, 100]) { + const scenario = `canonical_${walletName}_${wire}_${count}`; + if (filter !== undefined && !scenario.includes(filter)) continue; + const params: OrderParameters = { orders: Array.from({ length: count }, () => input), grouping: "na" }; + const exchange = config(await createWallet(), wire, count); + const reused = buildOrder(params); + const cases: Record Promise> = { + direct: () => order(exchange, params), + fresh: () => executeAction(exchange, buildOrder(params)), + reused: () => executeAction(exchange, reused), + staged: async () => submitAction(exchange, await signAction(exchange, reused)), + }; + const entries = Object.entries(cases); + const rounds = entries.map(() => [] as number[]); + const iterations = Math.max(20, Math.floor((walletName === "stub" ? 4000 : 400) / Math.sqrt(count))); + // Three discarded warmup rounds, then rotate the starting case each round. + for (let round = -3; round < sampleCount; round++) { + for (let index = 0; index < entries.length; index++) { + const selected = (index + round + entries.length * 3) % entries.length; + const start = performance.now(); + for (let i = 0; i < iterations; i++) await entries[selected][1](); + if (round >= 0) rounds[selected].push(((performance.now() - start) * 1000) / iterations); + } + } + const direct = median(rounds[0]); + entries.forEach(([variant], i) => { + const medianUs = median(rounds[i]); + results.push({ scenario, variant, medianUs, vsDirect: medianUs / direct, roundsUs: rounds[i] }); + }); + } +globalThis.fetch = originalFetch; + +console.table( + results.map(({ scenario, variant, medianUs, vsDirect }) => ({ + scenario, + variant, + medianUs: Number(medianUs.toFixed(2)), + vsDirect: Number(vsDirect.toFixed(3)), + })), +); +if (outIndex >= 0) { + const runtime = typeof Bun === "undefined" ? `node ${process.version}` : `bun ${Bun.version}`; + const meta = { runtime, cpu: cpus()[0]?.model, sampleCount, sink }; + await writeFile(process.argv[outIndex + 1], `${JSON.stringify({ meta, results }, null, 2)}\n`); +} diff --git a/packages/hyperliquid/src/actions/_canonical.ts b/packages/hyperliquid/src/actions/_canonical.ts index a58cb728..599f79bf 100644 --- a/packages/hyperliquid/src/actions/_canonical.ts +++ b/packages/hyperliquid/src/actions/_canonical.ts @@ -27,7 +27,9 @@ export function immutableCopy(value: T): T { if (value !== null && typeof value === "object") { const copy: Record = {}; for (const [key, child] of Object.entries(value)) { - Object.defineProperty(copy, key, { value: immutableCopy(child), enumerable: true }); + // Assignment is cheaper than defining each key; only `__proto__` needs an explicit own property. + if (key === "__proto__") Object.defineProperty(copy, key, { value: immutableCopy(child), enumerable: true }); + else copy[key] = immutableCopy(child); } return Object.freeze(copy) as T; } diff --git a/packages/hyperliquid/src/api/exchange/_methods/_base/_shell.ts b/packages/hyperliquid/src/api/exchange/_methods/_base/_shell.ts index b44c356f..3c154a6a 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/_base/_shell.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/_base/_shell.ts @@ -1,11 +1,11 @@ -import { race } from "../../../../transport/_abort.ts"; -import { registerExchangeWireRequest } from "../../../../transport/_wire.ts"; /** * Common execution shell shared by L1 and user-signed Exchange API actions. * @module */ import { getWalletAddress, type Signature } from "../../../../signing/mod.ts"; +import { race } from "../../../../transport/_abort.ts"; +import { registerExchangeWireRequest } from "../../../../transport/_wire.ts"; import type { ExchangeConfig } from "./_config.ts"; import { assertSuccessResponse } from "./errors.ts"; import { globalNonceManager } from "./_nonce.ts"; @@ -142,7 +142,9 @@ const dispatchChains = new Map>(); * @param config Exchange API configuration. * @param build Callback that, given the nonce, returns the action, signature, and any extras. * @param signal Optional {@link AbortSignal} to cancel the request. - * @return The validated API response. + * @param prepareOnly Return the signed request after nonce allocation and signing, without claiming a + * dispatch slot or calling the transport. Used by `signAction`; the nonce is consumed either way. + * @return The validated API response, or the signed request when `prepareOnly` is set. * * @throws {ApiRequestError} If the API returns an error response. */ diff --git a/packages/hyperliquid/src/api/exchange/_methods/activateOutcomeDeployer.ts b/packages/hyperliquid/src/api/exchange/_methods/activateOutcomeDeployer.ts index ccda2ac0..cbae3639 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/activateOutcomeDeployer.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/activateOutcomeDeployer.ts @@ -143,7 +143,16 @@ export function activateOutcomeDeployer( return executeL1Action(config, action, opts); } -/** Validate and own a canonical activateOutcomeDeployer action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode activateOutcomeDeployer} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link ActivateOutcomeDeployerSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildActivateOutcomeDeployer( params: ActivateOutcomeDeployerParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/agentEnableDexAbstraction.ts b/packages/hyperliquid/src/api/exchange/_methods/agentEnableDexAbstraction.ts index 45fc6ab9..17e26d39 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/agentEnableDexAbstraction.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/agentEnableDexAbstraction.ts @@ -118,7 +118,13 @@ export function agentEnableDexAbstraction( return executeL1Action(config, action, opts); } -/** Validate and own a canonical agentEnableDexAbstraction action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode agentEnableDexAbstraction} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @return Immutable action typed with {@link AgentEnableDexAbstractionSuccessResponse}. + */ export function buildAgentEnableDexAbstraction(): CanonicalAction { const action = buildAction(AgentEnableDexAbstractionActionSchema, { type: "agentEnableDexAbstraction" }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/agentSendAsset.ts b/packages/hyperliquid/src/api/exchange/_methods/agentSendAsset.ts index 193eecd2..4cf89213 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/agentSendAsset.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/agentSendAsset.ts @@ -155,7 +155,16 @@ export function agentSendAsset( ); } -/** Validate and own a canonical agentSendAsset action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode agentSendAsset} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link AgentSendAssetSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildAgentSendAsset(params: AgentSendAssetParameters): CanonicalAction { const action = buildAction(AgentSendAssetActionSchema, { type: "agentSendAsset", ...params, nonce: 0 }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/agentSetAbstraction.ts b/packages/hyperliquid/src/api/exchange/_methods/agentSetAbstraction.ts index 211c9d97..b5c8d8e2 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/agentSetAbstraction.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/agentSetAbstraction.ts @@ -133,7 +133,16 @@ export function agentSetAbstraction( return executeL1Action(config, action, opts); } -/** Validate and own a canonical agentSetAbstraction action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode agentSetAbstraction} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link AgentSetAbstractionSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildAgentSetAbstraction( params: AgentSetAbstractionParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/approveAgent.ts b/packages/hyperliquid/src/api/exchange/_methods/approveAgent.ts index 8748035d..ed096c37 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/approveAgent.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/approveAgent.ts @@ -246,7 +246,16 @@ function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null; } -/** Validate and own a canonical approveAgent action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode approveAgent} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link ApproveAgentSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildApproveAgent(params: ApproveAgentParameters): CanonicalAction { // Docs: an agent's `valid_until` expiration can be at most 180 days in the future. Guarded only // when a timestamp is present — a name without `valid_until` (or an unnamed agent) carries no diff --git a/packages/hyperliquid/src/api/exchange/_methods/approveBuilderFee.ts b/packages/hyperliquid/src/api/exchange/_methods/approveBuilderFee.ts index 0789c4e2..b8dae506 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/approveBuilderFee.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/approveBuilderFee.ts @@ -144,7 +144,16 @@ export function approveBuilderFee( return executeUserSignedAction(config, action, ApproveBuilderFeeTypes, opts); } -/** Validate and own a canonical approveBuilderFee action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode approveBuilderFee} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link ApproveBuilderFeeSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildApproveBuilderFee( params: ApproveBuilderFeeParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/authorizeAqav2Role.ts b/packages/hyperliquid/src/api/exchange/_methods/authorizeAqav2Role.ts index e19e5001..98b18136 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/authorizeAqav2Role.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/authorizeAqav2Role.ts @@ -126,7 +126,16 @@ export function authorizeAqav2Role( return executeL1Action(config, action, opts); } -/** Validate and own a canonical authorizeAqav2Role action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode authorizeAqav2Role} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link AuthorizeAqav2RoleSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildAuthorizeAqav2Role( params: AuthorizeAqav2RoleParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/batchModify.ts b/packages/hyperliquid/src/api/exchange/_methods/batchModify.ts index db61c45a..c6acdfbf 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/batchModify.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/batchModify.ts @@ -183,7 +183,16 @@ export function batchModify( return executeL1Action(config, action, opts); } -/** Validate and own a canonical batchModify action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode batchModify} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link BatchModifySuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildBatchModify(params: BatchModifyParameters): CanonicalAction { const action = buildAction(BatchModifyActionSchema, { type: "batchModify", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/borrowLend.ts b/packages/hyperliquid/src/api/exchange/_methods/borrowLend.ts index f9ffb778..be69f0bd 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/borrowLend.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/borrowLend.ts @@ -127,7 +127,16 @@ export function borrowLend( return executeL1Action(config, action, opts); } -/** Validate and own a canonical borrowLend action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode borrowLend} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link BorrowLendSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildBorrowLend(params: BorrowLendParameters): CanonicalAction { const action = buildAction(BorrowLendActionSchema, { type: "borrowLend", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/cDeposit.ts b/packages/hyperliquid/src/api/exchange/_methods/cDeposit.ts index f714ae98..e7160899 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/cDeposit.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/cDeposit.ts @@ -138,7 +138,16 @@ export function cDeposit( return executeUserSignedAction(config, action, CDepositTypes, opts); } -/** Validate and own a canonical cDeposit action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode cDeposit} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link CDepositSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildCDeposit(params: CDepositParameters): CanonicalAction { const action = buildAction(CDepositActionSchema, { type: "cDeposit", ...params }); return canonicalAction(action, { kind: "user", types: CDepositTypes }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/cSignerAction.ts b/packages/hyperliquid/src/api/exchange/_methods/cSignerAction.ts index 55bd014c..4cceea61 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/cSignerAction.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/cSignerAction.ts @@ -148,7 +148,16 @@ export function cSignerAction( return executeL1Action(config, action, opts); } -/** Validate and own a canonical cSignerAction action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode cSignerAction} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link CSignerActionSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildCSignerAction(params: CSignerActionParameters): CanonicalAction { const action = buildAction(CSignerActionActionSchema, { type: "CSignerAction", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/cValidatorAction.ts b/packages/hyperliquid/src/api/exchange/_methods/cValidatorAction.ts index c7917c89..67fdb524 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/cValidatorAction.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/cValidatorAction.ts @@ -191,7 +191,16 @@ export function cValidatorAction( return executeL1Action(config, action, opts); } -/** Validate and own a canonical cValidatorAction action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode cValidatorAction} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link CValidatorActionSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildCValidatorAction( params: CValidatorActionParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/cWithdraw.ts b/packages/hyperliquid/src/api/exchange/_methods/cWithdraw.ts index db659d18..bdcce287 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/cWithdraw.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/cWithdraw.ts @@ -138,7 +138,16 @@ export function cWithdraw( return executeUserSignedAction(config, action, CWithdrawTypes, opts); } -/** Validate and own a canonical cWithdraw action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode cWithdraw} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link CWithdrawSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildCWithdraw(params: CWithdrawParameters): CanonicalAction { const action = buildAction(CWithdrawActionSchema, { type: "cWithdraw", ...params }); return canonicalAction(action, { kind: "user", types: CWithdrawTypes }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/cancel.ts b/packages/hyperliquid/src/api/exchange/_methods/cancel.ts index e75088ba..43450035 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/cancel.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/cancel.ts @@ -145,7 +145,16 @@ export function cancel( return executeL1Action(config, action, opts); } -/** Validate and own a canonical cancel action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode cancel} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link CancelSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildCancel(params: CancelParameters): CanonicalAction { const action = buildAction(CancelActionSchema, { type: "cancel", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/cancelByCloid.ts b/packages/hyperliquid/src/api/exchange/_methods/cancelByCloid.ts index 249e0e82..32d523f2 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/cancelByCloid.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/cancelByCloid.ts @@ -122,7 +122,16 @@ export function cancelByCloid( return executeL1Action(config, action, opts); } -/** Validate and own a canonical cancelByCloid action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode cancelByCloid} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link CancelByCloidSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildCancelByCloid(params: CancelByCloidParameters): CanonicalAction { const action = buildAction(CancelByCloidActionSchema, { type: "cancelByCloid", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/claimRewards.ts b/packages/hyperliquid/src/api/exchange/_methods/claimRewards.ts index 0c226845..92a86d8b 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/claimRewards.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/claimRewards.ts @@ -111,7 +111,13 @@ export function claimRewards(config: ExchangeConfig, opts?: ClaimRewardsOptions) return executeL1Action(config, action, opts); } -/** Validate and own a canonical claimRewards action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode claimRewards} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @return Immutable action typed with {@link ClaimRewardsSuccessResponse}. + */ export function buildClaimRewards(): CanonicalAction { const action = buildAction(ClaimRewardsActionSchema, { type: "claimRewards" }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/convertToMultiSigUser.ts b/packages/hyperliquid/src/api/exchange/_methods/convertToMultiSigUser.ts index 295dd3d5..eac994f1 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/convertToMultiSigUser.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/convertToMultiSigUser.ts @@ -184,7 +184,16 @@ export function convertToMultiSigUser( return executeUserSignedAction(config, action, ConvertToMultiSigUserTypes, opts); } -/** Validate and own a canonical convertToMultiSigUser action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode convertToMultiSigUser} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link ConvertToMultiSigUserSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildConvertToMultiSigUser( params: ConvertToMultiSigUserParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/createSubAccount.ts b/packages/hyperliquid/src/api/exchange/_methods/createSubAccount.ts index 7fca216e..6e19d26a 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/createSubAccount.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/createSubAccount.ts @@ -124,7 +124,16 @@ export function createSubAccount( return executeL1Action(config, action, opts); } -/** Validate and own a canonical createSubAccount action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode createSubAccount} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link CreateSubAccountSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildCreateSubAccount( params: CreateSubAccountParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/createVault.ts b/packages/hyperliquid/src/api/exchange/_methods/createVault.ts index e02ecf78..4c9c33dd 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/createVault.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/createVault.ts @@ -143,7 +143,16 @@ export function createVault( ); } -/** Validate and own a canonical createVault action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode createVault} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link CreateVaultSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildCreateVault(params: CreateVaultParameters): CanonicalAction { const action = buildAction(CreateVaultActionSchema, { type: "createVault", ...params, nonce: 0 }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/evmUserModify.ts b/packages/hyperliquid/src/api/exchange/_methods/evmUserModify.ts index b8594f63..a0463823 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/evmUserModify.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/evmUserModify.ts @@ -123,7 +123,16 @@ export function evmUserModify( return executeL1Action(config, action, opts); } -/** Validate and own a canonical evmUserModify action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode evmUserModify} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link EvmUserModifySuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildEvmUserModify(params: EvmUserModifyParameters): CanonicalAction { const action = buildAction(EvmUserModifyActionSchema, { type: "evmUserModify", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/finalizeEvmContract.ts b/packages/hyperliquid/src/api/exchange/_methods/finalizeEvmContract.ts index 1834a9e6..4c9937bd 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/finalizeEvmContract.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/finalizeEvmContract.ts @@ -141,7 +141,16 @@ export function finalizeEvmContract( return executeL1Action(config, action, opts); } -/** Validate and own a canonical finalizeEvmContract action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode finalizeEvmContract} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link FinalizeEvmContractSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildFinalizeEvmContract( params: FinalizeEvmContractParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/gossipPriorityBid.ts b/packages/hyperliquid/src/api/exchange/_methods/gossipPriorityBid.ts index 7c42e7b9..c6e25905 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/gossipPriorityBid.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/gossipPriorityBid.ts @@ -129,7 +129,16 @@ export function gossipPriorityBid( return executeL1Action(config, action, opts); } -/** Validate and own a canonical gossipPriorityBid action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode gossipPriorityBid} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link GossipPriorityBidSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildGossipPriorityBid( params: GossipPriorityBidParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/hip3LiquidatorTransfer.ts b/packages/hyperliquid/src/api/exchange/_methods/hip3LiquidatorTransfer.ts index 87ad12dc..cdf66777 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/hip3LiquidatorTransfer.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/hip3LiquidatorTransfer.ts @@ -129,7 +129,16 @@ export function hip3LiquidatorTransfer( return executeL1Action(config, action, opts); } -/** Validate and own a canonical hip3LiquidatorTransfer action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode hip3LiquidatorTransfer} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link Hip3LiquidatorTransferSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildHip3LiquidatorTransfer( params: Hip3LiquidatorTransferParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/linkStakingUser.ts b/packages/hyperliquid/src/api/exchange/_methods/linkStakingUser.ts index 095edf3c..2905f737 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/linkStakingUser.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/linkStakingUser.ts @@ -152,7 +152,16 @@ export function linkStakingUser( return executeUserSignedAction(config, action, LinkStakingUserTypes, opts); } -/** Validate and own a canonical linkStakingUser action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode linkStakingUser} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link LinkStakingUserSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildLinkStakingUser( params: LinkStakingUserParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/modify.ts b/packages/hyperliquid/src/api/exchange/_methods/modify.ts index 30246c5e..6f1fd031 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/modify.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/modify.ts @@ -188,7 +188,16 @@ export function modify( return executeL1Action(config, action, opts); } -/** Validate and own a canonical modify action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode modify} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link ModifySuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildModify(params: ModifyParameters): CanonicalAction { const action = buildAction(ModifyActionSchema, { type: "modify", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/noop.ts b/packages/hyperliquid/src/api/exchange/_methods/noop.ts index f87b865d..5041694b 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/noop.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/noop.ts @@ -122,7 +122,16 @@ export function noop(config: ExchangeConfig, params: NoopParameters, opts?: Noop return executeL1Action({ ...config, nonceManager: () => params.nonce }, action, opts); } -/** Validate and own a canonical noop action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode noop} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link NoopSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildNoop(params: NoopParameters): CanonicalAction { const action = buildAction(NoopActionSchema, { type: "noop" }); return canonicalAction(action, { kind: "l1", nonce: parse(UnsignedInteger, params.nonce) }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/order.ts b/packages/hyperliquid/src/api/exchange/_methods/order.ts index 63c60f50..bfb3387f 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/order.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/order.ts @@ -257,7 +257,16 @@ export function order( return executeL1Action(config, action, opts); } -/** Validate and own a canonical order action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode order} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link OrderSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildOrder(params: OrderParameters): CanonicalAction { const action = buildAction(OrderActionSchema, { type: "order", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/outcomeDeploy.ts b/packages/hyperliquid/src/api/exchange/_methods/outcomeDeploy.ts index 978556ef..decf4955 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/outcomeDeploy.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/outcomeDeploy.ts @@ -195,7 +195,16 @@ export function outcomeDeploy( ); } -/** Validate and own a canonical outcomeDeploy action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode outcomeDeploy} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link OutcomeDeploySuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildOutcomeDeploy(params: OutcomeDeployParameters): CanonicalAction { const action = buildAction(OutcomeDeployActionSchema, { type: "outcomeDeploy", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/perpDeploy.ts b/packages/hyperliquid/src/api/exchange/_methods/perpDeploy.ts index 44a341af..ed3f474e 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/perpDeploy.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/perpDeploy.ts @@ -487,7 +487,16 @@ export function perpDeploy( return executeL1Action(config, action, opts); } -/** Validate and own a canonical perpDeploy action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode perpDeploy} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link PerpDeploySuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildPerpDeploy(params: PerpDeployParameters): CanonicalAction { const action = buildAction(PerpDeployActionSchema, { type: "perpDeploy", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/registerReferrer.ts b/packages/hyperliquid/src/api/exchange/_methods/registerReferrer.ts index 3219d75a..636912d2 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/registerReferrer.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/registerReferrer.ts @@ -119,7 +119,16 @@ export function registerReferrer( return executeL1Action(config, action, opts); } -/** Validate and own a canonical registerReferrer action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode registerReferrer} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link RegisterReferrerSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildRegisterReferrer( params: RegisterReferrerParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/reserveRequestWeight.ts b/packages/hyperliquid/src/api/exchange/_methods/reserveRequestWeight.ts index a3b2ce06..b8005d56 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/reserveRequestWeight.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/reserveRequestWeight.ts @@ -125,7 +125,16 @@ export function reserveRequestWeight( return executeL1Action(config, action, opts); } -/** Validate and own a canonical reserveRequestWeight action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode reserveRequestWeight} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link ReserveRequestWeightSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildReserveRequestWeight( params: ReserveRequestWeightParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/scheduleCancel.ts b/packages/hyperliquid/src/api/exchange/_methods/scheduleCancel.ts index 6c2b235d..ba66bf01 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/scheduleCancel.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/scheduleCancel.ts @@ -179,7 +179,16 @@ export function scheduleCancel( return executeL1Action(config, action, opts); } -/** Validate and own a canonical scheduleCancel action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode scheduleCancel} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link ScheduleCancelSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildScheduleCancel(params?: ScheduleCancelParameters): CanonicalAction { const actionInput: Record = { type: "scheduleCancel", ...params }; if (actionInput.time === null) delete actionInput.time; diff --git a/packages/hyperliquid/src/api/exchange/_methods/sendAsset.ts b/packages/hyperliquid/src/api/exchange/_methods/sendAsset.ts index d7b91ed5..6ef87adb 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/sendAsset.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/sendAsset.ts @@ -160,7 +160,16 @@ export function sendAsset( return executeUserSignedAction(config, action, SendAssetTypes, opts); } -/** Validate and own a canonical sendAsset action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode sendAsset} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link SendAssetSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildSendAsset(params: SendAssetParameters): CanonicalAction { const action = buildAction(SendAssetActionSchema, { type: "sendAsset", ...params }); return canonicalAction(action, { kind: "user", types: SendAssetTypes }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/sendToEvmWithData.ts b/packages/hyperliquid/src/api/exchange/_methods/sendToEvmWithData.ts index 4d85705e..21569df2 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/sendToEvmWithData.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/sendToEvmWithData.ts @@ -168,7 +168,16 @@ export function sendToEvmWithData( return executeUserSignedAction(config, action, SendToEvmWithDataTypes, opts); } -/** Validate and own a canonical sendToEvmWithData action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode sendToEvmWithData} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link SendToEvmWithDataSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildSendToEvmWithData( params: SendToEvmWithDataParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/setDisplayName.ts b/packages/hyperliquid/src/api/exchange/_methods/setDisplayName.ts index ff6b7653..05228f0f 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/setDisplayName.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/setDisplayName.ts @@ -122,7 +122,16 @@ export function setDisplayName( return executeL1Action(config, action, opts); } -/** Validate and own a canonical setDisplayName action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode setDisplayName} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link SetDisplayNameSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildSetDisplayName(params: SetDisplayNameParameters): CanonicalAction { const action = buildAction(SetDisplayNameActionSchema, { type: "setDisplayName", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/setReferrer.ts b/packages/hyperliquid/src/api/exchange/_methods/setReferrer.ts index 9ff75f8d..0ded3032 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/setReferrer.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/setReferrer.ts @@ -119,7 +119,16 @@ export function setReferrer( return executeL1Action(config, action, opts); } -/** Validate and own a canonical setReferrer action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode setReferrer} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link SetReferrerSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildSetReferrer(params: SetReferrerParameters): CanonicalAction { const action = buildAction(SetReferrerActionSchema, { type: "setReferrer", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/spotDeploy.ts b/packages/hyperliquid/src/api/exchange/_methods/spotDeploy.ts index a59c9c7d..0f0a252e 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/spotDeploy.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/spotDeploy.ts @@ -356,7 +356,16 @@ export function spotDeploy( return executeL1Action(config, action, opts); } -/** Validate and own a canonical spotDeploy action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode spotDeploy} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link SpotDeploySuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildSpotDeploy(params: SpotDeployParameters): CanonicalAction { const action = buildAction(SpotDeployActionSchema, { type: "spotDeploy", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/spotSend.ts b/packages/hyperliquid/src/api/exchange/_methods/spotSend.ts index 99b88ceb..41a9bcb3 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/spotSend.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/spotSend.ts @@ -144,7 +144,16 @@ export function spotSend( return executeUserSignedAction(config, action, SpotSendTypes, opts); } -/** Validate and own a canonical spotSend action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode spotSend} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link SpotSendSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildSpotSend(params: SpotSendParameters): CanonicalAction { const action = buildAction(SpotSendActionSchema, { type: "spotSend", ...params }); return canonicalAction(action, { kind: "user", types: SpotSendTypes }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/spotUser.ts b/packages/hyperliquid/src/api/exchange/_methods/spotUser.ts index 6b4d0e15..87fc8c60 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/spotUser.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/spotUser.ts @@ -122,7 +122,16 @@ export function spotUser( return executeL1Action(config, action, opts); } -/** Validate and own a canonical spotUser action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode spotUser} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link SpotUserSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildSpotUser(params: SpotUserParameters): CanonicalAction { const action = buildAction(SpotUserActionSchema, { type: "spotUser", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/stakingLinkDisableTradingUser.ts b/packages/hyperliquid/src/api/exchange/_methods/stakingLinkDisableTradingUser.ts index 4d1ff042..f365063e 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/stakingLinkDisableTradingUser.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/stakingLinkDisableTradingUser.ts @@ -153,7 +153,16 @@ export function stakingLinkDisableTradingUser( return executeUserSignedAction(config, action, StakingLinkDisableTradingUserTypes, opts); } -/** Validate and own a canonical stakingLinkDisableTradingUser action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode stakingLinkDisableTradingUser} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link StakingLinkDisableTradingUserSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildStakingLinkDisableTradingUser( params: StakingLinkDisableTradingUserParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/subAccountModify.ts b/packages/hyperliquid/src/api/exchange/_methods/subAccountModify.ts index 5fcf0519..c0d11313 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/subAccountModify.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/subAccountModify.ts @@ -122,7 +122,16 @@ export function subAccountModify( return executeL1Action(config, action, opts); } -/** Validate and own a canonical subAccountModify action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode subAccountModify} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link SubAccountModifySuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildSubAccountModify( params: SubAccountModifyParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/subAccountSpotTransfer.ts b/packages/hyperliquid/src/api/exchange/_methods/subAccountSpotTransfer.ts index da82aaab..6cd418a2 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/subAccountSpotTransfer.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/subAccountSpotTransfer.ts @@ -128,7 +128,16 @@ export function subAccountSpotTransfer( return executeL1Action(config, action, opts); } -/** Validate and own a canonical subAccountSpotTransfer action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode subAccountSpotTransfer} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link SubAccountSpotTransferSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildSubAccountSpotTransfer( params: SubAccountSpotTransferParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/subAccountTransfer.ts b/packages/hyperliquid/src/api/exchange/_methods/subAccountTransfer.ts index 50d5c0a4..35036d20 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/subAccountTransfer.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/subAccountTransfer.ts @@ -125,7 +125,16 @@ export function subAccountTransfer( return executeL1Action(config, action, opts); } -/** Validate and own a canonical subAccountTransfer action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode subAccountTransfer} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link SubAccountTransferSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildSubAccountTransfer( params: SubAccountTransferParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/tokenDelegate.ts b/packages/hyperliquid/src/api/exchange/_methods/tokenDelegate.ts index bf3c855e..dc3edeb1 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/tokenDelegate.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/tokenDelegate.ts @@ -148,7 +148,16 @@ export function tokenDelegate( return executeUserSignedAction(config, action, TokenDelegateTypes, opts); } -/** Validate and own a canonical tokenDelegate action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode tokenDelegate} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link TokenDelegateSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildTokenDelegate(params: TokenDelegateParameters): CanonicalAction { const action = buildAction(TokenDelegateActionSchema, { type: "tokenDelegate", ...params }); return canonicalAction(action, { kind: "user", types: TokenDelegateTypes }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/topUpIsolatedOnlyMargin.ts b/packages/hyperliquid/src/api/exchange/_methods/topUpIsolatedOnlyMargin.ts index f9588eef..9acb550c 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/topUpIsolatedOnlyMargin.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/topUpIsolatedOnlyMargin.ts @@ -131,7 +131,16 @@ export function topUpIsolatedOnlyMargin( return executeL1Action(config, action, opts); } -/** Validate and own a canonical topUpIsolatedOnlyMargin action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode topUpIsolatedOnlyMargin} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link TopUpIsolatedOnlyMarginSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildTopUpIsolatedOnlyMargin( params: TopUpIsolatedOnlyMarginParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/twapCancel.ts b/packages/hyperliquid/src/api/exchange/_methods/twapCancel.ts index e9dfea42..0596918f 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/twapCancel.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/twapCancel.ts @@ -131,7 +131,16 @@ export function twapCancel( return executeL1Action(config, action, opts); } -/** Validate and own a canonical twapCancel action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode twapCancel} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link TwapCancelSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildTwapCancel(params: TwapCancelParameters): CanonicalAction { const action = buildAction(TwapCancelActionSchema, { type: "twapCancel", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/twapOrder.ts b/packages/hyperliquid/src/api/exchange/_methods/twapOrder.ts index bdd4e915..2eb61208 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/twapOrder.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/twapOrder.ts @@ -170,7 +170,16 @@ export function twapOrder( return executeL1Action(config, action, opts); } -/** Validate and own a canonical twapOrder action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode twapOrder} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link TwapOrderSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildTwapOrder(params: TwapOrderParameters): CanonicalAction { const action = buildAction(TwapOrderActionSchema, { type: "twapOrder", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/updateIsolatedMargin.ts b/packages/hyperliquid/src/api/exchange/_methods/updateIsolatedMargin.ts index 8acf6d45..a7fef3c9 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/updateIsolatedMargin.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/updateIsolatedMargin.ts @@ -131,7 +131,16 @@ export function updateIsolatedMargin( return executeL1Action(config, action, opts); } -/** Validate and own a canonical updateIsolatedMargin action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode updateIsolatedMargin} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link UpdateIsolatedMarginSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildUpdateIsolatedMargin( params: UpdateIsolatedMarginParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/updateLeverage.ts b/packages/hyperliquid/src/api/exchange/_methods/updateLeverage.ts index 9331de5c..7a1ef11f 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/updateLeverage.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/updateLeverage.ts @@ -131,7 +131,16 @@ export function updateLeverage( return executeL1Action(config, action, opts); } -/** Validate and own a canonical updateLeverage action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode updateLeverage} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link UpdateLeverageSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildUpdateLeverage(params: UpdateLeverageParameters): CanonicalAction { const action = buildAction(UpdateLeverageActionSchema, { type: "updateLeverage", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/usdClassTransfer.ts b/packages/hyperliquid/src/api/exchange/_methods/usdClassTransfer.ts index 98b26445..7410a0ba 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/usdClassTransfer.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/usdClassTransfer.ts @@ -152,7 +152,16 @@ export function usdClassTransfer( return executeUserSignedAction(config, action, UsdClassTransferTypes, opts); } -/** Validate and own a canonical usdClassTransfer action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode usdClassTransfer} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link UsdClassTransferSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildUsdClassTransfer( params: UsdClassTransferParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/usdSend.ts b/packages/hyperliquid/src/api/exchange/_methods/usdSend.ts index e7665c5c..db30cdd2 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/usdSend.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/usdSend.ts @@ -140,7 +140,16 @@ export function usdSend( return executeUserSignedAction(config, action, UsdSendTypes, opts); } -/** Validate and own a canonical usdSend action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode usdSend} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link UsdSendSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildUsdSend(params: UsdSendParameters): CanonicalAction { const action = buildAction(UsdSendActionSchema, { type: "usdSend", ...params }); return canonicalAction(action, { kind: "user", types: UsdSendTypes }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/userDexAbstraction.ts b/packages/hyperliquid/src/api/exchange/_methods/userDexAbstraction.ts index 72d1f155..18bfd3a3 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/userDexAbstraction.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/userDexAbstraction.ts @@ -146,7 +146,16 @@ export function userDexAbstraction( return executeUserSignedAction(config, action, UserDexAbstractionTypes, opts); } -/** Validate and own a canonical userDexAbstraction action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode userDexAbstraction} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link UserDexAbstractionSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildUserDexAbstraction( params: UserDexAbstractionParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/userOutcome.ts b/packages/hyperliquid/src/api/exchange/_methods/userOutcome.ts index ecb1539f..57d57f79 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/userOutcome.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/userOutcome.ts @@ -184,7 +184,16 @@ export function userOutcome( return executeL1Action(config, action, opts); } -/** Validate and own a canonical userOutcome action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode userOutcome} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link UserOutcomeSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildUserOutcome(params: UserOutcomeParameters): CanonicalAction { const action = buildAction(UserOutcomeActionSchema, { type: "userOutcome", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/userPortfolioMargin.ts b/packages/hyperliquid/src/api/exchange/_methods/userPortfolioMargin.ts index 3213d0b6..2205f128 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/userPortfolioMargin.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/userPortfolioMargin.ts @@ -144,7 +144,16 @@ export function userPortfolioMargin( return executeUserSignedAction(config, action, UserPortfolioMarginTypes, opts); } -/** Validate and own a canonical userPortfolioMargin action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode userPortfolioMargin} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link UserPortfolioMarginSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildUserPortfolioMargin( params: UserPortfolioMarginParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/userSetAbstraction.ts b/packages/hyperliquid/src/api/exchange/_methods/userSetAbstraction.ts index 69281a40..0c1c648e 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/userSetAbstraction.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/userSetAbstraction.ts @@ -159,7 +159,16 @@ export function userSetAbstraction( return executeUserSignedAction(config, action, UserSetAbstractionTypes, { ...opts, toMultiSigPayloadAction }); } -/** Validate and own a canonical userSetAbstraction action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode userSetAbstraction} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link UserSetAbstractionSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildUserSetAbstraction( params: UserSetAbstractionParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/validatorL1Stream.ts b/packages/hyperliquid/src/api/exchange/_methods/validatorL1Stream.ts index 0c56d9ac..a82ea7e1 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/validatorL1Stream.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/validatorL1Stream.ts @@ -123,7 +123,16 @@ export function validatorL1Stream( return executeL1Action(config, action, opts); } -/** Validate and own a canonical validatorL1Stream action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode validatorL1Stream} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link ValidatorL1StreamSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildValidatorL1Stream( params: ValidatorL1StreamParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/vaultDistribute.ts b/packages/hyperliquid/src/api/exchange/_methods/vaultDistribute.ts index 60292828..874706b0 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/vaultDistribute.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/vaultDistribute.ts @@ -125,7 +125,16 @@ export function vaultDistribute( return executeL1Action(config, action, opts); } -/** Validate and own a canonical vaultDistribute action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode vaultDistribute} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link VaultDistributeSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildVaultDistribute( params: VaultDistributeParameters, ): CanonicalAction { diff --git a/packages/hyperliquid/src/api/exchange/_methods/vaultModify.ts b/packages/hyperliquid/src/api/exchange/_methods/vaultModify.ts index 39e03a97..16b1ea0e 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/vaultModify.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/vaultModify.ts @@ -125,7 +125,16 @@ export function vaultModify( return executeL1Action(config, action, opts); } -/** Validate and own a canonical vaultModify action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode vaultModify} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link VaultModifySuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildVaultModify(params: VaultModifyParameters): CanonicalAction { const action = buildAction(VaultModifyActionSchema, { type: "vaultModify", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/vaultTransfer.ts b/packages/hyperliquid/src/api/exchange/_methods/vaultTransfer.ts index 14302a52..de78d92a 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/vaultTransfer.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/vaultTransfer.ts @@ -129,7 +129,16 @@ export function vaultTransfer( return executeL1Action(config, action, opts); } -/** Validate and own a canonical vaultTransfer action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode vaultTransfer} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link VaultTransferSuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildVaultTransfer(params: VaultTransferParameters): CanonicalAction { const action = buildAction(VaultTransferActionSchema, { type: "vaultTransfer", ...params }); return canonicalAction(action, { kind: "l1" }); diff --git a/packages/hyperliquid/src/api/exchange/_methods/withdraw3.ts b/packages/hyperliquid/src/api/exchange/_methods/withdraw3.ts index ab48e26b..385db06a 100644 --- a/packages/hyperliquid/src/api/exchange/_methods/withdraw3.ts +++ b/packages/hyperliquid/src/api/exchange/_methods/withdraw3.ts @@ -142,7 +142,16 @@ export function withdraw3( return executeUserSignedAction(config, action, Withdraw3Types, opts); } -/** Validate and own a canonical withdraw3 action without allocating a nonce or calling a wallet/transport. */ +/** + * Build a canonical {@linkcode withdraw3} action: validate, normalize, fill defaults, and copy and freeze + * the result. Allocates no nonce and makes no wallet or transport call, so the action can be signed + * and submitted later, or reused while its fields stay valid. + * + * @param params Parameters specific to the API request. + * @return Immutable action typed with {@link Withdraw3SuccessResponse}. + * + * @throws {ValidationError} When the request parameters fail validation. + */ export function buildWithdraw3(params: Withdraw3Parameters): CanonicalAction { const action = buildAction(Withdraw3ActionSchema, { type: "withdraw3", ...params }); return canonicalAction(action, { kind: "user", types: Withdraw3Types }); diff --git a/packages/hyperliquid/src/api/exchange/client.ts b/packages/hyperliquid/src/api/exchange/client.ts index 078aa727..a9a6b432 100644 --- a/packages/hyperliquid/src/api/exchange/client.ts +++ b/packages/hyperliquid/src/api/exchange/client.ts @@ -1,11 +1,3 @@ -import { - executeAction, - signAction, - submitAction, - type CanonicalAction, - type SignedAction, - type ActionOptions, -} from "../../actions/execution.ts"; /** * Client for the Hyperliquid Exchange API endpoint. * @module @@ -18,6 +10,14 @@ import { type OutcomeDeployOptions, } from "./_methods/outcomeDeploy.ts"; import { HyperliquidError } from "../../_base.ts"; +import { + executeAction, + signAction, + submitAction, + type CanonicalAction, + type SignedAction, + type ActionOptions, +} from "../../actions/execution.ts"; import { preloadWasmKeccak } from "../../signing/mod.ts"; import { SymbolConverter } from "../../utils/mod.ts"; import type { ExchangeConfig, ExchangeSingleWalletConfig } from "./_methods/_base/mod.ts"; diff --git a/packages/hyperliquid/tests/api/exchange/_actions.test.ts b/packages/hyperliquid/tests/api/exchange/_actions.test.ts index cf5a924f..5ff96269 100644 --- a/packages/hyperliquid/tests/api/exchange/_actions.test.ts +++ b/packages/hyperliquid/tests/api/exchange/_actions.test.ts @@ -10,6 +10,7 @@ import { buildCreateVault, createVault } from "@bloxwap/hyperliquid/api/exchange import { buildAgentSendAsset, agentSendAsset } from "@bloxwap/hyperliquid/api/exchange/agentSendAsset"; import { buildUserSetAbstraction, userSetAbstraction } from "@bloxwap/hyperliquid/api/exchange/userSetAbstraction"; import { executeAction, signAction, submitAction, type CanonicalAction } from "@bloxwap/hyperliquid/actions/execution"; +import { immutableCopy } from "../../../src/actions/_canonical.ts"; const wallet = privateKeyToAccount(`0x${"11".repeat(32)}`); const secondWallet = privateKeyToAccount(`0x${"22".repeat(32)}`); @@ -46,6 +47,16 @@ describe("canonical actions", () => { expect(() => buildOrder({ orders: [] })).toThrow(); }); + test("immutable copies keep key order and own `__proto__` keys without changing the prototype", () => { + const source = JSON.parse('{"z":1,"__proto__":{"polluted":true},"a":[{"y":2,"b":3}]}'); + const copy = immutableCopy(source); + expect(Object.getPrototypeOf(copy)).toBe(Object.prototype); + expect(Object.keys(copy)).toEqual(["z", "__proto__", "a"]); + expect(JSON.stringify(copy)).toBe(JSON.stringify(source)); + expect(Object.isFrozen(copy.a[0])).toBe(true); + expect(({} as { polluted?: boolean }).polluted).toBeUndefined(); + }); + test("sign consumes one nonce without posting; submit retains the inferred response", async () => { const { config, calls } = harness(); let issued = 0; @@ -131,6 +142,59 @@ describe("canonical actions", () => { }); } + test("cancellation: before signing frees the nonce, during signing burns it, submit forwards the signal", async () => { + const { config, calls } = harness(); + let issued = 0; + config.nonceManager = () => 1_700_000_000_000 + issued++; + const action = buildOrder(input); + + const aborted = AbortSignal.abort(new Error("early")); + await expect(signAction(config, action, { signal: aborted })).rejects.toThrow("early"); + await expect(executeAction(config, action, { signal: aborted })).rejects.toThrow("early"); + expect(issued).toBe(0); + + const controller = new AbortController(); + let release!: () => void; + const pendingSign = new Promise((resolve) => { + release = resolve; + }); + const slowConfig: ExchangeConfig = { + ...config, + wallet: { + address: wallet.address, + signTypedData: async (args) => { + await pendingSign; + return wallet.signTypedData(args); + }, + }, + }; + const executing = executeAction(slowConfig, action, { signal: controller.signal }); + await Promise.resolve(); + await new Promise((resolve) => setTimeout(resolve, 0)); + controller.abort(new Error("late")); + await expect(executing).rejects.toThrow("late"); + release(); + expect(issued).toBe(1); + expect(calls).toHaveLength(0); + + const signals: (AbortSignal | undefined)[] = []; + const signed = await signAction(config, action); + const submitSignal = new AbortController().signal; + const forwarding: ExchangeConfig = { + ...config, + transport: { + isTestnet: true, + request: (endpoint, body, signal) => { + signals.push(signal); + return config.transport.request(endpoint, body, signal); + }, + }, + }; + await submitAction(forwarding, signed, { signal: submitSignal }); + expect(signals).toEqual([submitSignal]); + expect(issued).toBe(2); + }); + test("unknown/reconstructed actions and cross-network signed submissions are rejected", async () => { const { config, calls } = harness(); await expect(signAction(config, { payload: {} })).rejects.toThrow("SDK builder");