@metamask-previews/perps-controller 10.0.0-preview-beea66146 → 10.0.0-preview-7b60eca
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.
- package/CHANGELOG.md +5 -0
- package/dist/providers/HyperLiquidProvider.cjs +76 -1
- package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
- package/dist/providers/HyperLiquidProvider.mjs +77 -2
- package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
- package/dist/utils/errorUtils.cjs +17 -1
- package/dist/utils/errorUtils.cjs.map +1 -1
- package/dist/utils/errorUtils.d.cts +12 -0
- package/dist/utils/errorUtils.d.cts.map +1 -1
- package/dist/utils/errorUtils.d.mts +12 -0
- package/dist/utils/errorUtils.d.mts.map +1 -1
- package/dist/utils/errorUtils.mjs +15 -0
- package/dist/utils/errorUtils.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isHyperLiquidUserNotFoundError = exports.ensureError = exports.isKeyringLockedError = exports.isAbortError = void 0;
|
|
3
|
+
exports.isHyperLiquidMultiSigRequiredError = exports.isHyperLiquidUserNotFoundError = exports.ensureError = exports.isKeyringLockedError = exports.isAbortError = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Utility functions for error handling across Perps controller code.
|
|
6
6
|
* Includes generic error helpers and Perps error classification helpers.
|
|
@@ -85,4 +85,20 @@ function isHyperLiquidUserNotFoundError(error) {
|
|
|
85
85
|
return (lower.includes('user or api wallet') && lower.includes('does not exist'));
|
|
86
86
|
}
|
|
87
87
|
exports.isHyperLiquidUserNotFoundError = isHyperLiquidUserNotFoundError;
|
|
88
|
+
/**
|
|
89
|
+
* Hyperliquid rejects every single-signer exchange write for an account that
|
|
90
|
+
* has been converted to multi-sig (`ApiRequestError: Multi-sig required`).
|
|
91
|
+
* MetaMask signs Perps actions with a single agent/user wallet, so this is a
|
|
92
|
+
* permanent account-shape condition rather than a failure we should retry or
|
|
93
|
+
* forward to Sentry. Only the hyphenated spelling has been observed from the
|
|
94
|
+
* venue; the unhyphenated variant is matched defensively.
|
|
95
|
+
*
|
|
96
|
+
* @param error - The caught error.
|
|
97
|
+
* @returns True if the error indicates multi-sig signing is required.
|
|
98
|
+
*/
|
|
99
|
+
function isHyperLiquidMultiSigRequiredError(error) {
|
|
100
|
+
const lower = ensureError(error).message.toLowerCase();
|
|
101
|
+
return (lower.includes('multi-sig required') || lower.includes('multisig required'));
|
|
102
|
+
}
|
|
103
|
+
exports.isHyperLiquidMultiSigRequiredError = isHyperLiquidMultiSigRequiredError;
|
|
88
104
|
//# sourceMappingURL=errorUtils.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errorUtils.cjs","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,2CAA8C;AAE9C,+DAA0D;AAE1D;;;;;;;GAOG;AACH,SAAgB,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,CACL,KAAK,CAAC,IAAI,KAAK,YAAY;YAC3B,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAC3C,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CACpD,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AATD,oCASC;AAED;;;;;;GAMG;AACH,SAAgB,oBAAoB,CAAC,KAAc;IACjD,IAAI,OAAO,GAAY,KAAK,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAW,CAAC;IAEhC,OAAO,OAAO,YAAY,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAElB,IAAI,OAAO,CAAC,OAAO,KAAK,sCAAiB,CAAC,cAAc,EAAE,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,GAAI,OAA+B,CAAC,KAAK,CAAC;IACnD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAfD,oDAeC;AAED;;;;;;;;GAQG;AACH,SAAgB,WAAW,CAAC,KAAc,EAAE,OAAgB;IAC1D,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,8DAA8D;IAC9D,oFAAoF;IACpF,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,MAAM,WAAW,GAAG,qCAAqC,CAAC;QAC1D,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,IAAI,KAAK,CACd,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,IAAA,mBAAW,EAAC,KAAK,EAAE,SAAS,CAAC;QAC1E,CAAC,CAAC,MAAM,CAAE,KAA8B,CAAC,OAAO,CAAC;QACjD,CAAC,CAAC,eAAe,CACpB,CAAC;AACJ,CAAC;AAlBD,kCAkBC;AAED;;;;;;;;GAQG;AACH,SAAgB,8BAA8B,CAAC,KAAc;IAC3D,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACvD,OAAO,CACL,KAAK,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CACzE,CAAC;AACJ,CAAC;AALD,wEAKC","sourcesContent":["/**\n * Utility functions for error handling across Perps controller code.\n * Includes generic error helpers and Perps error classification helpers.\n */\nimport { hasProperty } from '@metamask/utils';\n\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes.js';\n\n/**\n * Detects expected cancellation/abort errors that should not be reported to Sentry.\n * These occur during normal navigation or view teardown when in-flight fetch requests\n * are cancelled via AbortController.\n *\n * @param error - The error to check.\n * @returns True if the error is an expected abort/cancellation.\n */\nexport function isAbortError(error: unknown): boolean {\n if (error instanceof Error) {\n return (\n error.name === 'AbortError' ||\n error.message.includes('signal is aborted') ||\n error.message.includes('The operation was aborted')\n );\n }\n return false;\n}\n\n/**\n * Detects keyring-locked errors, including SDK-wrapped errors that preserve the\n * original error in `cause`.\n *\n * @param error - The error to check.\n * @returns True if any error in the cause chain is KEYRING_LOCKED.\n */\nexport function isKeyringLockedError(error: unknown): boolean {\n let current: unknown = error;\n const seen = new Set<unknown>();\n\n while (current instanceof Error && !seen.has(current)) {\n seen.add(current);\n\n if (current.message === PERPS_ERROR_CODES.KEYRING_LOCKED) {\n return true;\n }\n\n current = (current as { cause?: unknown }).cause;\n }\n\n return false;\n}\n\n/**\n * Ensures we have a proper Error object for logging.\n * Converts unknown/string errors to proper Error instances.\n * Handles undefined/null specially for better Sentry context.\n *\n * @param error - The caught error (could be Error, string, or unknown)\n * @param context - Optional context string to help identify the source of the error\n * @returns A proper Error instance\n */\nexport function ensureError(error: unknown, context?: string): Error {\n if (error instanceof Error) {\n return error;\n }\n // Handle undefined/null specifically for better error context\n // e.g. Hyperliquid SDK may reject with undefined when AbortSignal.reason is not set\n if (error === undefined || error === null) {\n const baseMessage = 'Unknown error (no details provided)';\n return new Error(context ? `${baseMessage} [${context}]` : baseMessage);\n }\n if (typeof error === 'string') {\n return new Error(error);\n }\n return new Error(\n typeof error === 'object' && error !== null && hasProperty(error, 'message')\n ? String((error as { message: unknown }).message)\n : 'Unknown error',\n );\n}\n\n/**\n * Hyperliquid rejects user-scoped exchange writes (`agentSetAbstraction`,\n * `userSetAbstraction`, `setReferrer`, ...) with this exact message when the\n * wallet has never funded a Hyperliquid account. It is a benign pre-account\n * state, not an error we should forward to Sentry.\n *\n * @param error - The caught error.\n * @returns True if the error matches the Hyperliquid \"user not on chain yet\" rejection.\n */\nexport function isHyperLiquidUserNotFoundError(error: unknown): boolean {\n const lower = ensureError(error).message.toLowerCase();\n return (\n lower.includes('user or api wallet') && lower.includes('does not exist')\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"errorUtils.cjs","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,2CAA8C;AAE9C,+DAA0D;AAE1D;;;;;;;GAOG;AACH,SAAgB,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,CACL,KAAK,CAAC,IAAI,KAAK,YAAY;YAC3B,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAC3C,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CACpD,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AATD,oCASC;AAED;;;;;;GAMG;AACH,SAAgB,oBAAoB,CAAC,KAAc;IACjD,IAAI,OAAO,GAAY,KAAK,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAW,CAAC;IAEhC,OAAO,OAAO,YAAY,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAElB,IAAI,OAAO,CAAC,OAAO,KAAK,sCAAiB,CAAC,cAAc,EAAE,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,GAAI,OAA+B,CAAC,KAAK,CAAC;IACnD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAfD,oDAeC;AAED;;;;;;;;GAQG;AACH,SAAgB,WAAW,CAAC,KAAc,EAAE,OAAgB;IAC1D,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,8DAA8D;IAC9D,oFAAoF;IACpF,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,MAAM,WAAW,GAAG,qCAAqC,CAAC;QAC1D,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,IAAI,KAAK,CACd,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,IAAA,mBAAW,EAAC,KAAK,EAAE,SAAS,CAAC;QAC1E,CAAC,CAAC,MAAM,CAAE,KAA8B,CAAC,OAAO,CAAC;QACjD,CAAC,CAAC,eAAe,CACpB,CAAC;AACJ,CAAC;AAlBD,kCAkBC;AAED;;;;;;;;GAQG;AACH,SAAgB,8BAA8B,CAAC,KAAc;IAC3D,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACvD,OAAO,CACL,KAAK,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CACzE,CAAC;AACJ,CAAC;AALD,wEAKC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,kCAAkC,CAAC,KAAc;IAC/D,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACvD,OAAO,CACL,KAAK,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAC5E,CAAC;AACJ,CAAC;AALD,gFAKC","sourcesContent":["/**\n * Utility functions for error handling across Perps controller code.\n * Includes generic error helpers and Perps error classification helpers.\n */\nimport { hasProperty } from '@metamask/utils';\n\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes.js';\n\n/**\n * Detects expected cancellation/abort errors that should not be reported to Sentry.\n * These occur during normal navigation or view teardown when in-flight fetch requests\n * are cancelled via AbortController.\n *\n * @param error - The error to check.\n * @returns True if the error is an expected abort/cancellation.\n */\nexport function isAbortError(error: unknown): boolean {\n if (error instanceof Error) {\n return (\n error.name === 'AbortError' ||\n error.message.includes('signal is aborted') ||\n error.message.includes('The operation was aborted')\n );\n }\n return false;\n}\n\n/**\n * Detects keyring-locked errors, including SDK-wrapped errors that preserve the\n * original error in `cause`.\n *\n * @param error - The error to check.\n * @returns True if any error in the cause chain is KEYRING_LOCKED.\n */\nexport function isKeyringLockedError(error: unknown): boolean {\n let current: unknown = error;\n const seen = new Set<unknown>();\n\n while (current instanceof Error && !seen.has(current)) {\n seen.add(current);\n\n if (current.message === PERPS_ERROR_CODES.KEYRING_LOCKED) {\n return true;\n }\n\n current = (current as { cause?: unknown }).cause;\n }\n\n return false;\n}\n\n/**\n * Ensures we have a proper Error object for logging.\n * Converts unknown/string errors to proper Error instances.\n * Handles undefined/null specially for better Sentry context.\n *\n * @param error - The caught error (could be Error, string, or unknown)\n * @param context - Optional context string to help identify the source of the error\n * @returns A proper Error instance\n */\nexport function ensureError(error: unknown, context?: string): Error {\n if (error instanceof Error) {\n return error;\n }\n // Handle undefined/null specifically for better error context\n // e.g. Hyperliquid SDK may reject with undefined when AbortSignal.reason is not set\n if (error === undefined || error === null) {\n const baseMessage = 'Unknown error (no details provided)';\n return new Error(context ? `${baseMessage} [${context}]` : baseMessage);\n }\n if (typeof error === 'string') {\n return new Error(error);\n }\n return new Error(\n typeof error === 'object' && error !== null && hasProperty(error, 'message')\n ? String((error as { message: unknown }).message)\n : 'Unknown error',\n );\n}\n\n/**\n * Hyperliquid rejects user-scoped exchange writes (`agentSetAbstraction`,\n * `userSetAbstraction`, `setReferrer`, ...) with this exact message when the\n * wallet has never funded a Hyperliquid account. It is a benign pre-account\n * state, not an error we should forward to Sentry.\n *\n * @param error - The caught error.\n * @returns True if the error matches the Hyperliquid \"user not on chain yet\" rejection.\n */\nexport function isHyperLiquidUserNotFoundError(error: unknown): boolean {\n const lower = ensureError(error).message.toLowerCase();\n return (\n lower.includes('user or api wallet') && lower.includes('does not exist')\n );\n}\n\n/**\n * Hyperliquid rejects every single-signer exchange write for an account that\n * has been converted to multi-sig (`ApiRequestError: Multi-sig required`).\n * MetaMask signs Perps actions with a single agent/user wallet, so this is a\n * permanent account-shape condition rather than a failure we should retry or\n * forward to Sentry. Only the hyphenated spelling has been observed from the\n * venue; the unhyphenated variant is matched defensively.\n *\n * @param error - The caught error.\n * @returns True if the error indicates multi-sig signing is required.\n */\nexport function isHyperLiquidMultiSigRequiredError(error: unknown): boolean {\n const lower = ensureError(error).message.toLowerCase();\n return (\n lower.includes('multi-sig required') || lower.includes('multisig required')\n );\n}\n"]}
|
|
@@ -35,4 +35,16 @@ export declare function ensureError(error: unknown, context?: string): Error;
|
|
|
35
35
|
* @returns True if the error matches the Hyperliquid "user not on chain yet" rejection.
|
|
36
36
|
*/
|
|
37
37
|
export declare function isHyperLiquidUserNotFoundError(error: unknown): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Hyperliquid rejects every single-signer exchange write for an account that
|
|
40
|
+
* has been converted to multi-sig (`ApiRequestError: Multi-sig required`).
|
|
41
|
+
* MetaMask signs Perps actions with a single agent/user wallet, so this is a
|
|
42
|
+
* permanent account-shape condition rather than a failure we should retry or
|
|
43
|
+
* forward to Sentry. Only the hyphenated spelling has been observed from the
|
|
44
|
+
* venue; the unhyphenated variant is matched defensively.
|
|
45
|
+
*
|
|
46
|
+
* @param error - The caught error.
|
|
47
|
+
* @returns True if the error indicates multi-sig signing is required.
|
|
48
|
+
*/
|
|
49
|
+
export declare function isHyperLiquidMultiSigRequiredError(error: unknown): boolean;
|
|
38
50
|
//# sourceMappingURL=errorUtils.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errorUtils.d.cts","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CASpD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAe5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAkBnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKtE"}
|
|
1
|
+
{"version":3,"file":"errorUtils.d.cts","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CASpD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAe5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAkBnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKtE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kCAAkC,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAK1E"}
|
|
@@ -35,4 +35,16 @@ export declare function ensureError(error: unknown, context?: string): Error;
|
|
|
35
35
|
* @returns True if the error matches the Hyperliquid "user not on chain yet" rejection.
|
|
36
36
|
*/
|
|
37
37
|
export declare function isHyperLiquidUserNotFoundError(error: unknown): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Hyperliquid rejects every single-signer exchange write for an account that
|
|
40
|
+
* has been converted to multi-sig (`ApiRequestError: Multi-sig required`).
|
|
41
|
+
* MetaMask signs Perps actions with a single agent/user wallet, so this is a
|
|
42
|
+
* permanent account-shape condition rather than a failure we should retry or
|
|
43
|
+
* forward to Sentry. Only the hyphenated spelling has been observed from the
|
|
44
|
+
* venue; the unhyphenated variant is matched defensively.
|
|
45
|
+
*
|
|
46
|
+
* @param error - The caught error.
|
|
47
|
+
* @returns True if the error indicates multi-sig signing is required.
|
|
48
|
+
*/
|
|
49
|
+
export declare function isHyperLiquidMultiSigRequiredError(error: unknown): boolean;
|
|
38
50
|
//# sourceMappingURL=errorUtils.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errorUtils.d.mts","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CASpD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAe5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAkBnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKtE"}
|
|
1
|
+
{"version":3,"file":"errorUtils.d.mts","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CASpD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAe5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAkBnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKtE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kCAAkC,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAK1E"}
|
|
@@ -78,4 +78,19 @@ export function isHyperLiquidUserNotFoundError(error) {
|
|
|
78
78
|
const lower = ensureError(error).message.toLowerCase();
|
|
79
79
|
return (lower.includes('user or api wallet') && lower.includes('does not exist'));
|
|
80
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Hyperliquid rejects every single-signer exchange write for an account that
|
|
83
|
+
* has been converted to multi-sig (`ApiRequestError: Multi-sig required`).
|
|
84
|
+
* MetaMask signs Perps actions with a single agent/user wallet, so this is a
|
|
85
|
+
* permanent account-shape condition rather than a failure we should retry or
|
|
86
|
+
* forward to Sentry. Only the hyphenated spelling has been observed from the
|
|
87
|
+
* venue; the unhyphenated variant is matched defensively.
|
|
88
|
+
*
|
|
89
|
+
* @param error - The caught error.
|
|
90
|
+
* @returns True if the error indicates multi-sig signing is required.
|
|
91
|
+
*/
|
|
92
|
+
export function isHyperLiquidMultiSigRequiredError(error) {
|
|
93
|
+
const lower = ensureError(error).message.toLowerCase();
|
|
94
|
+
return (lower.includes('multi-sig required') || lower.includes('multisig required'));
|
|
95
|
+
}
|
|
81
96
|
//# sourceMappingURL=errorUtils.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errorUtils.mjs","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,WAAW,EAAE,wBAAwB;AAE9C,OAAO,EAAE,iBAAiB,EAAE,+BAA8B;AAE1D;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,CACL,KAAK,CAAC,IAAI,KAAK,YAAY;YAC3B,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAC3C,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CACpD,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,IAAI,OAAO,GAAY,KAAK,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAW,CAAC;IAEhC,OAAO,OAAO,YAAY,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAElB,IAAI,OAAO,CAAC,OAAO,KAAK,iBAAiB,CAAC,cAAc,EAAE,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,GAAI,OAA+B,CAAC,KAAK,CAAC;IACnD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc,EAAE,OAAgB;IAC1D,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,8DAA8D;IAC9D,oFAAoF;IACpF,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,MAAM,WAAW,GAAG,qCAAqC,CAAC;QAC1D,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,IAAI,KAAK,CACd,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,WAAW,CAAC,KAAK,EAAE,SAAS,CAAC;QAC1E,CAAC,CAAC,MAAM,CAAE,KAA8B,CAAC,OAAO,CAAC;QACjD,CAAC,CAAC,eAAe,CACpB,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,8BAA8B,CAAC,KAAc;IAC3D,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACvD,OAAO,CACL,KAAK,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CACzE,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Utility functions for error handling across Perps controller code.\n * Includes generic error helpers and Perps error classification helpers.\n */\nimport { hasProperty } from '@metamask/utils';\n\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes.js';\n\n/**\n * Detects expected cancellation/abort errors that should not be reported to Sentry.\n * These occur during normal navigation or view teardown when in-flight fetch requests\n * are cancelled via AbortController.\n *\n * @param error - The error to check.\n * @returns True if the error is an expected abort/cancellation.\n */\nexport function isAbortError(error: unknown): boolean {\n if (error instanceof Error) {\n return (\n error.name === 'AbortError' ||\n error.message.includes('signal is aborted') ||\n error.message.includes('The operation was aborted')\n );\n }\n return false;\n}\n\n/**\n * Detects keyring-locked errors, including SDK-wrapped errors that preserve the\n * original error in `cause`.\n *\n * @param error - The error to check.\n * @returns True if any error in the cause chain is KEYRING_LOCKED.\n */\nexport function isKeyringLockedError(error: unknown): boolean {\n let current: unknown = error;\n const seen = new Set<unknown>();\n\n while (current instanceof Error && !seen.has(current)) {\n seen.add(current);\n\n if (current.message === PERPS_ERROR_CODES.KEYRING_LOCKED) {\n return true;\n }\n\n current = (current as { cause?: unknown }).cause;\n }\n\n return false;\n}\n\n/**\n * Ensures we have a proper Error object for logging.\n * Converts unknown/string errors to proper Error instances.\n * Handles undefined/null specially for better Sentry context.\n *\n * @param error - The caught error (could be Error, string, or unknown)\n * @param context - Optional context string to help identify the source of the error\n * @returns A proper Error instance\n */\nexport function ensureError(error: unknown, context?: string): Error {\n if (error instanceof Error) {\n return error;\n }\n // Handle undefined/null specifically for better error context\n // e.g. Hyperliquid SDK may reject with undefined when AbortSignal.reason is not set\n if (error === undefined || error === null) {\n const baseMessage = 'Unknown error (no details provided)';\n return new Error(context ? `${baseMessage} [${context}]` : baseMessage);\n }\n if (typeof error === 'string') {\n return new Error(error);\n }\n return new Error(\n typeof error === 'object' && error !== null && hasProperty(error, 'message')\n ? String((error as { message: unknown }).message)\n : 'Unknown error',\n );\n}\n\n/**\n * Hyperliquid rejects user-scoped exchange writes (`agentSetAbstraction`,\n * `userSetAbstraction`, `setReferrer`, ...) with this exact message when the\n * wallet has never funded a Hyperliquid account. It is a benign pre-account\n * state, not an error we should forward to Sentry.\n *\n * @param error - The caught error.\n * @returns True if the error matches the Hyperliquid \"user not on chain yet\" rejection.\n */\nexport function isHyperLiquidUserNotFoundError(error: unknown): boolean {\n const lower = ensureError(error).message.toLowerCase();\n return (\n lower.includes('user or api wallet') && lower.includes('does not exist')\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"errorUtils.mjs","sourceRoot":"","sources":["../../src/utils/errorUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,WAAW,EAAE,wBAAwB;AAE9C,OAAO,EAAE,iBAAiB,EAAE,+BAA8B;AAE1D;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,CACL,KAAK,CAAC,IAAI,KAAK,YAAY;YAC3B,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAC3C,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CACpD,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,IAAI,OAAO,GAAY,KAAK,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAW,CAAC;IAEhC,OAAO,OAAO,YAAY,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAElB,IAAI,OAAO,CAAC,OAAO,KAAK,iBAAiB,CAAC,cAAc,EAAE,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,GAAI,OAA+B,CAAC,KAAK,CAAC;IACnD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc,EAAE,OAAgB;IAC1D,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,8DAA8D;IAC9D,oFAAoF;IACpF,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,MAAM,WAAW,GAAG,qCAAqC,CAAC;QAC1D,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,IAAI,KAAK,CACd,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,WAAW,CAAC,KAAK,EAAE,SAAS,CAAC;QAC1E,CAAC,CAAC,MAAM,CAAE,KAA8B,CAAC,OAAO,CAAC;QACjD,CAAC,CAAC,eAAe,CACpB,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,8BAA8B,CAAC,KAAc;IAC3D,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACvD,OAAO,CACL,KAAK,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CACzE,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kCAAkC,CAAC,KAAc;IAC/D,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACvD,OAAO,CACL,KAAK,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAC5E,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Utility functions for error handling across Perps controller code.\n * Includes generic error helpers and Perps error classification helpers.\n */\nimport { hasProperty } from '@metamask/utils';\n\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes.js';\n\n/**\n * Detects expected cancellation/abort errors that should not be reported to Sentry.\n * These occur during normal navigation or view teardown when in-flight fetch requests\n * are cancelled via AbortController.\n *\n * @param error - The error to check.\n * @returns True if the error is an expected abort/cancellation.\n */\nexport function isAbortError(error: unknown): boolean {\n if (error instanceof Error) {\n return (\n error.name === 'AbortError' ||\n error.message.includes('signal is aborted') ||\n error.message.includes('The operation was aborted')\n );\n }\n return false;\n}\n\n/**\n * Detects keyring-locked errors, including SDK-wrapped errors that preserve the\n * original error in `cause`.\n *\n * @param error - The error to check.\n * @returns True if any error in the cause chain is KEYRING_LOCKED.\n */\nexport function isKeyringLockedError(error: unknown): boolean {\n let current: unknown = error;\n const seen = new Set<unknown>();\n\n while (current instanceof Error && !seen.has(current)) {\n seen.add(current);\n\n if (current.message === PERPS_ERROR_CODES.KEYRING_LOCKED) {\n return true;\n }\n\n current = (current as { cause?: unknown }).cause;\n }\n\n return false;\n}\n\n/**\n * Ensures we have a proper Error object for logging.\n * Converts unknown/string errors to proper Error instances.\n * Handles undefined/null specially for better Sentry context.\n *\n * @param error - The caught error (could be Error, string, or unknown)\n * @param context - Optional context string to help identify the source of the error\n * @returns A proper Error instance\n */\nexport function ensureError(error: unknown, context?: string): Error {\n if (error instanceof Error) {\n return error;\n }\n // Handle undefined/null specifically for better error context\n // e.g. Hyperliquid SDK may reject with undefined when AbortSignal.reason is not set\n if (error === undefined || error === null) {\n const baseMessage = 'Unknown error (no details provided)';\n return new Error(context ? `${baseMessage} [${context}]` : baseMessage);\n }\n if (typeof error === 'string') {\n return new Error(error);\n }\n return new Error(\n typeof error === 'object' && error !== null && hasProperty(error, 'message')\n ? String((error as { message: unknown }).message)\n : 'Unknown error',\n );\n}\n\n/**\n * Hyperliquid rejects user-scoped exchange writes (`agentSetAbstraction`,\n * `userSetAbstraction`, `setReferrer`, ...) with this exact message when the\n * wallet has never funded a Hyperliquid account. It is a benign pre-account\n * state, not an error we should forward to Sentry.\n *\n * @param error - The caught error.\n * @returns True if the error matches the Hyperliquid \"user not on chain yet\" rejection.\n */\nexport function isHyperLiquidUserNotFoundError(error: unknown): boolean {\n const lower = ensureError(error).message.toLowerCase();\n return (\n lower.includes('user or api wallet') && lower.includes('does not exist')\n );\n}\n\n/**\n * Hyperliquid rejects every single-signer exchange write for an account that\n * has been converted to multi-sig (`ApiRequestError: Multi-sig required`).\n * MetaMask signs Perps actions with a single agent/user wallet, so this is a\n * permanent account-shape condition rather than a failure we should retry or\n * forward to Sentry. Only the hyphenated spelling has been observed from the\n * venue; the unhyphenated variant is matched defensively.\n *\n * @param error - The caught error.\n * @returns True if the error indicates multi-sig signing is required.\n */\nexport function isHyperLiquidMultiSigRequiredError(error: unknown): boolean {\n const lower = ensureError(error).message.toLowerCase();\n return (\n lower.includes('multi-sig required') || lower.includes('multisig required')\n );\n}\n"]}
|
package/package.json
CHANGED