Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions src/api/exchange/_methods/activateOutcomeDeployer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import * as v from "@valibot/valibot";

// ============================================================
// API Schemas
// ============================================================

import { Hex, UnsignedInteger } from "../../_schemas.ts";

/**
* Activate or deactivate the signer as an outcome deployer.
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/hip-4-deployer-actions#activation
*/
export const ActivateOutcomeDeployerRequest = /* @__PURE__ */ (() => {
return v.object({
/** Action to perform. */
action: v.object({
/** Type of action. */
type: v.literal("activateOutcomeDeployer"),
/** Deactivate instead of activate. */
isDeactivate: v.boolean(),
}),
/** Nonce (timestamp in ms) used to prevent replay attacks. */
nonce: UnsignedInteger,
/** ECDSA signature components. */
signature: v.object({
/** First 32-byte component. */
r: v.pipe(Hex, v.length(66)),
/** Second 32-byte component. */
s: v.pipe(Hex, v.length(66)),
/** Recovery identifier. */
v: v.picklist([27, 28]),
}),
/** Expiration time of the action. */
expiresAfter: v.optional(UnsignedInteger),
});
})();
export type ActivateOutcomeDeployerRequest = v.InferOutput<typeof ActivateOutcomeDeployerRequest>;

/**
* Successful response without specific data or error response.
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/hip-4-deployer-actions#activation
*/
export type ActivateOutcomeDeployerResponse =
| {
/** Successful status. */
status: "ok";
/** Response details. */
response: {
/** Type of response. */
type: "default";
};
}
| {
/** Error status. */
status: "err";
/** Error message. */
response: string;
};

// ============================================================
// Execution Logic
// ============================================================

import { parse } from "../../../_base.ts";
import { canonicalize } from "../../../signing/mod.ts";
import {
type ExchangeConfig,
type ExcludeErrorResponse,
executeL1Action,
type ExtractRequestOptions,
} from "./_base/mod.ts";

/** Schema for action fields (excludes request-level system fields). */
const ActivateOutcomeDeployerActionSchema = /* @__PURE__ */ (() => {
return v.object(ActivateOutcomeDeployerRequest.entries.action.entries);
})();

/** Action parameters for the {@linkcode activateOutcomeDeployer} function. */
export type ActivateOutcomeDeployerParameters = Omit<
v.InferInput<typeof ActivateOutcomeDeployerActionSchema>,
"type"
>;

/** Request options for the {@linkcode activateOutcomeDeployer} function. */
export type ActivateOutcomeDeployerOptions = ExtractRequestOptions<
v.InferInput<typeof ActivateOutcomeDeployerRequest>
>;

/** Successful variant of {@linkcode ActivateOutcomeDeployerResponse} without errors. */
export type ActivateOutcomeDeployerSuccessResponse = ExcludeErrorResponse<ActivateOutcomeDeployerResponse>;

/**
* Activate or deactivate the signer as an outcome deployer.
*
* Signing: L1 Action.
*
* @param config General configuration for Exchange API requests.
* @param params Parameters specific to the API request.
* @param opts Request execution options.
* @return Successful response without specific data.
*
* @throws {ValidationError} When the request parameters fail validation (before sending).
* @throws {TransportError} When the transport layer throws an error.
* @throws {ApiRequestError} When the API returns an unsuccessful response.
*
* @example
* ```ts
* import { HttpTransport } from "@nktkas/hyperliquid";
* import { activateOutcomeDeployer } from "@nktkas/hyperliquid/api/exchange";
* import { privateKeyToAccount } from "npm:viem/accounts";
*
* const wallet = privateKeyToAccount("0x..."); // viem or ethers
* const transport = new HttpTransport(); // or `WebSocketTransport`
*
* await activateOutcomeDeployer({ transport, wallet }, {
* isDeactivate: false,
* });
* ```
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/hip-4-deployer-actions#activation
*/
export function activateOutcomeDeployer(
config: ExchangeConfig,
params: ActivateOutcomeDeployerParameters,
opts?: ActivateOutcomeDeployerOptions,
): Promise<ActivateOutcomeDeployerSuccessResponse> {
const action = canonicalize(
ActivateOutcomeDeployerActionSchema,
parse(ActivateOutcomeDeployerActionSchema, { type: "activateOutcomeDeployer", ...params }),
);
return executeL1Action(config, action, opts);
}
45 changes: 45 additions & 0 deletions src/api/exchange/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import type { ExchangeConfig, ExchangeSingleWalletConfig } from "./_methods/_bas
// Methods Imports
// ============================================================

import {
activateOutcomeDeployer,
type ActivateOutcomeDeployerOptions,
type ActivateOutcomeDeployerParameters,
type ActivateOutcomeDeployerSuccessResponse,
} from "./_methods/activateOutcomeDeployer.ts";
import {
agentEnableDexAbstraction,
type AgentEnableDexAbstractionOptions,
Expand Down Expand Up @@ -394,6 +400,40 @@ export class ExchangeClient<C extends ExchangeConfig = ExchangeSingleWalletConfi
this.config_ = config;
}

/**
* Activate or deactivate the signer as an outcome deployer.
*
* Signing: L1 Action.
*
* @param params Parameters specific to the API request.
* @param opts Request execution options.
* @return Successful response without specific data.
*
* @throws {ValidationError} When the request parameters fail validation (before sending).
* @throws {TransportError} When the transport layer throws an error.
* @throws {ApiRequestError} When the API returns an unsuccessful response.
*
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
* import { privateKeyToAccount } from "npm:viem/accounts";
*
* const wallet = privateKeyToAccount("0x..."); // viem or ethers
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const client = new hl.ExchangeClient({ transport, wallet });
*
* await client.activateOutcomeDeployer({ isDeactivate: false });
* ```
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/hip-4-deployer-actions#activation
*/
activateOutcomeDeployer(
params: ActivateOutcomeDeployerParameters,
opts?: ActivateOutcomeDeployerOptions,
): Promise<ActivateOutcomeDeployerSuccessResponse> {
return activateOutcomeDeployer(this.config_, params, opts);
}

/**
* Enable HIP-3 DEX abstraction.
*
Expand Down Expand Up @@ -2588,6 +2628,11 @@ export {
type ExchangeSingleWalletConfig,
} from "./_methods/_base/mod.ts";

export type {
ActivateOutcomeDeployerOptions,
ActivateOutcomeDeployerParameters,
ActivateOutcomeDeployerSuccessResponse,
} from "./_methods/activateOutcomeDeployer.ts";
export type {
AgentEnableDexAbstractionOptions,
AgentEnableDexAbstractionSuccessResponse,
Expand Down
1 change: 1 addition & 0 deletions src/api/exchange/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export {
type ExchangeSingleWalletConfig,
} from "./_methods/_base/mod.ts";

export * from "./_methods/activateOutcomeDeployer.ts";
export * from "./_methods/agentEnableDexAbstraction.ts";
export * from "./_methods/agentSendAsset.ts";
export * from "./_methods/agentSetAbstraction.ts";
Expand Down
43 changes: 43 additions & 0 deletions tests/api/exchange/activateOutcomeDeployer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { ApiRequestError } from "@nktkas/hyperliquid";
import {
type ActivateOutcomeDeployerParameters,
ActivateOutcomeDeployerRequest,
} from "@nktkas/hyperliquid/api/exchange";
import * as v from "@valibot/valibot";
import { assertRejects } from "jsr:@std/assert@1";
import { schemaCoverage } from "../_utils/schemaCoverage.ts";
import { valibotToJsonSchema } from "../_utils/valibotToJsonSchema.ts";
import { runTest } from "./_t.ts";

const paramsSchema = valibotToJsonSchema(
v.omit(v.object(ActivateOutcomeDeployerRequest.entries.action.entries), ["type"]),
);

runTest({
name: "activateOutcomeDeployer",
codeTestFn: async (_t, exchClient) => {
const params: ActivateOutcomeDeployerParameters[] = [
// activate
{ isDeactivate: false },
// deactivate
{ isDeactivate: true },
];

await assertRejects(
async () => {
await exchClient.activateOutcomeDeployer(params[0]);
},
ApiRequestError,
"Insufficient stake",
);
await assertRejects(
async () => {
await exchClient.activateOutcomeDeployer(params[1]);
},
ApiRequestError,
"Error deploying outcome: not an outcome deployer",
);

schemaCoverage(paramsSchema, params);
},
});