UNPKG

@nktkas/hyperliquid

Version:

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

663 lines (662 loc) 23 kB
/** Action sorter and formatter for correct signature generation. */ export const actionSorter = { approveAgent: (action) => { return { type: action.type, signatureChainId: action.signatureChainId, hyperliquidChain: action.hyperliquidChain, agentAddress: action.agentAddress.toLowerCase(), agentName: action.agentName, nonce: action.nonce, }; }, approveBuilderFee: (action) => { return { type: action.type, signatureChainId: action.signatureChainId, hyperliquidChain: action.hyperliquidChain, maxFeeRate: action.maxFeeRate, builder: action.builder.toLowerCase(), nonce: action.nonce, }; }, batchModify: (action) => { return { type: action.type, modifies: action.modifies.map((modify) => { const sortedModify = { oid: modify.oid, order: { a: modify.order.a, b: modify.order.b, p: formatDecimal(modify.order.p), s: formatDecimal(modify.order.s), r: modify.order.r, t: "limit" in modify.order.t ? { limit: { tif: modify.order.t.limit.tif, }, } : { trigger: { isMarket: modify.order.t.trigger.isMarket, triggerPx: formatDecimal(modify.order.t.trigger.triggerPx), tpsl: modify.order.t.trigger.tpsl, }, }, c: modify.order.c, }, }; if (sortedModify.order.c === undefined) delete sortedModify.order.c; return sortedModify; }), }; }, cancel: (action) => { return { type: action.type, cancels: action.cancels.map((cancel) => ({ a: cancel.a, o: cancel.o, })), }; }, cancelByCloid: (action) => { return { type: action.type, cancels: action.cancels.map((cancel) => ({ asset: cancel.asset, cloid: cancel.cloid, })), }; }, cDeposit: (action) => { return { type: action.type, signatureChainId: action.signatureChainId, hyperliquidChain: action.hyperliquidChain, wei: action.wei, nonce: action.nonce, }; }, claimRewards: (action) => { return { type: action.type, }; }, convertToMultiSigUser: (action) => { return { type: action.type, signatureChainId: action.signatureChainId, hyperliquidChain: action.hyperliquidChain, signers: typeof action.signers === "string" ? action.signers : JSON.stringify(action.signers === null ? action.signers : { authorizedUsers: action.signers.authorizedUsers, threshold: action.signers.threshold, }), nonce: action.nonce, }; }, createSubAccount: (action) => { return { type: action.type, name: action.name, }; }, createVault: (action) => { return { type: action.type, name: action.name, description: action.description, initialUsd: action.initialUsd, nonce: action.nonce, }; }, CSignerAction: (action) => { if ("jailSelf" in action) { return { type: action.type, jailSelf: action.jailSelf, }; } else { return { type: action.type, unjailSelf: action.unjailSelf, }; } }, CValidatorAction: (action) => { if ("changeProfile" in action) { return { type: action.type, changeProfile: { node_ip: action.changeProfile.node_ip, name: action.changeProfile.name, description: action.changeProfile.description, unjailed: action.changeProfile.unjailed, disable_delegations: action.changeProfile.disable_delegations, commission_bps: action.changeProfile.commission_bps, signer: action.changeProfile.signer?.toLowerCase(), }, }; } else if ("register" in action) { return { type: action.type, register: { profile: { node_ip: { Ip: action.register.profile.node_ip.Ip, }, name: action.register.profile.name, description: action.register.profile.description, delegations_disabled: action.register.profile.delegations_disabled, commission_bps: action.register.profile.commission_bps, signer: action.register.profile.signer.toLowerCase(), }, unjailed: action.register.unjailed, initial_wei: action.register.initial_wei, }, }; } else { return { type: action.type, unregister: action.unregister, }; } }, cWithdraw: (action) => { return { type: action.type, signatureChainId: action.signatureChainId, hyperliquidChain: action.hyperliquidChain, wei: action.wei, nonce: action.nonce, }; }, evmUserModify: (action) => { return { type: action.type, usingBigBlocks: action.usingBigBlocks, }; }, modify: (action) => { const sortedAction = { type: action.type, oid: action.oid, order: { a: action.order.a, b: action.order.b, p: formatDecimal(action.order.p), s: formatDecimal(action.order.s), r: action.order.r, t: "limit" in action.order.t ? { limit: { tif: action.order.t.limit.tif, }, } : { trigger: { isMarket: action.order.t.trigger.isMarket, triggerPx: formatDecimal(action.order.t.trigger.triggerPx), tpsl: action.order.t.trigger.tpsl, }, }, c: action.order.c, }, }; if (sortedAction.order.c === undefined) delete sortedAction.order.c; return sortedAction; }, multiSig: (action) => { return { type: action.type, signatureChainId: action.signatureChainId, signatures: action.signatures.map((signature) => ({ r: signature.r.replace(/^0x0+/, "0x").toLowerCase(), s: signature.s.replace(/^0x0+/, "0x").toLowerCase(), v: signature.v, })), payload: { multiSigUser: action.payload.multiSigUser.toLowerCase(), outerSigner: action.payload.outerSigner.toLowerCase(), action: actionSorter[action.payload.action.type]( // @ts-ignore - TypeScript cannot infer the type correctly action.payload.action), }, }; }, order: (action) => { const sortedAction = { type: action.type, orders: action.orders.map((order) => { const sortedOrder = { a: order.a, b: order.b, p: formatDecimal(order.p), s: formatDecimal(order.s), r: order.r, t: "limit" in order.t ? { limit: { tif: order.t.limit.tif, }, } : { trigger: { isMarket: order.t.trigger.isMarket, triggerPx: formatDecimal(order.t.trigger.triggerPx), tpsl: order.t.trigger.tpsl, }, }, c: order.c, }; if (order.c === undefined) delete sortedOrder.c; return sortedOrder; }), grouping: action.grouping, builder: action.builder ? { b: action.builder.b.toLowerCase(), f: action.builder.f, } : action.builder, }; if (sortedAction.builder === undefined) delete sortedAction.builder; return sortedAction; }, perpDeploy: (action) => { if ("registerAsset" in action) { return { type: action.type, registerAsset: { maxGas: action.registerAsset.maxGas, assetRequest: { coin: action.registerAsset.assetRequest.coin, szDecimals: action.registerAsset.assetRequest.szDecimals, oraclePx: action.registerAsset.assetRequest.oraclePx, marginTableId: action.registerAsset.assetRequest.marginTableId, onlyIsolated: action.registerAsset.assetRequest.onlyIsolated, }, dex: action.registerAsset.dex, schema: action.registerAsset.schema ? { fullName: action.registerAsset.schema.fullName, collateralToken: action.registerAsset.schema.collateralToken, oracleUpdater: action.registerAsset.schema.oracleUpdater?.toLowerCase(), } : action.registerAsset.schema, }, }; } else { return { type: action.type, setOracle: { dex: action.setOracle.dex, oraclePxs: action.setOracle.oraclePxs.map((el) => [...el]), markPxs: action.setOracle.markPxs.map((el) => el.map((el2) => [...el2])), }, }; } }, registerReferrer: (action) => { return { type: action.type, code: action.code, }; }, reserveRequestWeight: (action) => { return { type: action.type, weight: action.weight, }; }, scheduleCancel: (action) => { const sortedAction = { type: action.type, time: action.time, }; if (sortedAction.time === undefined) delete sortedAction.time; return sortedAction; }, setDisplayName: (action) => { return { type: action.type, displayName: action.displayName, }; }, setReferrer: (action) => { return { type: action.type, code: action.code, }; }, spotDeploy: (action) => { if ("genesis" in action) { const sortedAction = { type: action.type, genesis: { token: action.genesis.token, maxSupply: action.genesis.maxSupply, noHyperliquidity: action.genesis.noHyperliquidity, }, }; if (sortedAction.genesis.noHyperliquidity === undefined) delete sortedAction.genesis.noHyperliquidity; return sortedAction; } else if ("registerHyperliquidity" in action) { const sortedAction = { type: action.type, registerHyperliquidity: { spot: action.registerHyperliquidity.spot, startPx: action.registerHyperliquidity.startPx, orderSz: action.registerHyperliquidity.orderSz, nOrders: action.registerHyperliquidity.nOrders, nSeededLevels: action.registerHyperliquidity.nSeededLevels, }, }; if (sortedAction.registerHyperliquidity.nSeededLevels === undefined) { delete sortedAction.registerHyperliquidity.nSeededLevels; } return sortedAction; } else if ("registerSpot" in action) { return { type: action.type, registerSpot: { tokens: [...action.registerSpot.tokens], }, }; } else if ("registerToken2" in action) { const sortedAction = { type: action.type, registerToken2: { spec: { name: action.registerToken2.spec.name, szDecimals: action.registerToken2.spec.szDecimals, weiDecimals: action.registerToken2.spec.weiDecimals, }, maxGas: action.registerToken2.maxGas, fullName: action.registerToken2.fullName, }, }; if (sortedAction.registerToken2.fullName === undefined) delete sortedAction.registerToken2.fullName; return sortedAction; } else if ("setDeployerTradingFeeShare" in action) { return { type: action.type, setDeployerTradingFeeShare: { token: action.setDeployerTradingFeeShare.token, share: action.setDeployerTradingFeeShare.share, }, }; } else { const sortedAction = { type: action.type, userGenesis: { token: action.userGenesis.token, userAndWei: action.userGenesis.userAndWei.map((el) => [...el]), existingTokenAndWei: action.userGenesis.existingTokenAndWei.map((el) => [...el]), blacklistUsers: action.userGenesis.blacklistUsers?.map((el) => [...el]), }, }; if (sortedAction.userGenesis.blacklistUsers === undefined) delete sortedAction.userGenesis.blacklistUsers; return sortedAction; } }, spotSend: (action) => { return { type: action.type, signatureChainId: action.signatureChainId, hyperliquidChain: action.hyperliquidChain, destination: action.destination.toLowerCase(), token: action.token, amount: action.amount, time: action.time, }; }, spotUser: (action) => { return { type: action.type, toggleSpotDusting: { optOut: action.toggleSpotDusting.optOut, }, }; }, subAccountModify: (action) => { return { type: action.type, subAccountUser: action.subAccountUser.toLowerCase(), name: action.name, }; }, subAccountSpotTransfer: (action) => { return { type: action.type, subAccountUser: action.subAccountUser.toLowerCase(), isDeposit: action.isDeposit, token: action.token, amount: action.amount, }; }, subAccountTransfer: (action) => { return { type: action.type, subAccountUser: action.subAccountUser.toLowerCase(), isDeposit: action.isDeposit, usd: action.usd, }; }, tokenDelegate: (action) => { return { type: action.type, signatureChainId: action.signatureChainId, hyperliquidChain: action.hyperliquidChain, validator: action.validator.toLowerCase(), wei: action.wei, isUndelegate: action.isUndelegate, nonce: action.nonce, }; }, twapCancel: (action) => { return { type: action.type, a: action.a, t: action.t, }; }, twapOrder: (action) => { return { type: action.type, twap: { a: action.twap.a, b: action.twap.b, s: formatDecimal(action.twap.s), r: action.twap.r, m: action.twap.m, t: action.twap.t, }, }; }, updateIsolatedMargin: (action) => { return { type: action.type, asset: action.asset, isBuy: action.isBuy, ntli: action.ntli, }; }, updateLeverage: (action) => { return { type: action.type, asset: action.asset, isCross: action.isCross, leverage: action.leverage, }; }, usdClassTransfer: (action) => { return { type: action.type, signatureChainId: action.signatureChainId, hyperliquidChain: action.hyperliquidChain, amount: action.amount, toPerp: action.toPerp, nonce: action.nonce, }; }, usdSend: (action) => { return { type: action.type, signatureChainId: action.signatureChainId, hyperliquidChain: action.hyperliquidChain, destination: action.destination.toLowerCase(), amount: action.amount, time: action.time, }; }, vaultDistribute: (action) => { return { type: action.type, vaultAddress: action.vaultAddress, usd: action.usd, }; }, vaultModify: (action) => { return { type: action.type, vaultAddress: action.vaultAddress, allowDeposits: action.allowDeposits, alwaysCloseOnWithdraw: action.alwaysCloseOnWithdraw, }; }, vaultTransfer: (action) => { return { type: action.type, vaultAddress: action.vaultAddress, isDeposit: action.isDeposit, usd: action.usd, }; }, withdraw3: (action) => { return { type: action.type, signatureChainId: action.signatureChainId, hyperliquidChain: action.hyperliquidChain, destination: action.destination.toLowerCase(), amount: action.amount, time: action.time, }; }, }; /** Removes trailing zeros from decimal string. */ function formatDecimal(numStr) { if (!numStr.includes(".")) return numStr; const [intPart, fracPart] = numStr.split("."); const newFrac = fracPart.replace(/0+$/, ""); return newFrac ? `${intPart}.${newFrac}` : intPart; } /** EIP-712 type definitions for user-signed actions. */ export const userSignedActionEip712Types = { approveAgent: { "HyperliquidTransaction:ApproveAgent": [ { name: "hyperliquidChain", type: "string" }, { name: "agentAddress", type: "address" }, { name: "agentName", type: "string" }, { name: "nonce", type: "uint64" }, ], }, approveBuilderFee: { "HyperliquidTransaction:ApproveBuilderFee": [ { name: "hyperliquidChain", type: "string" }, { name: "maxFeeRate", type: "string" }, { name: "builder", type: "address" }, { name: "nonce", type: "uint64" }, ], }, cDeposit: { "HyperliquidTransaction:CDeposit": [ { name: "hyperliquidChain", type: "string" }, { name: "wei", type: "uint64" }, { name: "nonce", type: "uint64" }, ], }, convertToMultiSigUser: { "HyperliquidTransaction:ConvertToMultiSigUser": [ { name: "hyperliquidChain", type: "string" }, { name: "signers", type: "string" }, { name: "nonce", type: "uint64" }, ], }, cWithdraw: { "HyperliquidTransaction:CWithdraw": [ { name: "hyperliquidChain", type: "string" }, { name: "wei", type: "uint64" }, { name: "nonce", type: "uint64" }, ], }, multiSig: { "HyperliquidTransaction:SendMultiSig": [ { name: "hyperliquidChain", type: "string" }, { name: "multiSigActionHash", type: "bytes32" }, { name: "nonce", type: "uint64" }, ], }, spotSend: { "HyperliquidTransaction:SpotSend": [ { name: "hyperliquidChain", type: "string" }, { name: "destination", type: "string" }, { name: "token", type: "string" }, { name: "amount", type: "string" }, { name: "time", type: "uint64" }, ], }, tokenDelegate: { "HyperliquidTransaction:TokenDelegate": [ { name: "hyperliquidChain", type: "string" }, { name: "validator", type: "address" }, { name: "wei", type: "uint64" }, { name: "isUndelegate", type: "bool" }, { name: "nonce", type: "uint64" }, ], }, usdClassTransfer: { "HyperliquidTransaction:UsdClassTransfer": [ { name: "hyperliquidChain", type: "string" }, { name: "amount", type: "string" }, { name: "toPerp", type: "bool" }, { name: "nonce", type: "uint64" }, ], }, usdSend: { "HyperliquidTransaction:UsdSend": [ { name: "hyperliquidChain", type: "string" }, { name: "destination", type: "string" }, { name: "amount", type: "string" }, { name: "time", type: "uint64" }, ], }, withdraw3: { "HyperliquidTransaction:Withdraw": [ { name: "hyperliquidChain", type: "string" }, { name: "destination", type: "string" }, { name: "amount", type: "string" }, { name: "time", type: "uint64" }, ], }, };