@metamask-previews/perps-controller 15.1.0-preview-00a181c → 15.1.0-preview-cfd35b8dd

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/CHANGELOG.md +0 -14
  2. package/dist/PerpsController-method-action-types.cjs.map +1 -1
  3. package/dist/PerpsController-method-action-types.d.cts +1 -20
  4. package/dist/PerpsController-method-action-types.d.cts.map +1 -1
  5. package/dist/PerpsController-method-action-types.d.mts +1 -20
  6. package/dist/PerpsController-method-action-types.d.mts.map +1 -1
  7. package/dist/PerpsController-method-action-types.mjs.map +1 -1
  8. package/dist/PerpsController.cjs +154 -65
  9. package/dist/PerpsController.cjs.map +1 -1
  10. package/dist/PerpsController.d.cts +43 -37
  11. package/dist/PerpsController.d.cts.map +1 -1
  12. package/dist/PerpsController.d.mts +43 -37
  13. package/dist/PerpsController.d.mts.map +1 -1
  14. package/dist/PerpsController.mjs +151 -64
  15. package/dist/PerpsController.mjs.map +1 -1
  16. package/dist/aggregation/SubscriptionMultiplexer.cjs +1 -1
  17. package/dist/aggregation/SubscriptionMultiplexer.cjs.map +1 -1
  18. package/dist/aggregation/SubscriptionMultiplexer.d.cts +1 -1
  19. package/dist/aggregation/SubscriptionMultiplexer.d.mts +1 -1
  20. package/dist/aggregation/SubscriptionMultiplexer.mjs +1 -1
  21. package/dist/aggregation/SubscriptionMultiplexer.mjs.map +1 -1
  22. package/dist/constants/index.cjs +1 -0
  23. package/dist/constants/index.cjs.map +1 -1
  24. package/dist/constants/index.d.cts +1 -0
  25. package/dist/constants/index.d.cts.map +1 -1
  26. package/dist/constants/index.d.mts +1 -0
  27. package/dist/constants/index.d.mts.map +1 -1
  28. package/dist/constants/index.mjs +1 -0
  29. package/dist/constants/index.mjs.map +1 -1
  30. package/dist/constants/myxConfig.cjs +253 -0
  31. package/dist/constants/myxConfig.cjs.map +1 -0
  32. package/dist/constants/myxConfig.d.cts +145 -0
  33. package/dist/constants/myxConfig.d.cts.map +1 -0
  34. package/dist/constants/myxConfig.d.mts +145 -0
  35. package/dist/constants/myxConfig.d.mts.map +1 -0
  36. package/dist/constants/myxConfig.mjs +243 -0
  37. package/dist/constants/myxConfig.mjs.map +1 -0
  38. package/dist/constants/perpsConfig.cjs +9 -4
  39. package/dist/constants/perpsConfig.cjs.map +1 -1
  40. package/dist/constants/perpsConfig.d.cts +5 -3
  41. package/dist/constants/perpsConfig.d.cts.map +1 -1
  42. package/dist/constants/perpsConfig.d.mts +5 -3
  43. package/dist/constants/perpsConfig.d.mts.map +1 -1
  44. package/dist/constants/perpsConfig.mjs +9 -4
  45. package/dist/constants/perpsConfig.mjs.map +1 -1
  46. package/dist/index.cjs +175 -146
  47. package/dist/index.cjs.map +1 -1
  48. package/dist/index.d.cts +2 -2
  49. package/dist/index.d.cts.map +1 -1
  50. package/dist/index.d.mts +2 -2
  51. package/dist/index.d.mts.map +1 -1
  52. package/dist/index.mjs +1 -0
  53. package/dist/index.mjs.map +1 -1
  54. package/dist/providers/AggregatedPerpsProvider.cjs +2 -8
  55. package/dist/providers/AggregatedPerpsProvider.cjs.map +1 -1
  56. package/dist/providers/AggregatedPerpsProvider.d.cts +2 -3
  57. package/dist/providers/AggregatedPerpsProvider.d.cts.map +1 -1
  58. package/dist/providers/AggregatedPerpsProvider.d.mts +2 -3
  59. package/dist/providers/AggregatedPerpsProvider.d.mts.map +1 -1
  60. package/dist/providers/AggregatedPerpsProvider.mjs +2 -8
  61. package/dist/providers/AggregatedPerpsProvider.mjs.map +1 -1
  62. package/dist/providers/HyperLiquidProvider.cjs +22 -118
  63. package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
  64. package/dist/providers/HyperLiquidProvider.d.cts +0 -31
  65. package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
  66. package/dist/providers/HyperLiquidProvider.d.mts +0 -31
  67. package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
  68. package/dist/providers/HyperLiquidProvider.mjs +22 -118
  69. package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
  70. package/dist/providers/LighterProvider.cjs +1 -1
  71. package/dist/providers/LighterProvider.cjs.map +1 -1
  72. package/dist/providers/LighterProvider.mjs +1 -1
  73. package/dist/providers/LighterProvider.mjs.map +1 -1
  74. package/dist/routing/ProviderRouter.cjs +1 -1
  75. package/dist/routing/ProviderRouter.cjs.map +1 -1
  76. package/dist/routing/ProviderRouter.d.cts +1 -1
  77. package/dist/routing/ProviderRouter.d.mts +1 -1
  78. package/dist/routing/ProviderRouter.mjs +1 -1
  79. package/dist/routing/ProviderRouter.mjs.map +1 -1
  80. package/dist/services/HyperLiquidClientService.cjs.map +1 -1
  81. package/dist/services/HyperLiquidClientService.d.cts +16 -26
  82. package/dist/services/HyperLiquidClientService.d.cts.map +1 -1
  83. package/dist/services/HyperLiquidClientService.d.mts +16 -26
  84. package/dist/services/HyperLiquidClientService.d.mts.map +1 -1
  85. package/dist/services/HyperLiquidClientService.mjs.map +1 -1
  86. package/dist/services/HyperLiquidWalletService.cjs +30 -80
  87. package/dist/services/HyperLiquidWalletService.cjs.map +1 -1
  88. package/dist/services/HyperLiquidWalletService.d.cts +22 -48
  89. package/dist/services/HyperLiquidWalletService.d.cts.map +1 -1
  90. package/dist/services/HyperLiquidWalletService.d.mts +22 -48
  91. package/dist/services/HyperLiquidWalletService.d.mts.map +1 -1
  92. package/dist/services/HyperLiquidWalletService.mjs +30 -80
  93. package/dist/services/HyperLiquidWalletService.mjs.map +1 -1
  94. package/dist/services/LighterWalletService.cjs +1 -1
  95. package/dist/services/LighterWalletService.cjs.map +1 -1
  96. package/dist/services/LighterWalletService.d.cts +1 -1
  97. package/dist/services/LighterWalletService.d.mts +1 -1
  98. package/dist/services/LighterWalletService.mjs +1 -1
  99. package/dist/services/LighterWalletService.mjs.map +1 -1
  100. package/dist/types/index.cjs.map +1 -1
  101. package/dist/types/index.d.cts +16 -10
  102. package/dist/types/index.d.cts.map +1 -1
  103. package/dist/types/index.d.mts +16 -10
  104. package/dist/types/index.d.mts.map +1 -1
  105. package/dist/types/index.mjs.map +1 -1
  106. package/dist/types/myx-types.cjs +41 -0
  107. package/dist/types/myx-types.cjs.map +1 -0
  108. package/dist/types/myx-types.d.cts +94 -0
  109. package/dist/types/myx-types.d.cts.map +1 -0
  110. package/dist/types/myx-types.d.mts +94 -0
  111. package/dist/types/myx-types.d.mts.map +1 -0
  112. package/dist/types/myx-types.mjs +26 -0
  113. package/dist/types/myx-types.mjs.map +1 -0
  114. package/dist/utils/lighterAdapter.cjs +2 -1
  115. package/dist/utils/lighterAdapter.cjs.map +1 -1
  116. package/dist/utils/lighterAdapter.d.cts +2 -1
  117. package/dist/utils/lighterAdapter.d.cts.map +1 -1
  118. package/dist/utils/lighterAdapter.d.mts +2 -1
  119. package/dist/utils/lighterAdapter.d.mts.map +1 -1
  120. package/dist/utils/lighterAdapter.mjs +2 -1
  121. package/dist/utils/lighterAdapter.mjs.map +1 -1
  122. package/dist/utils/myxAdapter.cjs +569 -0
  123. package/dist/utils/myxAdapter.cjs.map +1 -0
  124. package/dist/utils/myxAdapter.d.cts +168 -0
  125. package/dist/utils/myxAdapter.d.cts.map +1 -0
  126. package/dist/utils/myxAdapter.d.mts +168 -0
  127. package/dist/utils/myxAdapter.d.mts.map +1 -0
  128. package/dist/utils/myxAdapter.mjs +548 -0
  129. package/dist/utils/myxAdapter.mjs.map +1 -0
  130. package/package.json +8 -2
@@ -1 +1 @@
1
- {"version":3,"file":"HyperLiquidWalletService.cjs","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n hasProperty,\n isValidHexAddress,\n parseCaipAccountId,\n} from '@metamask/utils';\nimport type { CaipAccountId, Hex } from '@metamask/utils';\n\nimport { getChainId } from '../constants/hyperLiquidConfig.js';\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes.js';\nimport type {\n HyperLiquidSignTypedDataParams,\n HyperLiquidWalletParams,\n} from './HyperLiquidClientService.js';\nimport type {\n PerpsPlatformDependencies,\n PerpsTypedMessageParams,\n} from '../types/index.js';\nimport type { PerpsControllerMessengerBase } from '../types/messenger.js';\nimport {\n getSelectedEvmAccountDetailsFromMessenger,\n getSelectedEvmAccountFromMessenger,\n} from '../utils/accountUtils.js';\n\n// Mirrors KeyringTypes from @metamask/keyring-controller. Inlined to keep this\n// service portable between mobile and the core monorepo.\nconst HARDWARE_KEYRING_TYPES = new Set<string>([\n 'Ledger Hardware',\n 'Trezor Hardware',\n 'OneKey Hardware',\n 'Lattice Hardware',\n 'QR Hardware Wallet Device',\n]);\n\n/**\n * A local signer for a HyperLiquid agent account, in the SDK-native\n * `AbstractEthersV6Signer` shape (positional EIP-712 arguments, message as\n * the signed value). Provided by the client (e.g. a local key stored in\n * memory) so agent actions never touch the keyring.\n */\nexport type AgentSigner = {\n /** The agent account address used as the actor for signed actions. */\n address: `0x${string}`;\n /**\n * Sign EIP-712 typed data with the agent key (positional ethers-style\n * arguments; `types` must not include `EIP712Domain`).\n *\n * @param domain - The EIP-712 domain.\n * @param types - The EIP-712 type definitions (without `EIP712Domain`).\n * @param value - The message payload to sign.\n * @returns The hex signature.\n */\n signTypedData(\n domain: HyperLiquidSignTypedDataParams['domain'],\n types: HyperLiquidSignTypedDataParams['types'],\n value: Record<string, unknown>,\n ): Promise<string>;\n};\n\n/**\n * Service for MetaMask wallet integration with HyperLiquid SDK\n * Provides wallet adapter that implements AbstractWindowEthereum interface\n */\nexport class HyperLiquidWalletService {\n #isTestnet: boolean;\n\n // Platform dependencies for observability\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessengerBase;\n\n constructor(\n deps: PerpsPlatformDependencies,\n messenger: PerpsControllerMessengerBase,\n options: { isTestnet?: boolean } = {},\n ) {\n this.#deps = deps;\n this.#messenger = messenger;\n this.#isTestnet = options.isTestnet ?? false;\n }\n\n /**\n * Check if the keyring is currently unlocked\n *\n * @returns True if the keyring is unlocked and available for signing.\n */\n public isKeyringUnlocked(): boolean {\n return this.#messenger.call('KeyringController:getState').isUnlocked;\n }\n\n /**\n * Check whether the selected EVM account is backed by hardware.\n *\n * @returns True for MetaMask hardware keyrings; false for software accounts.\n */\n public isSelectedHardwareWallet(): boolean {\n const selectedEvmAccount = getSelectedEvmAccountDetailsFromMessenger(\n this.#messenger,\n );\n if (!selectedEvmAccount || !hasProperty(selectedEvmAccount, 'metadata')) {\n return false;\n }\n\n const metadata = selectedEvmAccount.metadata as\n | { keyring?: { type?: string } }\n | undefined;\n const keyringType = metadata?.keyring?.type;\n\n return Boolean(keyringType && HARDWARE_KEYRING_TYPES.has(keyringType));\n }\n\n /**\n * Sign typed data via DI keyring controller\n *\n * @param msgParams - The typed message parameters including data and sender address.\n * @returns The signature string.\n */\n async #signTypedMessage(msgParams: PerpsTypedMessageParams): Promise<string> {\n if (!this.isKeyringUnlocked()) {\n throw new Error(PERPS_ERROR_CODES.KEYRING_LOCKED);\n }\n // Cast needed: PerpsTypedMessageParams uses loose `data: unknown` type\n // while KeyringController uses strict TypedMessageParams / SignTypedDataVersion\n return this.#messenger.call(\n 'KeyringController:signTypedMessage',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n msgParams as any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n 'V4' as any,\n );\n }\n\n /**\n * Sign typed data with the master account via the keyring, resolving the\n * selected account fresh so account switches cannot race the adapter.\n *\n * @param params - The typed-data signing request the SDK passed to the adapter.\n * @returns The signature string.\n */\n async #signWithMaster(params: HyperLiquidSignTypedDataParams): Promise<Hex> {\n const currentEvmAccount = getSelectedEvmAccountFromMessenger(\n this.#messenger,\n );\n\n if (!currentEvmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const currentAddress = currentEvmAccount.address as Hex;\n\n this.#deps.debugLogger.log(\n 'HyperLiquidWalletService: Signing typed data (master fallback)',\n {\n address: currentAddress,\n primaryType: params.primaryType,\n domain: params.domain,\n },\n );\n\n const signature = await this.#signTypedMessage({\n from: currentAddress,\n data: {\n domain: params.domain,\n types: params.types,\n primaryType: params.primaryType,\n message: params.message,\n },\n });\n\n return signature as Hex;\n }\n\n /**\n * Whether a typed-data signing request is an L1 (phantom-agent) action.\n *\n * The HyperLiquid SDK signs L1 actions (order/cancel/modify/TWAP/leverage/\n * margin/agentSetAbstraction) with EIP-712 primaryType `Agent` over domain\n * `{ name: \"Exchange\", version: \"1\", chainId: 1337 }`. Only these may be\n * signed by an agent key; every other shape (e.g. `approveBuilderFee`,\n * `userSetAbstraction`, `sendAsset`, `withdraw3` over the\n * `HyperliquidSignTransaction` domain) is a user-signed action that\n * authorizes the master account and must be signed by the master wallet.\n *\n * @param primaryType - The EIP-712 primary type of the signing request.\n * @param domainName - The EIP-712 domain name of the signing request.\n * @returns True when the request belongs to the agent-signable L1 class.\n */\n #isL1AgentAction(primaryType: string, domainName?: string): boolean {\n return primaryType === 'Agent' || domainName === 'Exchange';\n }\n\n /**\n * Create a wallet adapter backed by a local agent signer.\n *\n * The returned adapter keeps the params-style `signTypedData` shape the SDK\n * already accepts (viem local account), but routes by typed-data shape:\n * L1 (phantom-agent) actions — primaryType `Agent` over the `Exchange`\n * domain — are signed directly by the injected local signer with no keyring\n * contact; user-signed actions (`approveBuilderFee`, `userSetAbstraction`,\n * `sendAsset`, `withdraw3`, … over the `HyperliquidSignTransaction` domain)\n * are master-account authorizations and fall through to the master keyring\n * signing path, so hardware users get the normal device prompt. The SDK's\n * viem adapters inject an `EIP712Domain` entry into `types` before calling\n * params-style wallets; ethers-style signers reject that entry, so it is\n * stripped before delegating to the agent signer (the master path passes\n * `types` through unchanged, matching the pre-seam master adapter).\n *\n * @param agentSigner - The local agent signer to delegate L1 actions to.\n * @returns The agent wallet adapter.\n */\n public createAgentWalletAdapter(\n agentSigner: AgentSigner,\n ): HyperLiquidWalletParams {\n return {\n // The agent address is returned for identity purposes: the SDK only uses\n // it for local lock/nonce keying (`getWalletAddress`), never inside the\n // signed payload — HyperLiquid recovers the signer from the signature.\n address: agentSigner.address,\n signTypedData: async (\n params: HyperLiquidSignTypedDataParams,\n ): Promise<Hex> => {\n if (this.#isL1AgentAction(params.primaryType, params.domain?.name)) {\n const { EIP712Domain: _eip712Domain, ...types } = params.types;\n\n this.#deps.debugLogger.log(\n 'HyperLiquidWalletService: Signing typed data (agent mode)',\n {\n address: agentSigner.address,\n primaryType: params.primaryType,\n },\n );\n\n return (await agentSigner.signTypedData(\n params.domain,\n types,\n params.message,\n )) as Hex;\n }\n\n // User-signed action: master-account authorization, must be signed\n // by the master wallet (device prompt on hardware).\n return this.#signWithMaster(params);\n },\n getChainId: async (): Promise<number> =>\n parseInt(getChainId(this.#isTestnet), 10),\n };\n }\n\n /**\n * Create the master-keyring wallet adapter for the HyperLiquid SDK.\n *\n * This factory is synchronous and always signs via the selected master\n * account. Agent wallets are built separately with\n * {@link createAgentWalletAdapter}; the provider selects which adapter the\n * SDK clients use.\n *\n * @returns The wallet adapter with address, signTypedData, and getChainId methods.\n */\n public createWalletAdapter(): HyperLiquidWalletParams {\n // Get current EVM account via DI messenger\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const address = evmAccount.address as Hex;\n\n return {\n address,\n signTypedData: async (\n params: HyperLiquidSignTypedDataParams,\n ): Promise<Hex> => this.#signWithMaster(params),\n getChainId: async (): Promise<number> =>\n parseInt(getChainId(this.#isTestnet), 10),\n };\n }\n\n /**\n * Get current account ID using messenger\n *\n * @returns The CAIP account ID for the current EVM account.\n */\n public async getCurrentAccountId(): Promise<CaipAccountId> {\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const chainId = getChainId(this.#isTestnet);\n const caipAccountId: CaipAccountId = `eip155:${chainId}:${evmAccount.address}`;\n\n return caipAccountId;\n }\n\n /**\n * Get validated user address as Hex from account ID\n *\n * @param accountId - The CAIP account ID to extract the address from.\n * @returns The validated hex address.\n */\n public getUserAddress(accountId: CaipAccountId): Hex {\n const parsed = parseCaipAccountId(accountId);\n const address = parsed.address as Hex;\n\n if (!isValidHexAddress(address)) {\n throw new Error(PERPS_ERROR_CODES.INVALID_ADDRESS_FORMAT);\n }\n\n return address;\n }\n\n /**\n * Get user address with default fallback to current account\n *\n * @param accountId - Optional CAIP account ID; defaults to current account if omitted.\n * @returns The validated hex address.\n */\n public async getUserAddressWithDefault(\n accountId?: CaipAccountId,\n ): Promise<Hex> {\n const id = accountId ?? (await this.getCurrentAccountId());\n return this.getUserAddress(id);\n }\n\n /**\n * Update testnet mode\n *\n * @param isTestnet - Whether to enable testnet mode.\n */\n public setTestnetMode(isTestnet: boolean): void {\n this.#isTestnet = isTestnet;\n }\n\n /**\n * Check if running on testnet\n *\n * @returns True if the service is in testnet mode.\n */\n public isTestnetMode(): boolean {\n return this.#isTestnet;\n }\n}\n"]}
1
+ {"version":3,"file":"HyperLiquidWalletService.cjs","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAIyB;AAGzB,6EAA+D;AAC/D,+DAA0D;AAM1D,+DAGkC;AAElC,+EAA+E;AAC/E,yDAAyD;AACzD,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAS;IAC7C,iBAAiB;IACjB,iBAAiB;IACjB,iBAAiB;IACjB,kBAAkB;IAClB,2BAA2B;CAC5B,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAa,wBAAwB;IAQnC,YACE,IAA+B,EAC/B,SAAuC,EACvC,UAAmC,EAAE;;QAVvC,sDAAoB;QAEpB,0CAA0C;QACjC,iDAAiC;QAEjC,sDAAyC;QAOhD,uBAAA,IAAI,kCAAS,IAAI,MAAA,CAAC;QAClB,uBAAA,IAAI,uCAAc,SAAS,MAAA,CAAC;QAC5B,uBAAA,IAAI,uCAAc,OAAO,CAAC,SAAS,IAAI,KAAK,MAAA,CAAC;IAC/C,CAAC;IAED;;;;OAIG;IACI,iBAAiB;QACtB,OAAO,uBAAA,IAAI,2CAAW,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC,UAAU,CAAC;IACvE,CAAC;IAED;;;;OAIG;IACI,wBAAwB;QAC7B,MAAM,kBAAkB,GAAG,IAAA,2DAAyC,EAClE,uBAAA,IAAI,2CAAW,CAChB,CAAC;QACF,IAAI,CAAC,kBAAkB,IAAI,CAAC,IAAA,mBAAW,EAAC,kBAAkB,EAAE,UAAU,CAAC,EAAE,CAAC;YACxE,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,QAAQ,GAAG,kBAAkB,CAAC,QAEvB,CAAC;QACd,MAAM,WAAW,GAAG,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;QAE5C,OAAO,OAAO,CAAC,WAAW,IAAI,sBAAsB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;IACzE,CAAC;IAuBD;;;;;OAKG;IACI,mBAAmB;QAiBxB,2CAA2C;QAC3C,MAAM,UAAU,GAAG,IAAA,oDAAkC,EAAC,uBAAA,IAAI,2CAAW,CAAC,CAAC;QAEvE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,sCAAiB,CAAC,mBAAmB,CAAC,CAAC;QACzD,CAAC;QAED,MAAM,OAAO,GAAG,UAAU,CAAC,OAAc,CAAC;QAE1C,OAAO;YACL,OAAO;YACP,aAAa,EAAE,KAAK,EAAE,MAYrB,EAAgB,EAAE;gBACjB,6DAA6D;gBAC7D,kFAAkF;gBAClF,MAAM,iBAAiB,GAAG,IAAA,oDAAkC,EAC1D,uBAAA,IAAI,2CAAW,CAChB,CAAC;gBAEF,IAAI,CAAC,iBAAiB,EAAE,OAAO,EAAE,CAAC;oBAChC,MAAM,IAAI,KAAK,CAAC,sCAAiB,CAAC,mBAAmB,CAAC,CAAC;gBACzD,CAAC;gBAED,MAAM,cAAc,GAAG,iBAAiB,CAAC,OAAc,CAAC;gBAExD,+BAA+B;gBAC/B,MAAM,SAAS,GAAG;oBAChB,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,KAAK,EAAE,MAAM,CAAC,KAAK;oBACnB,WAAW,EAAE,MAAM,CAAC,WAAW;oBAC/B,OAAO,EAAE,MAAM,CAAC,OAAO;iBACxB,CAAC;gBAEF,uBAAA,IAAI,sCAAM,CAAC,WAAW,CAAC,GAAG,CACxB,8CAA8C,EAC9C;oBACE,OAAO,EAAE,cAAc;oBACvB,WAAW,EAAE,MAAM,CAAC,WAAW;oBAC/B,MAAM,EAAE,MAAM,CAAC,MAAM;iBACtB,CACF,CAAC;gBAEF,mCAAmC;gBACnC,MAAM,SAAS,GAAG,MAAM,uBAAA,IAAI,uFAAkB,MAAtB,IAAI,EAAmB;oBAC7C,IAAI,EAAE,cAAc;oBACpB,IAAI,EAAE,SAAS;iBAChB,CAAC,CAAC;gBAEH,OAAO,SAAgB,CAAC;YAC1B,CAAC;YACD,UAAU,EAAE,KAAK,IAAqB,EAAE,CACtC,QAAQ,CAAC,IAAA,iCAAU,EAAC,uBAAA,IAAI,2CAAW,CAAC,EAAE,EAAE,CAAC;SAC5C,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,mBAAmB;QAC9B,MAAM,UAAU,GAAG,IAAA,oDAAkC,EAAC,uBAAA,IAAI,2CAAW,CAAC,CAAC;QAEvE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,sCAAiB,CAAC,mBAAmB,CAAC,CAAC;QACzD,CAAC;QAED,MAAM,OAAO,GAAG,IAAA,iCAAU,EAAC,uBAAA,IAAI,2CAAW,CAAC,CAAC;QAC5C,MAAM,aAAa,GAAkB,UAAU,OAAO,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;QAE/E,OAAO,aAAa,CAAC;IACvB,CAAC;IAED;;;;;OAKG;IACI,cAAc,CAAC,SAAwB;QAC5C,MAAM,MAAM,GAAG,IAAA,0BAAkB,EAAC,SAAS,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAc,CAAC;QAEtC,IAAI,CAAC,IAAA,yBAAiB,EAAC,OAAO,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,sCAAiB,CAAC,sBAAsB,CAAC,CAAC;QAC5D,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,yBAAyB,CACpC,SAAyB;QAEzB,MAAM,EAAE,GAAG,SAAS,IAAI,CAAC,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACI,cAAc,CAAC,SAAkB;QACtC,uBAAA,IAAI,uCAAc,SAAS,MAAA,CAAC;IAC9B,CAAC;IAED;;;;OAIG;IACI,aAAa;QAClB,OAAO,uBAAA,IAAI,2CAAW,CAAC;IACzB,CAAC;CACF;AA/ND,4DA+NC;;AA/KC;;;;;GAKG;AACH,KAAK,qDAAmB,SAAkC;IACxD,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,sCAAiB,CAAC,cAAc,CAAC,CAAC;IACpD,CAAC;IACD,uEAAuE;IACvE,gFAAgF;IAChF,OAAO,uBAAA,IAAI,2CAAW,CAAC,IAAI,CACzB,oCAAoC;IACpC,8DAA8D;IAC9D,SAAgB;IAChB,8DAA8D;IAC9D,IAAW,CACZ,CAAC;AACJ,CAAC","sourcesContent":["import {\n hasProperty,\n isValidHexAddress,\n parseCaipAccountId,\n} from '@metamask/utils';\nimport type { CaipAccountId, Hex } from '@metamask/utils';\n\nimport { getChainId } from '../constants/hyperLiquidConfig.js';\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes.js';\nimport type {\n PerpsPlatformDependencies,\n PerpsTypedMessageParams,\n} from '../types/index.js';\nimport type { PerpsControllerMessengerBase } from '../types/messenger.js';\nimport {\n getSelectedEvmAccountDetailsFromMessenger,\n getSelectedEvmAccountFromMessenger,\n} from '../utils/accountUtils.js';\n\n// Mirrors KeyringTypes from @metamask/keyring-controller. Inlined to keep this\n// service portable between mobile and the core monorepo.\nconst HARDWARE_KEYRING_TYPES = new Set<string>([\n 'Ledger Hardware',\n 'Trezor Hardware',\n 'OneKey Hardware',\n 'Lattice Hardware',\n 'QR Hardware Wallet Device',\n]);\n\n/**\n * Service for MetaMask wallet integration with HyperLiquid SDK\n * Provides wallet adapter that implements AbstractWindowEthereum interface\n */\nexport class HyperLiquidWalletService {\n #isTestnet: boolean;\n\n // Platform dependencies for observability\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessengerBase;\n\n constructor(\n deps: PerpsPlatformDependencies,\n messenger: PerpsControllerMessengerBase,\n options: { isTestnet?: boolean } = {},\n ) {\n this.#deps = deps;\n this.#messenger = messenger;\n this.#isTestnet = options.isTestnet ?? false;\n }\n\n /**\n * Check if the keyring is currently unlocked\n *\n * @returns True if the keyring is unlocked and available for signing.\n */\n public isKeyringUnlocked(): boolean {\n return this.#messenger.call('KeyringController:getState').isUnlocked;\n }\n\n /**\n * Check whether the selected EVM account is backed by hardware.\n *\n * @returns True for MetaMask hardware keyrings; false for software accounts.\n */\n public isSelectedHardwareWallet(): boolean {\n const selectedEvmAccount = getSelectedEvmAccountDetailsFromMessenger(\n this.#messenger,\n );\n if (!selectedEvmAccount || !hasProperty(selectedEvmAccount, 'metadata')) {\n return false;\n }\n\n const metadata = selectedEvmAccount.metadata as\n | { keyring?: { type?: string } }\n | undefined;\n const keyringType = metadata?.keyring?.type;\n\n return Boolean(keyringType && HARDWARE_KEYRING_TYPES.has(keyringType));\n }\n\n /**\n * Sign typed data via DI keyring controller\n *\n * @param msgParams - The typed message parameters including data and sender address.\n * @returns The signature string.\n */\n async #signTypedMessage(msgParams: PerpsTypedMessageParams): Promise<string> {\n if (!this.isKeyringUnlocked()) {\n throw new Error(PERPS_ERROR_CODES.KEYRING_LOCKED);\n }\n // Cast needed: PerpsTypedMessageParams uses loose `data: unknown` type\n // while KeyringController uses strict TypedMessageParams / SignTypedDataVersion\n return this.#messenger.call(\n 'KeyringController:signTypedMessage',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n msgParams as any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n 'V4' as any,\n );\n }\n\n /**\n * Create wallet adapter that implements AbstractViemJsonRpcAccount interface\n * Required by @nktkas/hyperliquid SDK for signing transactions\n *\n * @returns The wallet adapter with address, signTypedData, and getChainId methods.\n */\n public createWalletAdapter(): {\n address: Hex;\n signTypedData: (params: {\n domain: {\n name: string;\n version: string;\n chainId: number;\n verifyingContract: Hex;\n };\n types: {\n [key: string]: { name: string; type: string }[];\n };\n primaryType: string;\n message: Record<string, unknown>;\n }) => Promise<Hex>;\n getChainId?: () => Promise<number>;\n } {\n // Get current EVM account via DI messenger\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const address = evmAccount.address as Hex;\n\n return {\n address,\n signTypedData: async (params: {\n domain: {\n name: string;\n version: string;\n chainId: number;\n verifyingContract: Hex;\n };\n types: {\n [key: string]: { name: string; type: string }[];\n };\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<Hex> => {\n // Get FRESH account on every sign to handle account switches\n // This prevents race conditions where wallet adapter was created with old account\n const currentEvmAccount = getSelectedEvmAccountFromMessenger(\n this.#messenger,\n );\n\n if (!currentEvmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const currentAddress = currentEvmAccount.address as Hex;\n\n // Construct EIP-712 typed data\n const typedData = {\n domain: params.domain,\n types: params.types,\n primaryType: params.primaryType,\n message: params.message,\n };\n\n this.#deps.debugLogger.log(\n 'HyperLiquidWalletService: Signing typed data',\n {\n address: currentAddress,\n primaryType: params.primaryType,\n domain: params.domain,\n },\n );\n\n // Use messenger to sign typed data\n const signature = await this.#signTypedMessage({\n from: currentAddress,\n data: typedData,\n });\n\n return signature as Hex;\n },\n getChainId: async (): Promise<number> =>\n parseInt(getChainId(this.#isTestnet), 10),\n };\n }\n\n /**\n * Get current account ID using messenger\n *\n * @returns The CAIP account ID for the current EVM account.\n */\n public async getCurrentAccountId(): Promise<CaipAccountId> {\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const chainId = getChainId(this.#isTestnet);\n const caipAccountId: CaipAccountId = `eip155:${chainId}:${evmAccount.address}`;\n\n return caipAccountId;\n }\n\n /**\n * Get validated user address as Hex from account ID\n *\n * @param accountId - The CAIP account ID to extract the address from.\n * @returns The validated hex address.\n */\n public getUserAddress(accountId: CaipAccountId): Hex {\n const parsed = parseCaipAccountId(accountId);\n const address = parsed.address as Hex;\n\n if (!isValidHexAddress(address)) {\n throw new Error(PERPS_ERROR_CODES.INVALID_ADDRESS_FORMAT);\n }\n\n return address;\n }\n\n /**\n * Get user address with default fallback to current account\n *\n * @param accountId - Optional CAIP account ID; defaults to current account if omitted.\n * @returns The validated hex address.\n */\n public async getUserAddressWithDefault(\n accountId?: CaipAccountId,\n ): Promise<Hex> {\n const id = accountId ?? (await this.getCurrentAccountId());\n return this.getUserAddress(id);\n }\n\n /**\n * Update testnet mode\n *\n * @param isTestnet - Whether to enable testnet mode.\n */\n public setTestnetMode(isTestnet: boolean): void {\n this.#isTestnet = isTestnet;\n }\n\n /**\n * Check if running on testnet\n *\n * @returns True if the service is in testnet mode.\n */\n public isTestnetMode(): boolean {\n return this.#isTestnet;\n }\n}\n"]}
@@ -1,27 +1,6 @@
1
1
  import type { CaipAccountId, Hex } from "@metamask/utils";
2
- import type { HyperLiquidSignTypedDataParams, HyperLiquidWalletParams } from "./HyperLiquidClientService.cjs";
3
2
  import type { PerpsPlatformDependencies } from "../types/index.cjs";
4
3
  import type { PerpsControllerMessengerBase } from "../types/messenger.cjs";
5
- /**
6
- * A local signer for a HyperLiquid agent account, in the SDK-native
7
- * `AbstractEthersV6Signer` shape (positional EIP-712 arguments, message as
8
- * the signed value). Provided by the client (e.g. a local key stored in
9
- * memory) so agent actions never touch the keyring.
10
- */
11
- export type AgentSigner = {
12
- /** The agent account address used as the actor for signed actions. */
13
- address: `0x${string}`;
14
- /**
15
- * Sign EIP-712 typed data with the agent key (positional ethers-style
16
- * arguments; `types` must not include `EIP712Domain`).
17
- *
18
- * @param domain - The EIP-712 domain.
19
- * @param types - The EIP-712 type definitions (without `EIP712Domain`).
20
- * @param value - The message payload to sign.
21
- * @returns The hex signature.
22
- */
23
- signTypedData(domain: HyperLiquidSignTypedDataParams['domain'], types: HyperLiquidSignTypedDataParams['types'], value: Record<string, unknown>): Promise<string>;
24
- };
25
4
  /**
26
5
  * Service for MetaMask wallet integration with HyperLiquid SDK
27
6
  * Provides wallet adapter that implements AbstractWindowEthereum interface
@@ -44,36 +23,31 @@ export declare class HyperLiquidWalletService {
44
23
  */
45
24
  isSelectedHardwareWallet(): boolean;
46
25
  /**
47
- * Create a wallet adapter backed by a local agent signer.
48
- *
49
- * The returned adapter keeps the params-style `signTypedData` shape the SDK
50
- * already accepts (viem local account), but routes by typed-data shape:
51
- * L1 (phantom-agent) actions — primaryType `Agent` over the `Exchange`
52
- * domain — are signed directly by the injected local signer with no keyring
53
- * contact; user-signed actions (`approveBuilderFee`, `userSetAbstraction`,
54
- * `sendAsset`, `withdraw3`, … over the `HyperliquidSignTransaction` domain)
55
- * are master-account authorizations and fall through to the master keyring
56
- * signing path, so hardware users get the normal device prompt. The SDK's
57
- * viem adapters inject an `EIP712Domain` entry into `types` before calling
58
- * params-style wallets; ethers-style signers reject that entry, so it is
59
- * stripped before delegating to the agent signer (the master path passes
60
- * `types` through unchanged, matching the pre-seam master adapter).
61
- *
62
- * @param agentSigner - The local agent signer to delegate L1 actions to.
63
- * @returns The agent wallet adapter.
64
- */
65
- createAgentWalletAdapter(agentSigner: AgentSigner): HyperLiquidWalletParams;
66
- /**
67
- * Create the master-keyring wallet adapter for the HyperLiquid SDK.
68
- *
69
- * This factory is synchronous and always signs via the selected master
70
- * account. Agent wallets are built separately with
71
- * {@link createAgentWalletAdapter}; the provider selects which adapter the
72
- * SDK clients use.
26
+ * Create wallet adapter that implements AbstractViemJsonRpcAccount interface
27
+ * Required by @nktkas/hyperliquid SDK for signing transactions
73
28
  *
74
29
  * @returns The wallet adapter with address, signTypedData, and getChainId methods.
75
30
  */
76
- createWalletAdapter(): HyperLiquidWalletParams;
31
+ createWalletAdapter(): {
32
+ address: Hex;
33
+ signTypedData: (params: {
34
+ domain: {
35
+ name: string;
36
+ version: string;
37
+ chainId: number;
38
+ verifyingContract: Hex;
39
+ };
40
+ types: {
41
+ [key: string]: {
42
+ name: string;
43
+ type: string;
44
+ }[];
45
+ };
46
+ primaryType: string;
47
+ message: Record<string, unknown>;
48
+ }) => Promise<Hex>;
49
+ getChainId?: () => Promise<number>;
50
+ };
77
51
  /**
78
52
  * Get current account ID using messenger
79
53
  *
@@ -1 +1 @@
1
- {"version":3,"file":"HyperLiquidWalletService.d.cts","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,wBAAwB;AAI1D,OAAO,KAAK,EACV,8BAA8B,EAC9B,uBAAuB,EACxB,uCAAsC;AACvC,OAAO,KAAK,EACV,yBAAyB,EAE1B,2BAA0B;AAC3B,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAA8B;AAgB1E;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,sEAAsE;IACtE,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;IACvB;;;;;;;;OAQG;IACH,aAAa,CACX,MAAM,EAAE,8BAA8B,CAAC,QAAQ,CAAC,EAChD,KAAK,EAAE,8BAA8B,CAAC,OAAO,CAAC,EAC9C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,MAAM,CAAC,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,qBAAa,wBAAwB;;gBASjC,IAAI,EAAE,yBAAyB,EAC/B,SAAS,EAAE,4BAA4B,EACvC,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO;IAOvC;;;;OAIG;IACI,iBAAiB,IAAI,OAAO;IAInC;;;;OAIG;IACI,wBAAwB,IAAI,OAAO;IAgG1C;;;;;;;;;;;;;;;;;;OAkBG;IACI,wBAAwB,CAC7B,WAAW,EAAE,WAAW,GACvB,uBAAuB;IAoC1B;;;;;;;;;OASG;IACI,mBAAmB,IAAI,uBAAuB;IAoBrD;;;;OAIG;IACU,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC;IAa1D;;;;;OAKG;IACI,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,GAAG;IAWpD;;;;;OAKG;IACU,yBAAyB,CACpC,SAAS,CAAC,EAAE,aAAa,GACxB,OAAO,CAAC,GAAG,CAAC;IAKf;;;;OAIG;IACI,cAAc,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAI/C;;;;OAIG;IACI,aAAa,IAAI,OAAO;CAGhC"}
1
+ {"version":3,"file":"HyperLiquidWalletService.d.cts","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,wBAAwB;AAI1D,OAAO,KAAK,EACV,yBAAyB,EAE1B,2BAA0B;AAC3B,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAA8B;AAgB1E;;;GAGG;AACH,qBAAa,wBAAwB;;gBASjC,IAAI,EAAE,yBAAyB,EAC/B,SAAS,EAAE,4BAA4B,EACvC,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO;IAOvC;;;;OAIG;IACI,iBAAiB,IAAI,OAAO;IAInC;;;;OAIG;IACI,wBAAwB,IAAI,OAAO;IAqC1C;;;;;OAKG;IACI,mBAAmB,IAAI;QAC5B,OAAO,EAAE,GAAG,CAAC;QACb,aAAa,EAAE,CAAC,MAAM,EAAE;YACtB,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM,CAAC;gBACb,OAAO,EAAE,MAAM,CAAC;gBAChB,OAAO,EAAE,MAAM,CAAC;gBAChB,iBAAiB,EAAE,GAAG,CAAC;aACxB,CAAC;YACF,KAAK,EAAE;gBACL,CAAC,GAAG,EAAE,MAAM,GAAG;oBAAE,IAAI,EAAE,MAAM,CAAC;oBAAC,IAAI,EAAE,MAAM,CAAA;iBAAE,EAAE,CAAC;aACjD,CAAC;YACF,WAAW,EAAE,MAAM,CAAC;YACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SAClC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;KACpC;IAmED;;;;OAIG;IACU,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC;IAa1D;;;;;OAKG;IACI,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,GAAG;IAWpD;;;;;OAKG;IACU,yBAAyB,CACpC,SAAS,CAAC,EAAE,aAAa,GACxB,OAAO,CAAC,GAAG,CAAC;IAKf;;;;OAIG;IACI,cAAc,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAI/C;;;;OAIG;IACI,aAAa,IAAI,OAAO;CAGhC"}
@@ -1,27 +1,6 @@
1
1
  import type { CaipAccountId, Hex } from "@metamask/utils";
2
- import type { HyperLiquidSignTypedDataParams, HyperLiquidWalletParams } from "./HyperLiquidClientService.mjs";
3
2
  import type { PerpsPlatformDependencies } from "../types/index.mjs";
4
3
  import type { PerpsControllerMessengerBase } from "../types/messenger.mjs";
5
- /**
6
- * A local signer for a HyperLiquid agent account, in the SDK-native
7
- * `AbstractEthersV6Signer` shape (positional EIP-712 arguments, message as
8
- * the signed value). Provided by the client (e.g. a local key stored in
9
- * memory) so agent actions never touch the keyring.
10
- */
11
- export type AgentSigner = {
12
- /** The agent account address used as the actor for signed actions. */
13
- address: `0x${string}`;
14
- /**
15
- * Sign EIP-712 typed data with the agent key (positional ethers-style
16
- * arguments; `types` must not include `EIP712Domain`).
17
- *
18
- * @param domain - The EIP-712 domain.
19
- * @param types - The EIP-712 type definitions (without `EIP712Domain`).
20
- * @param value - The message payload to sign.
21
- * @returns The hex signature.
22
- */
23
- signTypedData(domain: HyperLiquidSignTypedDataParams['domain'], types: HyperLiquidSignTypedDataParams['types'], value: Record<string, unknown>): Promise<string>;
24
- };
25
4
  /**
26
5
  * Service for MetaMask wallet integration with HyperLiquid SDK
27
6
  * Provides wallet adapter that implements AbstractWindowEthereum interface
@@ -44,36 +23,31 @@ export declare class HyperLiquidWalletService {
44
23
  */
45
24
  isSelectedHardwareWallet(): boolean;
46
25
  /**
47
- * Create a wallet adapter backed by a local agent signer.
48
- *
49
- * The returned adapter keeps the params-style `signTypedData` shape the SDK
50
- * already accepts (viem local account), but routes by typed-data shape:
51
- * L1 (phantom-agent) actions — primaryType `Agent` over the `Exchange`
52
- * domain — are signed directly by the injected local signer with no keyring
53
- * contact; user-signed actions (`approveBuilderFee`, `userSetAbstraction`,
54
- * `sendAsset`, `withdraw3`, … over the `HyperliquidSignTransaction` domain)
55
- * are master-account authorizations and fall through to the master keyring
56
- * signing path, so hardware users get the normal device prompt. The SDK's
57
- * viem adapters inject an `EIP712Domain` entry into `types` before calling
58
- * params-style wallets; ethers-style signers reject that entry, so it is
59
- * stripped before delegating to the agent signer (the master path passes
60
- * `types` through unchanged, matching the pre-seam master adapter).
61
- *
62
- * @param agentSigner - The local agent signer to delegate L1 actions to.
63
- * @returns The agent wallet adapter.
64
- */
65
- createAgentWalletAdapter(agentSigner: AgentSigner): HyperLiquidWalletParams;
66
- /**
67
- * Create the master-keyring wallet adapter for the HyperLiquid SDK.
68
- *
69
- * This factory is synchronous and always signs via the selected master
70
- * account. Agent wallets are built separately with
71
- * {@link createAgentWalletAdapter}; the provider selects which adapter the
72
- * SDK clients use.
26
+ * Create wallet adapter that implements AbstractViemJsonRpcAccount interface
27
+ * Required by @nktkas/hyperliquid SDK for signing transactions
73
28
  *
74
29
  * @returns The wallet adapter with address, signTypedData, and getChainId methods.
75
30
  */
76
- createWalletAdapter(): HyperLiquidWalletParams;
31
+ createWalletAdapter(): {
32
+ address: Hex;
33
+ signTypedData: (params: {
34
+ domain: {
35
+ name: string;
36
+ version: string;
37
+ chainId: number;
38
+ verifyingContract: Hex;
39
+ };
40
+ types: {
41
+ [key: string]: {
42
+ name: string;
43
+ type: string;
44
+ }[];
45
+ };
46
+ primaryType: string;
47
+ message: Record<string, unknown>;
48
+ }) => Promise<Hex>;
49
+ getChainId?: () => Promise<number>;
50
+ };
77
51
  /**
78
52
  * Get current account ID using messenger
79
53
  *
@@ -1 +1 @@
1
- {"version":3,"file":"HyperLiquidWalletService.d.mts","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,wBAAwB;AAI1D,OAAO,KAAK,EACV,8BAA8B,EAC9B,uBAAuB,EACxB,uCAAsC;AACvC,OAAO,KAAK,EACV,yBAAyB,EAE1B,2BAA0B;AAC3B,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAA8B;AAgB1E;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,sEAAsE;IACtE,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;IACvB;;;;;;;;OAQG;IACH,aAAa,CACX,MAAM,EAAE,8BAA8B,CAAC,QAAQ,CAAC,EAChD,KAAK,EAAE,8BAA8B,CAAC,OAAO,CAAC,EAC9C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,MAAM,CAAC,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,qBAAa,wBAAwB;;gBASjC,IAAI,EAAE,yBAAyB,EAC/B,SAAS,EAAE,4BAA4B,EACvC,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO;IAOvC;;;;OAIG;IACI,iBAAiB,IAAI,OAAO;IAInC;;;;OAIG;IACI,wBAAwB,IAAI,OAAO;IAgG1C;;;;;;;;;;;;;;;;;;OAkBG;IACI,wBAAwB,CAC7B,WAAW,EAAE,WAAW,GACvB,uBAAuB;IAoC1B;;;;;;;;;OASG;IACI,mBAAmB,IAAI,uBAAuB;IAoBrD;;;;OAIG;IACU,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC;IAa1D;;;;;OAKG;IACI,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,GAAG;IAWpD;;;;;OAKG;IACU,yBAAyB,CACpC,SAAS,CAAC,EAAE,aAAa,GACxB,OAAO,CAAC,GAAG,CAAC;IAKf;;;;OAIG;IACI,cAAc,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAI/C;;;;OAIG;IACI,aAAa,IAAI,OAAO;CAGhC"}
1
+ {"version":3,"file":"HyperLiquidWalletService.d.mts","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,wBAAwB;AAI1D,OAAO,KAAK,EACV,yBAAyB,EAE1B,2BAA0B;AAC3B,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAA8B;AAgB1E;;;GAGG;AACH,qBAAa,wBAAwB;;gBASjC,IAAI,EAAE,yBAAyB,EAC/B,SAAS,EAAE,4BAA4B,EACvC,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO;IAOvC;;;;OAIG;IACI,iBAAiB,IAAI,OAAO;IAInC;;;;OAIG;IACI,wBAAwB,IAAI,OAAO;IAqC1C;;;;;OAKG;IACI,mBAAmB,IAAI;QAC5B,OAAO,EAAE,GAAG,CAAC;QACb,aAAa,EAAE,CAAC,MAAM,EAAE;YACtB,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM,CAAC;gBACb,OAAO,EAAE,MAAM,CAAC;gBAChB,OAAO,EAAE,MAAM,CAAC;gBAChB,iBAAiB,EAAE,GAAG,CAAC;aACxB,CAAC;YACF,KAAK,EAAE;gBACL,CAAC,GAAG,EAAE,MAAM,GAAG;oBAAE,IAAI,EAAE,MAAM,CAAC;oBAAC,IAAI,EAAE,MAAM,CAAA;iBAAE,EAAE,CAAC;aACjD,CAAC;YACF,WAAW,EAAE,MAAM,CAAC;YACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SAClC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;KACpC;IAmED;;;;OAIG;IACU,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC;IAa1D;;;;;OAKG;IACI,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,GAAG;IAWpD;;;;;OAKG;IACU,yBAAyB,CACpC,SAAS,CAAC,EAAE,aAAa,GACxB,OAAO,CAAC,GAAG,CAAC;IAKf;;;;OAIG;IACI,cAAc,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAI/C;;;;OAIG;IACI,aAAa,IAAI,OAAO;CAGhC"}
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _HyperLiquidWalletService_instances, _HyperLiquidWalletService_isTestnet, _HyperLiquidWalletService_deps, _HyperLiquidWalletService_messenger, _HyperLiquidWalletService_signTypedMessage, _HyperLiquidWalletService_signWithMaster, _HyperLiquidWalletService_isL1AgentAction;
12
+ var _HyperLiquidWalletService_instances, _HyperLiquidWalletService_isTestnet, _HyperLiquidWalletService_deps, _HyperLiquidWalletService_messenger, _HyperLiquidWalletService_signTypedMessage;
13
13
  import { hasProperty, isValidHexAddress, parseCaipAccountId } from "@metamask/utils";
14
14
  import { getChainId } from "../constants/hyperLiquidConfig.mjs";
15
15
  import { PERPS_ERROR_CODES } from "../perpsErrorCodes.mjs";
@@ -61,53 +61,8 @@ export class HyperLiquidWalletService {
61
61
  return Boolean(keyringType && HARDWARE_KEYRING_TYPES.has(keyringType));
62
62
  }
63
63
  /**
64
- * Create a wallet adapter backed by a local agent signer.
65
- *
66
- * The returned adapter keeps the params-style `signTypedData` shape the SDK
67
- * already accepts (viem local account), but routes by typed-data shape:
68
- * L1 (phantom-agent) actions — primaryType `Agent` over the `Exchange`
69
- * domain — are signed directly by the injected local signer with no keyring
70
- * contact; user-signed actions (`approveBuilderFee`, `userSetAbstraction`,
71
- * `sendAsset`, `withdraw3`, … over the `HyperliquidSignTransaction` domain)
72
- * are master-account authorizations and fall through to the master keyring
73
- * signing path, so hardware users get the normal device prompt. The SDK's
74
- * viem adapters inject an `EIP712Domain` entry into `types` before calling
75
- * params-style wallets; ethers-style signers reject that entry, so it is
76
- * stripped before delegating to the agent signer (the master path passes
77
- * `types` through unchanged, matching the pre-seam master adapter).
78
- *
79
- * @param agentSigner - The local agent signer to delegate L1 actions to.
80
- * @returns The agent wallet adapter.
81
- */
82
- createAgentWalletAdapter(agentSigner) {
83
- return {
84
- // The agent address is returned for identity purposes: the SDK only uses
85
- // it for local lock/nonce keying (`getWalletAddress`), never inside the
86
- // signed payload — HyperLiquid recovers the signer from the signature.
87
- address: agentSigner.address,
88
- signTypedData: async (params) => {
89
- if (__classPrivateFieldGet(this, _HyperLiquidWalletService_instances, "m", _HyperLiquidWalletService_isL1AgentAction).call(this, params.primaryType, params.domain?.name)) {
90
- const { EIP712Domain: _eip712Domain, ...types } = params.types;
91
- __classPrivateFieldGet(this, _HyperLiquidWalletService_deps, "f").debugLogger.log('HyperLiquidWalletService: Signing typed data (agent mode)', {
92
- address: agentSigner.address,
93
- primaryType: params.primaryType,
94
- });
95
- return (await agentSigner.signTypedData(params.domain, types, params.message));
96
- }
97
- // User-signed action: master-account authorization, must be signed
98
- // by the master wallet (device prompt on hardware).
99
- return __classPrivateFieldGet(this, _HyperLiquidWalletService_instances, "m", _HyperLiquidWalletService_signWithMaster).call(this, params);
100
- },
101
- getChainId: async () => parseInt(getChainId(__classPrivateFieldGet(this, _HyperLiquidWalletService_isTestnet, "f")), 10),
102
- };
103
- }
104
- /**
105
- * Create the master-keyring wallet adapter for the HyperLiquid SDK.
106
- *
107
- * This factory is synchronous and always signs via the selected master
108
- * account. Agent wallets are built separately with
109
- * {@link createAgentWalletAdapter}; the provider selects which adapter the
110
- * SDK clients use.
64
+ * Create wallet adapter that implements AbstractViemJsonRpcAccount interface
65
+ * Required by @nktkas/hyperliquid SDK for signing transactions
111
66
  *
112
67
  * @returns The wallet adapter with address, signTypedData, and getChainId methods.
113
68
  */
@@ -120,7 +75,33 @@ export class HyperLiquidWalletService {
120
75
  const address = evmAccount.address;
121
76
  return {
122
77
  address,
123
- signTypedData: async (params) => __classPrivateFieldGet(this, _HyperLiquidWalletService_instances, "m", _HyperLiquidWalletService_signWithMaster).call(this, params),
78
+ signTypedData: async (params) => {
79
+ // Get FRESH account on every sign to handle account switches
80
+ // This prevents race conditions where wallet adapter was created with old account
81
+ const currentEvmAccount = getSelectedEvmAccountFromMessenger(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f"));
82
+ if (!currentEvmAccount?.address) {
83
+ throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);
84
+ }
85
+ const currentAddress = currentEvmAccount.address;
86
+ // Construct EIP-712 typed data
87
+ const typedData = {
88
+ domain: params.domain,
89
+ types: params.types,
90
+ primaryType: params.primaryType,
91
+ message: params.message,
92
+ };
93
+ __classPrivateFieldGet(this, _HyperLiquidWalletService_deps, "f").debugLogger.log('HyperLiquidWalletService: Signing typed data', {
94
+ address: currentAddress,
95
+ primaryType: params.primaryType,
96
+ domain: params.domain,
97
+ });
98
+ // Use messenger to sign typed data
99
+ const signature = await __classPrivateFieldGet(this, _HyperLiquidWalletService_instances, "m", _HyperLiquidWalletService_signTypedMessage).call(this, {
100
+ from: currentAddress,
101
+ data: typedData,
102
+ });
103
+ return signature;
104
+ },
124
105
  getChainId: async () => parseInt(getChainId(__classPrivateFieldGet(this, _HyperLiquidWalletService_isTestnet, "f")), 10),
125
106
  };
126
107
  }
@@ -197,36 +178,5 @@ async function _HyperLiquidWalletService_signTypedMessage(msgParams) {
197
178
  msgParams,
198
179
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
199
180
  'V4');
200
- }, _HyperLiquidWalletService_signWithMaster =
201
- /**
202
- * Sign typed data with the master account via the keyring, resolving the
203
- * selected account fresh so account switches cannot race the adapter.
204
- *
205
- * @param params - The typed-data signing request the SDK passed to the adapter.
206
- * @returns The signature string.
207
- */
208
- async function _HyperLiquidWalletService_signWithMaster(params) {
209
- const currentEvmAccount = getSelectedEvmAccountFromMessenger(__classPrivateFieldGet(this, _HyperLiquidWalletService_messenger, "f"));
210
- if (!currentEvmAccount?.address) {
211
- throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);
212
- }
213
- const currentAddress = currentEvmAccount.address;
214
- __classPrivateFieldGet(this, _HyperLiquidWalletService_deps, "f").debugLogger.log('HyperLiquidWalletService: Signing typed data (master fallback)', {
215
- address: currentAddress,
216
- primaryType: params.primaryType,
217
- domain: params.domain,
218
- });
219
- const signature = await __classPrivateFieldGet(this, _HyperLiquidWalletService_instances, "m", _HyperLiquidWalletService_signTypedMessage).call(this, {
220
- from: currentAddress,
221
- data: {
222
- domain: params.domain,
223
- types: params.types,
224
- primaryType: params.primaryType,
225
- message: params.message,
226
- },
227
- });
228
- return signature;
229
- }, _HyperLiquidWalletService_isL1AgentAction = function _HyperLiquidWalletService_isL1AgentAction(primaryType, domainName) {
230
- return primaryType === 'Agent' || domainName === 'Exchange';
231
181
  };
232
182
  //# sourceMappingURL=HyperLiquidWalletService.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"HyperLiquidWalletService.mjs","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n hasProperty,\n isValidHexAddress,\n parseCaipAccountId,\n} from '@metamask/utils';\nimport type { CaipAccountId, Hex } from '@metamask/utils';\n\nimport { getChainId } from '../constants/hyperLiquidConfig.js';\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes.js';\nimport type {\n HyperLiquidSignTypedDataParams,\n HyperLiquidWalletParams,\n} from './HyperLiquidClientService.js';\nimport type {\n PerpsPlatformDependencies,\n PerpsTypedMessageParams,\n} from '../types/index.js';\nimport type { PerpsControllerMessengerBase } from '../types/messenger.js';\nimport {\n getSelectedEvmAccountDetailsFromMessenger,\n getSelectedEvmAccountFromMessenger,\n} from '../utils/accountUtils.js';\n\n// Mirrors KeyringTypes from @metamask/keyring-controller. Inlined to keep this\n// service portable between mobile and the core monorepo.\nconst HARDWARE_KEYRING_TYPES = new Set<string>([\n 'Ledger Hardware',\n 'Trezor Hardware',\n 'OneKey Hardware',\n 'Lattice Hardware',\n 'QR Hardware Wallet Device',\n]);\n\n/**\n * A local signer for a HyperLiquid agent account, in the SDK-native\n * `AbstractEthersV6Signer` shape (positional EIP-712 arguments, message as\n * the signed value). Provided by the client (e.g. a local key stored in\n * memory) so agent actions never touch the keyring.\n */\nexport type AgentSigner = {\n /** The agent account address used as the actor for signed actions. */\n address: `0x${string}`;\n /**\n * Sign EIP-712 typed data with the agent key (positional ethers-style\n * arguments; `types` must not include `EIP712Domain`).\n *\n * @param domain - The EIP-712 domain.\n * @param types - The EIP-712 type definitions (without `EIP712Domain`).\n * @param value - The message payload to sign.\n * @returns The hex signature.\n */\n signTypedData(\n domain: HyperLiquidSignTypedDataParams['domain'],\n types: HyperLiquidSignTypedDataParams['types'],\n value: Record<string, unknown>,\n ): Promise<string>;\n};\n\n/**\n * Service for MetaMask wallet integration with HyperLiquid SDK\n * Provides wallet adapter that implements AbstractWindowEthereum interface\n */\nexport class HyperLiquidWalletService {\n #isTestnet: boolean;\n\n // Platform dependencies for observability\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessengerBase;\n\n constructor(\n deps: PerpsPlatformDependencies,\n messenger: PerpsControllerMessengerBase,\n options: { isTestnet?: boolean } = {},\n ) {\n this.#deps = deps;\n this.#messenger = messenger;\n this.#isTestnet = options.isTestnet ?? false;\n }\n\n /**\n * Check if the keyring is currently unlocked\n *\n * @returns True if the keyring is unlocked and available for signing.\n */\n public isKeyringUnlocked(): boolean {\n return this.#messenger.call('KeyringController:getState').isUnlocked;\n }\n\n /**\n * Check whether the selected EVM account is backed by hardware.\n *\n * @returns True for MetaMask hardware keyrings; false for software accounts.\n */\n public isSelectedHardwareWallet(): boolean {\n const selectedEvmAccount = getSelectedEvmAccountDetailsFromMessenger(\n this.#messenger,\n );\n if (!selectedEvmAccount || !hasProperty(selectedEvmAccount, 'metadata')) {\n return false;\n }\n\n const metadata = selectedEvmAccount.metadata as\n | { keyring?: { type?: string } }\n | undefined;\n const keyringType = metadata?.keyring?.type;\n\n return Boolean(keyringType && HARDWARE_KEYRING_TYPES.has(keyringType));\n }\n\n /**\n * Sign typed data via DI keyring controller\n *\n * @param msgParams - The typed message parameters including data and sender address.\n * @returns The signature string.\n */\n async #signTypedMessage(msgParams: PerpsTypedMessageParams): Promise<string> {\n if (!this.isKeyringUnlocked()) {\n throw new Error(PERPS_ERROR_CODES.KEYRING_LOCKED);\n }\n // Cast needed: PerpsTypedMessageParams uses loose `data: unknown` type\n // while KeyringController uses strict TypedMessageParams / SignTypedDataVersion\n return this.#messenger.call(\n 'KeyringController:signTypedMessage',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n msgParams as any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n 'V4' as any,\n );\n }\n\n /**\n * Sign typed data with the master account via the keyring, resolving the\n * selected account fresh so account switches cannot race the adapter.\n *\n * @param params - The typed-data signing request the SDK passed to the adapter.\n * @returns The signature string.\n */\n async #signWithMaster(params: HyperLiquidSignTypedDataParams): Promise<Hex> {\n const currentEvmAccount = getSelectedEvmAccountFromMessenger(\n this.#messenger,\n );\n\n if (!currentEvmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const currentAddress = currentEvmAccount.address as Hex;\n\n this.#deps.debugLogger.log(\n 'HyperLiquidWalletService: Signing typed data (master fallback)',\n {\n address: currentAddress,\n primaryType: params.primaryType,\n domain: params.domain,\n },\n );\n\n const signature = await this.#signTypedMessage({\n from: currentAddress,\n data: {\n domain: params.domain,\n types: params.types,\n primaryType: params.primaryType,\n message: params.message,\n },\n });\n\n return signature as Hex;\n }\n\n /**\n * Whether a typed-data signing request is an L1 (phantom-agent) action.\n *\n * The HyperLiquid SDK signs L1 actions (order/cancel/modify/TWAP/leverage/\n * margin/agentSetAbstraction) with EIP-712 primaryType `Agent` over domain\n * `{ name: \"Exchange\", version: \"1\", chainId: 1337 }`. Only these may be\n * signed by an agent key; every other shape (e.g. `approveBuilderFee`,\n * `userSetAbstraction`, `sendAsset`, `withdraw3` over the\n * `HyperliquidSignTransaction` domain) is a user-signed action that\n * authorizes the master account and must be signed by the master wallet.\n *\n * @param primaryType - The EIP-712 primary type of the signing request.\n * @param domainName - The EIP-712 domain name of the signing request.\n * @returns True when the request belongs to the agent-signable L1 class.\n */\n #isL1AgentAction(primaryType: string, domainName?: string): boolean {\n return primaryType === 'Agent' || domainName === 'Exchange';\n }\n\n /**\n * Create a wallet adapter backed by a local agent signer.\n *\n * The returned adapter keeps the params-style `signTypedData` shape the SDK\n * already accepts (viem local account), but routes by typed-data shape:\n * L1 (phantom-agent) actions — primaryType `Agent` over the `Exchange`\n * domain — are signed directly by the injected local signer with no keyring\n * contact; user-signed actions (`approveBuilderFee`, `userSetAbstraction`,\n * `sendAsset`, `withdraw3`, … over the `HyperliquidSignTransaction` domain)\n * are master-account authorizations and fall through to the master keyring\n * signing path, so hardware users get the normal device prompt. The SDK's\n * viem adapters inject an `EIP712Domain` entry into `types` before calling\n * params-style wallets; ethers-style signers reject that entry, so it is\n * stripped before delegating to the agent signer (the master path passes\n * `types` through unchanged, matching the pre-seam master adapter).\n *\n * @param agentSigner - The local agent signer to delegate L1 actions to.\n * @returns The agent wallet adapter.\n */\n public createAgentWalletAdapter(\n agentSigner: AgentSigner,\n ): HyperLiquidWalletParams {\n return {\n // The agent address is returned for identity purposes: the SDK only uses\n // it for local lock/nonce keying (`getWalletAddress`), never inside the\n // signed payload — HyperLiquid recovers the signer from the signature.\n address: agentSigner.address,\n signTypedData: async (\n params: HyperLiquidSignTypedDataParams,\n ): Promise<Hex> => {\n if (this.#isL1AgentAction(params.primaryType, params.domain?.name)) {\n const { EIP712Domain: _eip712Domain, ...types } = params.types;\n\n this.#deps.debugLogger.log(\n 'HyperLiquidWalletService: Signing typed data (agent mode)',\n {\n address: agentSigner.address,\n primaryType: params.primaryType,\n },\n );\n\n return (await agentSigner.signTypedData(\n params.domain,\n types,\n params.message,\n )) as Hex;\n }\n\n // User-signed action: master-account authorization, must be signed\n // by the master wallet (device prompt on hardware).\n return this.#signWithMaster(params);\n },\n getChainId: async (): Promise<number> =>\n parseInt(getChainId(this.#isTestnet), 10),\n };\n }\n\n /**\n * Create the master-keyring wallet adapter for the HyperLiquid SDK.\n *\n * This factory is synchronous and always signs via the selected master\n * account. Agent wallets are built separately with\n * {@link createAgentWalletAdapter}; the provider selects which adapter the\n * SDK clients use.\n *\n * @returns The wallet adapter with address, signTypedData, and getChainId methods.\n */\n public createWalletAdapter(): HyperLiquidWalletParams {\n // Get current EVM account via DI messenger\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const address = evmAccount.address as Hex;\n\n return {\n address,\n signTypedData: async (\n params: HyperLiquidSignTypedDataParams,\n ): Promise<Hex> => this.#signWithMaster(params),\n getChainId: async (): Promise<number> =>\n parseInt(getChainId(this.#isTestnet), 10),\n };\n }\n\n /**\n * Get current account ID using messenger\n *\n * @returns The CAIP account ID for the current EVM account.\n */\n public async getCurrentAccountId(): Promise<CaipAccountId> {\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const chainId = getChainId(this.#isTestnet);\n const caipAccountId: CaipAccountId = `eip155:${chainId}:${evmAccount.address}`;\n\n return caipAccountId;\n }\n\n /**\n * Get validated user address as Hex from account ID\n *\n * @param accountId - The CAIP account ID to extract the address from.\n * @returns The validated hex address.\n */\n public getUserAddress(accountId: CaipAccountId): Hex {\n const parsed = parseCaipAccountId(accountId);\n const address = parsed.address as Hex;\n\n if (!isValidHexAddress(address)) {\n throw new Error(PERPS_ERROR_CODES.INVALID_ADDRESS_FORMAT);\n }\n\n return address;\n }\n\n /**\n * Get user address with default fallback to current account\n *\n * @param accountId - Optional CAIP account ID; defaults to current account if omitted.\n * @returns The validated hex address.\n */\n public async getUserAddressWithDefault(\n accountId?: CaipAccountId,\n ): Promise<Hex> {\n const id = accountId ?? (await this.getCurrentAccountId());\n return this.getUserAddress(id);\n }\n\n /**\n * Update testnet mode\n *\n * @param isTestnet - Whether to enable testnet mode.\n */\n public setTestnetMode(isTestnet: boolean): void {\n this.#isTestnet = isTestnet;\n }\n\n /**\n * Check if running on testnet\n *\n * @returns True if the service is in testnet mode.\n */\n public isTestnetMode(): boolean {\n return this.#isTestnet;\n }\n}\n"]}
1
+ {"version":3,"file":"HyperLiquidWalletService.mjs","sourceRoot":"","sources":["../../src/services/HyperLiquidWalletService.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n hasProperty,\n isValidHexAddress,\n parseCaipAccountId,\n} from '@metamask/utils';\nimport type { CaipAccountId, Hex } from '@metamask/utils';\n\nimport { getChainId } from '../constants/hyperLiquidConfig.js';\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes.js';\nimport type {\n PerpsPlatformDependencies,\n PerpsTypedMessageParams,\n} from '../types/index.js';\nimport type { PerpsControllerMessengerBase } from '../types/messenger.js';\nimport {\n getSelectedEvmAccountDetailsFromMessenger,\n getSelectedEvmAccountFromMessenger,\n} from '../utils/accountUtils.js';\n\n// Mirrors KeyringTypes from @metamask/keyring-controller. Inlined to keep this\n// service portable between mobile and the core monorepo.\nconst HARDWARE_KEYRING_TYPES = new Set<string>([\n 'Ledger Hardware',\n 'Trezor Hardware',\n 'OneKey Hardware',\n 'Lattice Hardware',\n 'QR Hardware Wallet Device',\n]);\n\n/**\n * Service for MetaMask wallet integration with HyperLiquid SDK\n * Provides wallet adapter that implements AbstractWindowEthereum interface\n */\nexport class HyperLiquidWalletService {\n #isTestnet: boolean;\n\n // Platform dependencies for observability\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessengerBase;\n\n constructor(\n deps: PerpsPlatformDependencies,\n messenger: PerpsControllerMessengerBase,\n options: { isTestnet?: boolean } = {},\n ) {\n this.#deps = deps;\n this.#messenger = messenger;\n this.#isTestnet = options.isTestnet ?? false;\n }\n\n /**\n * Check if the keyring is currently unlocked\n *\n * @returns True if the keyring is unlocked and available for signing.\n */\n public isKeyringUnlocked(): boolean {\n return this.#messenger.call('KeyringController:getState').isUnlocked;\n }\n\n /**\n * Check whether the selected EVM account is backed by hardware.\n *\n * @returns True for MetaMask hardware keyrings; false for software accounts.\n */\n public isSelectedHardwareWallet(): boolean {\n const selectedEvmAccount = getSelectedEvmAccountDetailsFromMessenger(\n this.#messenger,\n );\n if (!selectedEvmAccount || !hasProperty(selectedEvmAccount, 'metadata')) {\n return false;\n }\n\n const metadata = selectedEvmAccount.metadata as\n | { keyring?: { type?: string } }\n | undefined;\n const keyringType = metadata?.keyring?.type;\n\n return Boolean(keyringType && HARDWARE_KEYRING_TYPES.has(keyringType));\n }\n\n /**\n * Sign typed data via DI keyring controller\n *\n * @param msgParams - The typed message parameters including data and sender address.\n * @returns The signature string.\n */\n async #signTypedMessage(msgParams: PerpsTypedMessageParams): Promise<string> {\n if (!this.isKeyringUnlocked()) {\n throw new Error(PERPS_ERROR_CODES.KEYRING_LOCKED);\n }\n // Cast needed: PerpsTypedMessageParams uses loose `data: unknown` type\n // while KeyringController uses strict TypedMessageParams / SignTypedDataVersion\n return this.#messenger.call(\n 'KeyringController:signTypedMessage',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n msgParams as any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n 'V4' as any,\n );\n }\n\n /**\n * Create wallet adapter that implements AbstractViemJsonRpcAccount interface\n * Required by @nktkas/hyperliquid SDK for signing transactions\n *\n * @returns The wallet adapter with address, signTypedData, and getChainId methods.\n */\n public createWalletAdapter(): {\n address: Hex;\n signTypedData: (params: {\n domain: {\n name: string;\n version: string;\n chainId: number;\n verifyingContract: Hex;\n };\n types: {\n [key: string]: { name: string; type: string }[];\n };\n primaryType: string;\n message: Record<string, unknown>;\n }) => Promise<Hex>;\n getChainId?: () => Promise<number>;\n } {\n // Get current EVM account via DI messenger\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const address = evmAccount.address as Hex;\n\n return {\n address,\n signTypedData: async (params: {\n domain: {\n name: string;\n version: string;\n chainId: number;\n verifyingContract: Hex;\n };\n types: {\n [key: string]: { name: string; type: string }[];\n };\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<Hex> => {\n // Get FRESH account on every sign to handle account switches\n // This prevents race conditions where wallet adapter was created with old account\n const currentEvmAccount = getSelectedEvmAccountFromMessenger(\n this.#messenger,\n );\n\n if (!currentEvmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const currentAddress = currentEvmAccount.address as Hex;\n\n // Construct EIP-712 typed data\n const typedData = {\n domain: params.domain,\n types: params.types,\n primaryType: params.primaryType,\n message: params.message,\n };\n\n this.#deps.debugLogger.log(\n 'HyperLiquidWalletService: Signing typed data',\n {\n address: currentAddress,\n primaryType: params.primaryType,\n domain: params.domain,\n },\n );\n\n // Use messenger to sign typed data\n const signature = await this.#signTypedMessage({\n from: currentAddress,\n data: typedData,\n });\n\n return signature as Hex;\n },\n getChainId: async (): Promise<number> =>\n parseInt(getChainId(this.#isTestnet), 10),\n };\n }\n\n /**\n * Get current account ID using messenger\n *\n * @returns The CAIP account ID for the current EVM account.\n */\n public async getCurrentAccountId(): Promise<CaipAccountId> {\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n const chainId = getChainId(this.#isTestnet);\n const caipAccountId: CaipAccountId = `eip155:${chainId}:${evmAccount.address}`;\n\n return caipAccountId;\n }\n\n /**\n * Get validated user address as Hex from account ID\n *\n * @param accountId - The CAIP account ID to extract the address from.\n * @returns The validated hex address.\n */\n public getUserAddress(accountId: CaipAccountId): Hex {\n const parsed = parseCaipAccountId(accountId);\n const address = parsed.address as Hex;\n\n if (!isValidHexAddress(address)) {\n throw new Error(PERPS_ERROR_CODES.INVALID_ADDRESS_FORMAT);\n }\n\n return address;\n }\n\n /**\n * Get user address with default fallback to current account\n *\n * @param accountId - Optional CAIP account ID; defaults to current account if omitted.\n * @returns The validated hex address.\n */\n public async getUserAddressWithDefault(\n accountId?: CaipAccountId,\n ): Promise<Hex> {\n const id = accountId ?? (await this.getCurrentAccountId());\n return this.getUserAddress(id);\n }\n\n /**\n * Update testnet mode\n *\n * @param isTestnet - Whether to enable testnet mode.\n */\n public setTestnetMode(isTestnet: boolean): void {\n this.#isTestnet = isTestnet;\n }\n\n /**\n * Check if running on testnet\n *\n * @returns True if the service is in testnet mode.\n */\n public isTestnetMode(): boolean {\n return this.#isTestnet;\n }\n}\n"]}
@@ -14,7 +14,7 @@
14
14
  * 2. Venue-key (Schnorr/ECgFp5) signatures over L2 transactions, produced
15
15
  * inside the injected signer bridge from client-managed key material.
16
16
  *
17
- * Signature routing goes through
17
+ * Signature routing mirrors MYXWalletService: through
18
18
  * `KeyringController:signPersonalMessage` when a messenger is available,
19
19
  * or through an injected `LighterPersonalSigner` for headless use.
20
20
  */
@@ -1 +1 @@
1
- {"version":3,"file":"LighterWalletService.cjs","sourceRoot":"","sources":["../../src/services/LighterWalletService.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;;;;;;;;;;;;;AAEH,2CAA6C;AAI7C,+DAA0D;AAM1D,+DAA8E;AAE9E,MAAa,oBAAoB;IAW/B,YACE,IAA+B,EAC/B,UAKI,EAAE;QAjBR,kDAAoB;QAEX,6CAAiC;QAEjC,kDAAiD;QAEjD,uDAAmD;QAEnD,kDAA+B;QAWtC,uBAAA,IAAI,8BAAS,IAAI,MAAA,CAAC;QAClB,uBAAA,IAAI,mCAAc,OAAO,CAAC,SAAS,MAAA,CAAC;QACpC,uBAAA,IAAI,wCAAmB,OAAO,CAAC,cAAc,MAAA,CAAC;QAC9C,uBAAA,IAAI,mCAAc,OAAO,CAAC,SAAS,MAAA,CAAC;QACpC,uBAAA,IAAI,mCAAc,OAAO,CAAC,SAAS,IAAI,IAAI,MAAA,CAAC;IAC9C,CAAC;IAED,IAAI,OAAO;QACT,OAAO,uBAAA,IAAI,uCAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IACjD,CAAC;IAED;;;;OAIG;IACH,cAAc;QACZ,IAAI,uBAAA,IAAI,uCAAW,EAAE,CAAC;YACpB,MAAM,UAAU,GAAG,IAAA,oDAAkC,EAAC,uBAAA,IAAI,uCAAW,CAAC,CAAC;YACvE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,sCAAiB,CAAC,mBAAmB,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,UAAU,CAAC,OAAO,CAAC;QAC5B,CAAC;QACD,IAAI,uBAAA,IAAI,uCAAW,EAAE,CAAC;YACpB,OAAO,uBAAA,IAAI,uCAAW,CAAC;QACzB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,sCAAiB,CAAC,mBAAmB,CAAC,CAAC;IACzD,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,mBAAmB,CAAC,OAAe;QACvC,IAAI,uBAAA,IAAI,uCAAW,EAAE,CAAC;YACpB,MAAM,EAAE,UAAU,EAAE,GAAG,uBAAA,IAAI,uCAAW,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;YAC1E,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,sCAAiB,CAAC,cAAc,CAAC,CAAC;YACpD,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,EAAS,CAAC;YAC7C,uBAAA,IAAI,kCAAM,CAAC,WAAW,CAAC,GAAG,CAAC,qCAAqC,EAAE;gBAChE,OAAO;aACR,CAAC,CAAC;YACH,kEAAkE;YAClE,MAAM,IAAI,GAAG,IAAA,kBAAU,EAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YAC3D,OAAO,MAAM,uBAAA,IAAI,uCAAW,CAAC,IAAI,CAC/B,uCAAuC,EACvC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CACxB,CAAC;QACJ,CAAC;QAED,IAAI,uBAAA,IAAI,4CAAgB,EAAE,CAAC;YACzB,OAAO,MAAM,uBAAA,IAAI,4CAAgB,MAApB,IAAI,EAAiB,OAAO,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,sCAAiB,CAAC,mBAAmB,CAAC,CAAC;IACzD,CAAC;IAEM,cAAc,CAAC,SAAkB;QACtC,uBAAA,IAAI,mCAAc,SAAS,MAAA,CAAC;IAC9B,CAAC;IAEM,aAAa;QAClB,OAAO,uBAAA,IAAI,uCAAW,CAAC;IACzB,CAAC;CACF;AA3FD,oDA2FC","sourcesContent":["/**\n * LighterWalletService\n *\n * Routes the L1 signatures Lighter requires. The client-owned signer bridge\n * creates and stores the venue key; Core never receives its seed or private\n * key.\n *\n * Lighter's protocol needs two kinds of signatures:\n * 1. An EIP-191 `personal_sign` over the ChangePubKey plaintext produced by\n * the WASM signer — this registers the venue key on the account. The\n * signature is injected into the L2 transaction (`L1Sig`); the raw EVM\n * private key is never required, so hardware wallets are supported.\n * 2. Venue-key (Schnorr/ECgFp5) signatures over L2 transactions, produced\n * inside the injected signer bridge from client-managed key material.\n *\n * Signature routing goes through\n * `KeyringController:signPersonalMessage` when a messenger is available,\n * or through an injected `LighterPersonalSigner` for headless use.\n */\n\nimport { bytesToHex } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type { PerpsControllerMessenger } from '../PerpsController.js';\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes.js';\nimport type { PerpsPlatformDependencies } from '../types/index.js';\nimport type {\n LighterNetwork,\n LighterPersonalSigner,\n} from '../types/lighter-types.js';\nimport { getSelectedEvmAccountFromMessenger } from '../utils/accountUtils.js';\n\nexport class LighterWalletService {\n #isTestnet: boolean;\n\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessenger | undefined;\n\n readonly #personalSigner: LighterPersonalSigner | undefined;\n\n readonly #l1Address: string | undefined;\n\n constructor(\n deps: PerpsPlatformDependencies,\n options: {\n isTestnet?: boolean;\n messenger?: PerpsControllerMessenger;\n personalSigner?: LighterPersonalSigner;\n l1Address?: string;\n } = {},\n ) {\n this.#deps = deps;\n this.#messenger = options.messenger;\n this.#personalSigner = options.personalSigner;\n this.#l1Address = options.l1Address;\n this.#isTestnet = options.isTestnet ?? true;\n }\n\n get network(): LighterNetwork {\n return this.#isTestnet ? 'testnet' : 'mainnet';\n }\n\n /**\n * Resolve the L1 address whose account owns the Lighter account.\n *\n * @returns The EVM address.\n */\n getUserAddress(): string {\n if (this.#messenger) {\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n return evmAccount.address;\n }\n if (this.#l1Address) {\n return this.#l1Address;\n }\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n /**\n * Sign an EIP-191 personal message with the user's L1 account.\n *\n * Routes through the keyring when a messenger is present, else the\n * injected headless signer.\n *\n * @param message - Plaintext message to sign.\n * @returns 65-byte signature as 0x-prefixed hex.\n */\n async signPersonalMessage(message: string): Promise<string> {\n if (this.#messenger) {\n const { isUnlocked } = this.#messenger.call('KeyringController:getState');\n if (!isUnlocked) {\n throw new Error(PERPS_ERROR_CODES.KEYRING_LOCKED);\n }\n const address = this.getUserAddress() as Hex;\n this.#deps.debugLogger.log('LighterWalletService: personal_sign', {\n address,\n });\n // KeyringController:signPersonalMessage expects hex-encoded data.\n const data = bytesToHex(new TextEncoder().encode(message));\n return await this.#messenger.call(\n 'KeyringController:signPersonalMessage',\n { from: address, data },\n );\n }\n\n if (this.#personalSigner) {\n return await this.#personalSigner(message);\n }\n\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n public setTestnetMode(isTestnet: boolean): void {\n this.#isTestnet = isTestnet;\n }\n\n public isTestnetMode(): boolean {\n return this.#isTestnet;\n }\n}\n"]}
1
+ {"version":3,"file":"LighterWalletService.cjs","sourceRoot":"","sources":["../../src/services/LighterWalletService.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;;;;;;;;;;;;;AAEH,2CAA6C;AAI7C,+DAA0D;AAM1D,+DAA8E;AAE9E,MAAa,oBAAoB;IAW/B,YACE,IAA+B,EAC/B,UAKI,EAAE;QAjBR,kDAAoB;QAEX,6CAAiC;QAEjC,kDAAiD;QAEjD,uDAAmD;QAEnD,kDAA+B;QAWtC,uBAAA,IAAI,8BAAS,IAAI,MAAA,CAAC;QAClB,uBAAA,IAAI,mCAAc,OAAO,CAAC,SAAS,MAAA,CAAC;QACpC,uBAAA,IAAI,wCAAmB,OAAO,CAAC,cAAc,MAAA,CAAC;QAC9C,uBAAA,IAAI,mCAAc,OAAO,CAAC,SAAS,MAAA,CAAC;QACpC,uBAAA,IAAI,mCAAc,OAAO,CAAC,SAAS,IAAI,IAAI,MAAA,CAAC;IAC9C,CAAC;IAED,IAAI,OAAO;QACT,OAAO,uBAAA,IAAI,uCAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IACjD,CAAC;IAED;;;;OAIG;IACH,cAAc;QACZ,IAAI,uBAAA,IAAI,uCAAW,EAAE,CAAC;YACpB,MAAM,UAAU,GAAG,IAAA,oDAAkC,EAAC,uBAAA,IAAI,uCAAW,CAAC,CAAC;YACvE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,sCAAiB,CAAC,mBAAmB,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,UAAU,CAAC,OAAO,CAAC;QAC5B,CAAC;QACD,IAAI,uBAAA,IAAI,uCAAW,EAAE,CAAC;YACpB,OAAO,uBAAA,IAAI,uCAAW,CAAC;QACzB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,sCAAiB,CAAC,mBAAmB,CAAC,CAAC;IACzD,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,mBAAmB,CAAC,OAAe;QACvC,IAAI,uBAAA,IAAI,uCAAW,EAAE,CAAC;YACpB,MAAM,EAAE,UAAU,EAAE,GAAG,uBAAA,IAAI,uCAAW,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;YAC1E,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,sCAAiB,CAAC,cAAc,CAAC,CAAC;YACpD,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,EAAS,CAAC;YAC7C,uBAAA,IAAI,kCAAM,CAAC,WAAW,CAAC,GAAG,CAAC,qCAAqC,EAAE;gBAChE,OAAO;aACR,CAAC,CAAC;YACH,kEAAkE;YAClE,MAAM,IAAI,GAAG,IAAA,kBAAU,EAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YAC3D,OAAO,MAAM,uBAAA,IAAI,uCAAW,CAAC,IAAI,CAC/B,uCAAuC,EACvC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CACxB,CAAC;QACJ,CAAC;QAED,IAAI,uBAAA,IAAI,4CAAgB,EAAE,CAAC;YACzB,OAAO,MAAM,uBAAA,IAAI,4CAAgB,MAApB,IAAI,EAAiB,OAAO,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,sCAAiB,CAAC,mBAAmB,CAAC,CAAC;IACzD,CAAC;IAEM,cAAc,CAAC,SAAkB;QACtC,uBAAA,IAAI,mCAAc,SAAS,MAAA,CAAC;IAC9B,CAAC;IAEM,aAAa;QAClB,OAAO,uBAAA,IAAI,uCAAW,CAAC;IACzB,CAAC;CACF;AA3FD,oDA2FC","sourcesContent":["/**\n * LighterWalletService\n *\n * Routes the L1 signatures Lighter requires. The client-owned signer bridge\n * creates and stores the venue key; Core never receives its seed or private\n * key.\n *\n * Lighter's protocol needs two kinds of signatures:\n * 1. An EIP-191 `personal_sign` over the ChangePubKey plaintext produced by\n * the WASM signer — this registers the venue key on the account. The\n * signature is injected into the L2 transaction (`L1Sig`); the raw EVM\n * private key is never required, so hardware wallets are supported.\n * 2. Venue-key (Schnorr/ECgFp5) signatures over L2 transactions, produced\n * inside the injected signer bridge from client-managed key material.\n *\n * Signature routing mirrors MYXWalletService: through\n * `KeyringController:signPersonalMessage` when a messenger is available,\n * or through an injected `LighterPersonalSigner` for headless use.\n */\n\nimport { bytesToHex } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type { PerpsControllerMessenger } from '../PerpsController.js';\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes.js';\nimport type { PerpsPlatformDependencies } from '../types/index.js';\nimport type {\n LighterNetwork,\n LighterPersonalSigner,\n} from '../types/lighter-types.js';\nimport { getSelectedEvmAccountFromMessenger } from '../utils/accountUtils.js';\n\nexport class LighterWalletService {\n #isTestnet: boolean;\n\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessenger | undefined;\n\n readonly #personalSigner: LighterPersonalSigner | undefined;\n\n readonly #l1Address: string | undefined;\n\n constructor(\n deps: PerpsPlatformDependencies,\n options: {\n isTestnet?: boolean;\n messenger?: PerpsControllerMessenger;\n personalSigner?: LighterPersonalSigner;\n l1Address?: string;\n } = {},\n ) {\n this.#deps = deps;\n this.#messenger = options.messenger;\n this.#personalSigner = options.personalSigner;\n this.#l1Address = options.l1Address;\n this.#isTestnet = options.isTestnet ?? true;\n }\n\n get network(): LighterNetwork {\n return this.#isTestnet ? 'testnet' : 'mainnet';\n }\n\n /**\n * Resolve the L1 address whose account owns the Lighter account.\n *\n * @returns The EVM address.\n */\n getUserAddress(): string {\n if (this.#messenger) {\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n return evmAccount.address;\n }\n if (this.#l1Address) {\n return this.#l1Address;\n }\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n /**\n * Sign an EIP-191 personal message with the user's L1 account.\n *\n * Routes through the keyring when a messenger is present, else the\n * injected headless signer.\n *\n * @param message - Plaintext message to sign.\n * @returns 65-byte signature as 0x-prefixed hex.\n */\n async signPersonalMessage(message: string): Promise<string> {\n if (this.#messenger) {\n const { isUnlocked } = this.#messenger.call('KeyringController:getState');\n if (!isUnlocked) {\n throw new Error(PERPS_ERROR_CODES.KEYRING_LOCKED);\n }\n const address = this.getUserAddress() as Hex;\n this.#deps.debugLogger.log('LighterWalletService: personal_sign', {\n address,\n });\n // KeyringController:signPersonalMessage expects hex-encoded data.\n const data = bytesToHex(new TextEncoder().encode(message));\n return await this.#messenger.call(\n 'KeyringController:signPersonalMessage',\n { from: address, data },\n );\n }\n\n if (this.#personalSigner) {\n return await this.#personalSigner(message);\n }\n\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n public setTestnetMode(isTestnet: boolean): void {\n this.#isTestnet = isTestnet;\n }\n\n public isTestnetMode(): boolean {\n return this.#isTestnet;\n }\n}\n"]}
@@ -13,7 +13,7 @@
13
13
  * 2. Venue-key (Schnorr/ECgFp5) signatures over L2 transactions, produced
14
14
  * inside the injected signer bridge from client-managed key material.
15
15
  *
16
- * Signature routing goes through
16
+ * Signature routing mirrors MYXWalletService: through
17
17
  * `KeyringController:signPersonalMessage` when a messenger is available,
18
18
  * or through an injected `LighterPersonalSigner` for headless use.
19
19
  */
@@ -13,7 +13,7 @@
13
13
  * 2. Venue-key (Schnorr/ECgFp5) signatures over L2 transactions, produced
14
14
  * inside the injected signer bridge from client-managed key material.
15
15
  *
16
- * Signature routing goes through
16
+ * Signature routing mirrors MYXWalletService: through
17
17
  * `KeyringController:signPersonalMessage` when a messenger is available,
18
18
  * or through an injected `LighterPersonalSigner` for headless use.
19
19
  */
@@ -13,7 +13,7 @@
13
13
  * 2. Venue-key (Schnorr/ECgFp5) signatures over L2 transactions, produced
14
14
  * inside the injected signer bridge from client-managed key material.
15
15
  *
16
- * Signature routing goes through
16
+ * Signature routing mirrors MYXWalletService: through
17
17
  * `KeyringController:signPersonalMessage` when a messenger is available,
18
18
  * or through an injected `LighterPersonalSigner` for headless use.
19
19
  */
@@ -1 +1 @@
1
- {"version":3,"file":"LighterWalletService.mjs","sourceRoot":"","sources":["../../src/services/LighterWalletService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;;;;;;;;;;;AAEH,OAAO,EAAE,UAAU,EAAE,wBAAwB;AAI7C,OAAO,EAAE,iBAAiB,EAAE,+BAA8B;AAM1D,OAAO,EAAE,kCAAkC,EAAE,kCAAiC;AAE9E,MAAM,OAAO,oBAAoB;IAW/B,YACE,IAA+B,EAC/B,UAKI,EAAE;QAjBR,kDAAoB;QAEX,6CAAiC;QAEjC,kDAAiD;QAEjD,uDAAmD;QAEnD,kDAA+B;QAWtC,uBAAA,IAAI,8BAAS,IAAI,MAAA,CAAC;QAClB,uBAAA,IAAI,mCAAc,OAAO,CAAC,SAAS,MAAA,CAAC;QACpC,uBAAA,IAAI,wCAAmB,OAAO,CAAC,cAAc,MAAA,CAAC;QAC9C,uBAAA,IAAI,mCAAc,OAAO,CAAC,SAAS,MAAA,CAAC;QACpC,uBAAA,IAAI,mCAAc,OAAO,CAAC,SAAS,IAAI,IAAI,MAAA,CAAC;IAC9C,CAAC;IAED,IAAI,OAAO;QACT,OAAO,uBAAA,IAAI,uCAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IACjD,CAAC;IAED;;;;OAIG;IACH,cAAc;QACZ,IAAI,uBAAA,IAAI,uCAAW,EAAE,CAAC;YACpB,MAAM,UAAU,GAAG,kCAAkC,CAAC,uBAAA,IAAI,uCAAW,CAAC,CAAC;YACvE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,UAAU,CAAC,OAAO,CAAC;QAC5B,CAAC;QACD,IAAI,uBAAA,IAAI,uCAAW,EAAE,CAAC;YACpB,OAAO,uBAAA,IAAI,uCAAW,CAAC;QACzB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;IACzD,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,mBAAmB,CAAC,OAAe;QACvC,IAAI,uBAAA,IAAI,uCAAW,EAAE,CAAC;YACpB,MAAM,EAAE,UAAU,EAAE,GAAG,uBAAA,IAAI,uCAAW,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;YAC1E,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;YACpD,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,EAAS,CAAC;YAC7C,uBAAA,IAAI,kCAAM,CAAC,WAAW,CAAC,GAAG,CAAC,qCAAqC,EAAE;gBAChE,OAAO;aACR,CAAC,CAAC;YACH,kEAAkE;YAClE,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YAC3D,OAAO,MAAM,uBAAA,IAAI,uCAAW,CAAC,IAAI,CAC/B,uCAAuC,EACvC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CACxB,CAAC;QACJ,CAAC;QAED,IAAI,uBAAA,IAAI,4CAAgB,EAAE,CAAC;YACzB,OAAO,MAAM,uBAAA,IAAI,4CAAgB,MAApB,IAAI,EAAiB,OAAO,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;IACzD,CAAC;IAEM,cAAc,CAAC,SAAkB;QACtC,uBAAA,IAAI,mCAAc,SAAS,MAAA,CAAC;IAC9B,CAAC;IAEM,aAAa;QAClB,OAAO,uBAAA,IAAI,uCAAW,CAAC;IACzB,CAAC;CACF","sourcesContent":["/**\n * LighterWalletService\n *\n * Routes the L1 signatures Lighter requires. The client-owned signer bridge\n * creates and stores the venue key; Core never receives its seed or private\n * key.\n *\n * Lighter's protocol needs two kinds of signatures:\n * 1. An EIP-191 `personal_sign` over the ChangePubKey plaintext produced by\n * the WASM signer — this registers the venue key on the account. The\n * signature is injected into the L2 transaction (`L1Sig`); the raw EVM\n * private key is never required, so hardware wallets are supported.\n * 2. Venue-key (Schnorr/ECgFp5) signatures over L2 transactions, produced\n * inside the injected signer bridge from client-managed key material.\n *\n * Signature routing goes through\n * `KeyringController:signPersonalMessage` when a messenger is available,\n * or through an injected `LighterPersonalSigner` for headless use.\n */\n\nimport { bytesToHex } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type { PerpsControllerMessenger } from '../PerpsController.js';\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes.js';\nimport type { PerpsPlatformDependencies } from '../types/index.js';\nimport type {\n LighterNetwork,\n LighterPersonalSigner,\n} from '../types/lighter-types.js';\nimport { getSelectedEvmAccountFromMessenger } from '../utils/accountUtils.js';\n\nexport class LighterWalletService {\n #isTestnet: boolean;\n\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessenger | undefined;\n\n readonly #personalSigner: LighterPersonalSigner | undefined;\n\n readonly #l1Address: string | undefined;\n\n constructor(\n deps: PerpsPlatformDependencies,\n options: {\n isTestnet?: boolean;\n messenger?: PerpsControllerMessenger;\n personalSigner?: LighterPersonalSigner;\n l1Address?: string;\n } = {},\n ) {\n this.#deps = deps;\n this.#messenger = options.messenger;\n this.#personalSigner = options.personalSigner;\n this.#l1Address = options.l1Address;\n this.#isTestnet = options.isTestnet ?? true;\n }\n\n get network(): LighterNetwork {\n return this.#isTestnet ? 'testnet' : 'mainnet';\n }\n\n /**\n * Resolve the L1 address whose account owns the Lighter account.\n *\n * @returns The EVM address.\n */\n getUserAddress(): string {\n if (this.#messenger) {\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n return evmAccount.address;\n }\n if (this.#l1Address) {\n return this.#l1Address;\n }\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n /**\n * Sign an EIP-191 personal message with the user's L1 account.\n *\n * Routes through the keyring when a messenger is present, else the\n * injected headless signer.\n *\n * @param message - Plaintext message to sign.\n * @returns 65-byte signature as 0x-prefixed hex.\n */\n async signPersonalMessage(message: string): Promise<string> {\n if (this.#messenger) {\n const { isUnlocked } = this.#messenger.call('KeyringController:getState');\n if (!isUnlocked) {\n throw new Error(PERPS_ERROR_CODES.KEYRING_LOCKED);\n }\n const address = this.getUserAddress() as Hex;\n this.#deps.debugLogger.log('LighterWalletService: personal_sign', {\n address,\n });\n // KeyringController:signPersonalMessage expects hex-encoded data.\n const data = bytesToHex(new TextEncoder().encode(message));\n return await this.#messenger.call(\n 'KeyringController:signPersonalMessage',\n { from: address, data },\n );\n }\n\n if (this.#personalSigner) {\n return await this.#personalSigner(message);\n }\n\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n public setTestnetMode(isTestnet: boolean): void {\n this.#isTestnet = isTestnet;\n }\n\n public isTestnetMode(): boolean {\n return this.#isTestnet;\n }\n}\n"]}
1
+ {"version":3,"file":"LighterWalletService.mjs","sourceRoot":"","sources":["../../src/services/LighterWalletService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;;;;;;;;;;;AAEH,OAAO,EAAE,UAAU,EAAE,wBAAwB;AAI7C,OAAO,EAAE,iBAAiB,EAAE,+BAA8B;AAM1D,OAAO,EAAE,kCAAkC,EAAE,kCAAiC;AAE9E,MAAM,OAAO,oBAAoB;IAW/B,YACE,IAA+B,EAC/B,UAKI,EAAE;QAjBR,kDAAoB;QAEX,6CAAiC;QAEjC,kDAAiD;QAEjD,uDAAmD;QAEnD,kDAA+B;QAWtC,uBAAA,IAAI,8BAAS,IAAI,MAAA,CAAC;QAClB,uBAAA,IAAI,mCAAc,OAAO,CAAC,SAAS,MAAA,CAAC;QACpC,uBAAA,IAAI,wCAAmB,OAAO,CAAC,cAAc,MAAA,CAAC;QAC9C,uBAAA,IAAI,mCAAc,OAAO,CAAC,SAAS,MAAA,CAAC;QACpC,uBAAA,IAAI,mCAAc,OAAO,CAAC,SAAS,IAAI,IAAI,MAAA,CAAC;IAC9C,CAAC;IAED,IAAI,OAAO;QACT,OAAO,uBAAA,IAAI,uCAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IACjD,CAAC;IAED;;;;OAIG;IACH,cAAc;QACZ,IAAI,uBAAA,IAAI,uCAAW,EAAE,CAAC;YACpB,MAAM,UAAU,GAAG,kCAAkC,CAAC,uBAAA,IAAI,uCAAW,CAAC,CAAC;YACvE,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;YACzD,CAAC;YACD,OAAO,UAAU,CAAC,OAAO,CAAC;QAC5B,CAAC;QACD,IAAI,uBAAA,IAAI,uCAAW,EAAE,CAAC;YACpB,OAAO,uBAAA,IAAI,uCAAW,CAAC;QACzB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;IACzD,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,mBAAmB,CAAC,OAAe;QACvC,IAAI,uBAAA,IAAI,uCAAW,EAAE,CAAC;YACpB,MAAM,EAAE,UAAU,EAAE,GAAG,uBAAA,IAAI,uCAAW,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;YAC1E,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;YACpD,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,EAAS,CAAC;YAC7C,uBAAA,IAAI,kCAAM,CAAC,WAAW,CAAC,GAAG,CAAC,qCAAqC,EAAE;gBAChE,OAAO;aACR,CAAC,CAAC;YACH,kEAAkE;YAClE,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YAC3D,OAAO,MAAM,uBAAA,IAAI,uCAAW,CAAC,IAAI,CAC/B,uCAAuC,EACvC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CACxB,CAAC;QACJ,CAAC;QAED,IAAI,uBAAA,IAAI,4CAAgB,EAAE,CAAC;YACzB,OAAO,MAAM,uBAAA,IAAI,4CAAgB,MAApB,IAAI,EAAiB,OAAO,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;IACzD,CAAC;IAEM,cAAc,CAAC,SAAkB;QACtC,uBAAA,IAAI,mCAAc,SAAS,MAAA,CAAC;IAC9B,CAAC;IAEM,aAAa;QAClB,OAAO,uBAAA,IAAI,uCAAW,CAAC;IACzB,CAAC;CACF","sourcesContent":["/**\n * LighterWalletService\n *\n * Routes the L1 signatures Lighter requires. The client-owned signer bridge\n * creates and stores the venue key; Core never receives its seed or private\n * key.\n *\n * Lighter's protocol needs two kinds of signatures:\n * 1. An EIP-191 `personal_sign` over the ChangePubKey plaintext produced by\n * the WASM signer — this registers the venue key on the account. The\n * signature is injected into the L2 transaction (`L1Sig`); the raw EVM\n * private key is never required, so hardware wallets are supported.\n * 2. Venue-key (Schnorr/ECgFp5) signatures over L2 transactions, produced\n * inside the injected signer bridge from client-managed key material.\n *\n * Signature routing mirrors MYXWalletService: through\n * `KeyringController:signPersonalMessage` when a messenger is available,\n * or through an injected `LighterPersonalSigner` for headless use.\n */\n\nimport { bytesToHex } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type { PerpsControllerMessenger } from '../PerpsController.js';\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes.js';\nimport type { PerpsPlatformDependencies } from '../types/index.js';\nimport type {\n LighterNetwork,\n LighterPersonalSigner,\n} from '../types/lighter-types.js';\nimport { getSelectedEvmAccountFromMessenger } from '../utils/accountUtils.js';\n\nexport class LighterWalletService {\n #isTestnet: boolean;\n\n readonly #deps: PerpsPlatformDependencies;\n\n readonly #messenger: PerpsControllerMessenger | undefined;\n\n readonly #personalSigner: LighterPersonalSigner | undefined;\n\n readonly #l1Address: string | undefined;\n\n constructor(\n deps: PerpsPlatformDependencies,\n options: {\n isTestnet?: boolean;\n messenger?: PerpsControllerMessenger;\n personalSigner?: LighterPersonalSigner;\n l1Address?: string;\n } = {},\n ) {\n this.#deps = deps;\n this.#messenger = options.messenger;\n this.#personalSigner = options.personalSigner;\n this.#l1Address = options.l1Address;\n this.#isTestnet = options.isTestnet ?? true;\n }\n\n get network(): LighterNetwork {\n return this.#isTestnet ? 'testnet' : 'mainnet';\n }\n\n /**\n * Resolve the L1 address whose account owns the Lighter account.\n *\n * @returns The EVM address.\n */\n getUserAddress(): string {\n if (this.#messenger) {\n const evmAccount = getSelectedEvmAccountFromMessenger(this.#messenger);\n if (!evmAccount?.address) {\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n return evmAccount.address;\n }\n if (this.#l1Address) {\n return this.#l1Address;\n }\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n /**\n * Sign an EIP-191 personal message with the user's L1 account.\n *\n * Routes through the keyring when a messenger is present, else the\n * injected headless signer.\n *\n * @param message - Plaintext message to sign.\n * @returns 65-byte signature as 0x-prefixed hex.\n */\n async signPersonalMessage(message: string): Promise<string> {\n if (this.#messenger) {\n const { isUnlocked } = this.#messenger.call('KeyringController:getState');\n if (!isUnlocked) {\n throw new Error(PERPS_ERROR_CODES.KEYRING_LOCKED);\n }\n const address = this.getUserAddress() as Hex;\n this.#deps.debugLogger.log('LighterWalletService: personal_sign', {\n address,\n });\n // KeyringController:signPersonalMessage expects hex-encoded data.\n const data = bytesToHex(new TextEncoder().encode(message));\n return await this.#messenger.call(\n 'KeyringController:signPersonalMessage',\n { from: address, data },\n );\n }\n\n if (this.#personalSigner) {\n return await this.#personalSigner(message);\n }\n\n throw new Error(PERPS_ERROR_CODES.NO_ACCOUNT_SELECTED);\n }\n\n public setTestnetMode(isTestnet: boolean): void {\n this.#isTestnet = isTestnet;\n }\n\n public isTestnetMode(): boolean {\n return this.#isTestnet;\n }\n}\n"]}