UNPKG

@nktkas/hyperliquid

Version:

Hyperliquid API SDK for all major JS runtimes, written in TypeScript.

233 lines (232 loc) 7.81 kB
/** * Multi-sig wrapper construction and outer signing. * @module */ /// <amd-module name="file:///home/runner/work/hyperliquid/hyperliquid/src/signing/_multiSig.ts" /> import { type AbstractWallet, type Signature } from "./_abstractWallet.js"; /** A multi-sig wrapper as it appears on the wire. */ interface MultiSigAction { /** Wire-level discriminator. */ type: "multiSig"; /** Chain ID in hex format for [EIP-712](https://eips.ethereum.org/EIPS/eip-712) signing. */ signatureChainId: `0x${string}`; /** Trimmed inner signatures from the authorized signers. */ signatures: readonly Signature[]; /** The inner authorization payload. */ payload: { /** The multi-sig account address (lowercased). */ multiSigUser: `0x${string}`; /** The leader address (lowercased). */ outerSigner: `0x${string}`; /** The action being authorized. */ action: Record<string, unknown> | readonly unknown[]; }; } /** * Signs an L1 action with multi-sig orchestration. * * Collects inner signatures from each signer over `[multiSigUser, outerSigner, action]`, * builds the multi-sig wrapper, and signs the wrapper with the leader (first signer). * * @param args The signers, action, and signing parameters. * @return The wrapper action (modified) and the leader's signature. * * @throws {AbstractWalletError} If signing fails. * * @example * ```ts * import { signMultiSigL1 } from "@nktkas/hyperliquid/signing"; * import { privateKeyToAccount } from "npm:viem/accounts"; * * const signers = [ * privateKeyToAccount("0x..."), * privateKeyToAccount("0x..."), * // ...more signers if needed * ] as const; * * const action = { type: "cancel", cancels: [{ a: 0, o: 12345 }] }; * const nonce = Date.now(); * * const { action: wrapper, signature } = await signMultiSigL1({ * signers, * multiSigUser: "0x...", * signatureChainId: "0x66eee", * action, * nonce, * }); * ``` * * @example * \- Full cycle of signing and sending a multi-sig L1 action to the Hyperliquid API * ```ts * import { canonicalize, signMultiSigL1 } from "@nktkas/hyperliquid/signing"; * import { CancelRequest } from "@nktkas/hyperliquid/api/exchange"; * import { privateKeyToAccount } from "npm:viem/accounts"; * * const signers = [ * privateKeyToAccount("0x..."), * privateKeyToAccount("0x..."), * // ...more signers if needed * ] as const; * * // For correct hashing, keys in the L1 action must be in * // the same order as in the schema definition * // ⌄⌄⌄⌄⌄⌄⌄⌄⌄ * const action = canonicalize(CancelRequest.entries.action, { * type: "cancel", * cancels: [{ a: 0, o: 12345 }], * }); * const nonce = Date.now(); * * const { action: wrapper, signature } = await signMultiSigL1({ * signers, * multiSigUser: "0x...", * signatureChainId: "0x66eee", * action, * nonce, * }); * * // Send the multi-sig wrapper to the Hyperliquid API * const response = await fetch("https://api.hyperliquid.xyz/exchange", { * method: "POST", * headers: { "Content-Type": "application/json" }, * body: JSON.stringify({ action: wrapper, signature, nonce }), * }); * const body = await response.json(); * ``` */ export declare function signMultiSigL1(args: { /** Array of wallets for multi-sig. First wallet is the leader. */ signers: readonly [AbstractWallet, ...AbstractWallet[]]; /** The multi-signature account address. */ multiSigUser: `0x${string}`; /** Chain ID in hex format for [EIP-712](https://eips.ethereum.org/EIPS/eip-712) signing. */ signatureChainId: `0x${string}`; /** The action payload. */ action: Record<string, unknown> | unknown[]; /** The current timestamp in ms. */ nonce: number; /** * Indicates if the action is for the testnet. * * Default: `false` */ isTestnet?: boolean; /** Optional vault address used in the action. */ vaultAddress?: `0x${string}`; /** Optional expiration time of the action in ms since the epoch. */ expiresAfter?: number; }): Promise<{ action: MultiSigAction; signature: Signature; }>; /** * Signs a user-signed action with multi-sig orchestration. * * Collects inner signatures from each signer over the action with multi-sig * fields injected into its [EIP-712](https://eips.ethereum.org/EIPS/eip-712) type, builds the wrapper, and signs the * wrapper with the leader. * * @param args The signers, action, types, and signing parameters. * @return The wrapper action and the leader's signature. * * @throws {AbstractWalletError} If signing fails. * * @example * ```ts * import { signMultiSigUserSigned } from "@nktkas/hyperliquid/signing"; * import { ApproveAgentTypes } from "@nktkas/hyperliquid/api/exchange"; * import { privateKeyToAccount } from "npm:viem/accounts"; * * const signers = [ * privateKeyToAccount("0x..."), * privateKeyToAccount("0x..."), * // ...more signers if needed * ] as const; * * const types = ApproveAgentTypes; // or custom EIP-712 types matching the action * const action = { * type: "approveAgent", * signatureChainId: "0x66eee" as const, * hyperliquidChain: "Mainnet" as const, * agentAddress: "0x...", * agentName: "Agent", * nonce: Date.now(), * }; * * const { action: wrapper, signature } = await signMultiSigUserSigned({ * signers, * multiSigUser: "0x...", * action, * types, * }); * ``` * * @example * \- Full cycle of signing and sending a multi-sig user-signed action to the Hyperliquid API * ```ts * import { signMultiSigUserSigned } from "@nktkas/hyperliquid/signing"; * import { ApproveAgentTypes } from "@nktkas/hyperliquid/api/exchange"; * import { privateKeyToAccount } from "npm:viem/accounts"; * * const signers = [ * privateKeyToAccount("0x..."), * privateKeyToAccount("0x..."), * // ...more signers if needed * ] as const; * * const types = ApproveAgentTypes; // or custom EIP-712 types matching the action * const action = { * type: "approveAgent", * signatureChainId: "0x66eee" as const, * hyperliquidChain: "Mainnet" as const, * agentAddress: "0x...", * agentName: "Agent", * nonce: Date.now(), * }; * * const { action: wrapper, signature } = await signMultiSigUserSigned({ * signers, * multiSigUser: "0x...", * action, * types, * }); * * // Send the multi-sig wrapper to the Hyperliquid API * const response = await fetch("https://api.hyperliquid.xyz/exchange", { * method: "POST", * headers: { "Content-Type": "application/json" }, * body: JSON.stringify({ action: wrapper, signature, nonce: action.nonce }), * }); * const body = await response.json(); * ``` */ export declare function signMultiSigUserSigned(args: { /** Array of wallets for multi-sig. First wallet is the leader. */ signers: readonly [AbstractWallet, ...AbstractWallet[]]; /** The multi-signature account address. */ multiSigUser: `0x${string}`; /** The action payload (must include `signatureChainId`, `hyperliquidChain`, and `nonce` or `time`). */ action: { signatureChainId: `0x${string}`; hyperliquidChain: "Mainnet" | "Testnet"; [key: string]: unknown; } & ({ nonce: number; time?: never; } | { time: number; nonce?: never; }); /** [EIP-712](https://eips.ethereum.org/EIPS/eip-712) type definitions. */ types: Record<string, readonly { name: string; type: string; }[]>; }): Promise<{ action: MultiSigAction; signature: Signature; }>; /** Removes leading zeros from signature `r` and `s` (required for multi-sig signatures). */ export declare function trimSignature(sig: Signature): Signature; export {};