@metamask/transaction-controller 65.0.0 → 65.1.0
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 +17 -1
- package/dist/TransactionController.cjs +32 -1
- package/dist/TransactionController.cjs.map +1 -1
- package/dist/TransactionController.d.cts.map +1 -1
- package/dist/TransactionController.d.mts.map +1 -1
- package/dist/TransactionController.mjs +32 -1
- package/dist/TransactionController.mjs.map +1 -1
- package/dist/api/simulation-api.cjs.map +1 -1
- package/dist/api/simulation-api.d.cts +2 -0
- package/dist/api/simulation-api.d.cts.map +1 -1
- package/dist/api/simulation-api.d.mts +2 -0
- package/dist/api/simulation-api.d.mts.map +1 -1
- package/dist/api/simulation-api.mjs.map +1 -1
- package/dist/helpers/PendingTransactionTracker.cjs +13 -2
- package/dist/helpers/PendingTransactionTracker.cjs.map +1 -1
- package/dist/helpers/PendingTransactionTracker.d.cts.map +1 -1
- package/dist/helpers/PendingTransactionTracker.d.mts.map +1 -1
- package/dist/helpers/PendingTransactionTracker.mjs +13 -2
- package/dist/helpers/PendingTransactionTracker.mjs.map +1 -1
- package/dist/index.cjs +3 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +22 -0
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +22 -0
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/dist/utils/balance-changes.cjs +21 -1
- package/dist/utils/balance-changes.cjs.map +1 -1
- package/dist/utils/balance-changes.d.cts +2 -1
- package/dist/utils/balance-changes.d.cts.map +1 -1
- package/dist/utils/balance-changes.d.mts +2 -1
- package/dist/utils/balance-changes.d.mts.map +1 -1
- package/dist/utils/balance-changes.mjs +21 -1
- package/dist/utils/balance-changes.mjs.map +1 -1
- package/dist/utils/eip7702.cjs +38 -9
- package/dist/utils/eip7702.cjs.map +1 -1
- package/dist/utils/eip7702.d.cts +12 -0
- package/dist/utils/eip7702.d.cts.map +1 -1
- package/dist/utils/eip7702.d.mts +12 -0
- package/dist/utils/eip7702.d.mts.map +1 -1
- package/dist/utils/eip7702.mjs +36 -8
- package/dist/utils/eip7702.mjs.map +1 -1
- package/dist/utils/gas.cjs +12 -5
- package/dist/utils/gas.cjs.map +1 -1
- package/dist/utils/gas.d.cts +2 -1
- package/dist/utils/gas.d.cts.map +1 -1
- package/dist/utils/gas.d.mts +2 -1
- package/dist/utils/gas.d.mts.map +1 -1
- package/dist/utils/gas.mjs +12 -5
- package/dist/utils/gas.mjs.map +1 -1
- package/dist/utils/revert-reason.cjs +192 -0
- package/dist/utils/revert-reason.cjs.map +1 -0
- package/dist/utils/revert-reason.d.cts +57 -0
- package/dist/utils/revert-reason.d.cts.map +1 -0
- package/dist/utils/revert-reason.d.mts +57 -0
- package/dist/utils/revert-reason.d.mts.map +1 -0
- package/dist/utils/revert-reason.mjs +186 -0
- package/dist/utils/revert-reason.mjs.map +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { defaultAbiCoder } from "@ethersproject/abi";
|
|
2
|
+
import { createModuleLogger, projectLogger } from "../logger.mjs";
|
|
3
|
+
import { rpcRequest } from "./provider.mjs";
|
|
4
|
+
const log = createModuleLogger(projectLogger, 'revert-reason');
|
|
5
|
+
const ERROR_SELECTOR = '0x08c379a0';
|
|
6
|
+
const PANIC_SELECTOR = '0x4e487b71';
|
|
7
|
+
/**
|
|
8
|
+
* Solidity panic code descriptions.
|
|
9
|
+
*
|
|
10
|
+
* @see https://docs.soliditylang.org/en/latest/control-structures.html#panic-via-assert-and-error-via-require
|
|
11
|
+
*/
|
|
12
|
+
const PANIC_CODE_MESSAGES = {
|
|
13
|
+
'0x00': 'Generic compiler panic',
|
|
14
|
+
'0x01': 'Assertion failed',
|
|
15
|
+
'0x11': 'Arithmetic overflow or underflow',
|
|
16
|
+
'0x12': 'Division or modulo by zero',
|
|
17
|
+
'0x21': 'Invalid enum value',
|
|
18
|
+
'0x22': 'Incorrectly encoded storage byte array',
|
|
19
|
+
'0x31': 'Pop on empty array',
|
|
20
|
+
'0x32': 'Array index out of bounds',
|
|
21
|
+
'0x41': 'Memory allocation overflow',
|
|
22
|
+
'0x51': 'Call to zero-initialized function',
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Error thrown by `PendingTransactionTracker` when a transaction failed
|
|
26
|
+
* on-chain, carrying any decoded revert.
|
|
27
|
+
*/
|
|
28
|
+
export class OnChainFailureError extends Error {
|
|
29
|
+
constructor(revert) {
|
|
30
|
+
const suffix = revert?.message ? `: ${revert.message}` : '';
|
|
31
|
+
super(`Transaction failed on-chain${suffix}`);
|
|
32
|
+
this.name = 'OnChainFailureError';
|
|
33
|
+
this.revert = revert;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Decode an EVM revert into a `Revert` containing both the decoded
|
|
38
|
+
* human-readable message and the original raw `data`. Accepts either a
|
|
39
|
+
* raw revert data hex string, or a thrown JSON-RPC error of the shape
|
|
40
|
+
* `{ data: Hex | { data: Hex } }`. Handles `Error(string)`,
|
|
41
|
+
* `Panic(uint256)`, and falls back to a raw `Custom error: 0x<selector>`
|
|
42
|
+
* reference for unknown custom errors.
|
|
43
|
+
*
|
|
44
|
+
* @param input - Raw revert data hex, or a thrown JSON-RPC error.
|
|
45
|
+
* @param source - Optional label included in debug logs to identify the
|
|
46
|
+
* caller (e.g. `gas`, `simulation`).
|
|
47
|
+
* @returns A `Revert` if any data was found, otherwise `undefined`.
|
|
48
|
+
*/
|
|
49
|
+
export function decodeRevert(input, source) {
|
|
50
|
+
const data = toRevertDataHex(input);
|
|
51
|
+
if (!data) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
const message = decodeMessage(data);
|
|
55
|
+
const revert = {
|
|
56
|
+
...(message ? { message } : {}),
|
|
57
|
+
data,
|
|
58
|
+
};
|
|
59
|
+
logRevert(source, revert);
|
|
60
|
+
return revert;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Replay a transaction that failed on-chain via `eth_estimateGas` to
|
|
64
|
+
* recover the revert reason. `eth_estimateGas` is used instead of
|
|
65
|
+
* `eth_call` to avoid `RetryOnEmptyMiddleware`, which retries reverted
|
|
66
|
+
* `eth_call` responses 10 times and discards the original error data.
|
|
67
|
+
*
|
|
68
|
+
* Always resolves; never throws.
|
|
69
|
+
*
|
|
70
|
+
* @param input - Extraction inputs.
|
|
71
|
+
* @param input.messenger - Transaction controller messenger.
|
|
72
|
+
* @param input.networkClientId - Network client ID to replay against.
|
|
73
|
+
* @param input.txParams - Transaction parameters for the failed tx.
|
|
74
|
+
* @returns A `Revert`, or `undefined` if none could be observed.
|
|
75
|
+
*/
|
|
76
|
+
export async function extractRevert({ messenger, networkClientId, txParams, }) {
|
|
77
|
+
if (!txParams?.to && !txParams?.data) {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
const callParams = {};
|
|
81
|
+
if (txParams.from) {
|
|
82
|
+
callParams.from = txParams.from;
|
|
83
|
+
}
|
|
84
|
+
if (txParams.to) {
|
|
85
|
+
callParams.to = txParams.to;
|
|
86
|
+
}
|
|
87
|
+
if (txParams.data) {
|
|
88
|
+
callParams.data = txParams.data;
|
|
89
|
+
}
|
|
90
|
+
if (txParams.value) {
|
|
91
|
+
callParams.value = txParams.value;
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
await rpcRequest({
|
|
95
|
+
messenger,
|
|
96
|
+
networkClientId,
|
|
97
|
+
// `eth_estimateGas` is used instead of `eth_call` to bypass
|
|
98
|
+
// `RetryOnEmptyMiddleware`, which retries reverted `eth_call`
|
|
99
|
+
// responses and discards the original revert data.
|
|
100
|
+
method: 'eth_estimateGas',
|
|
101
|
+
params: [callParams],
|
|
102
|
+
});
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
return decodeRevert(error, 'receipt');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Coerce a `RevertInput` to a non-empty revert data hex string.
|
|
111
|
+
*
|
|
112
|
+
* @param input - Raw hex or thrown JSON-RPC error.
|
|
113
|
+
* @returns The revert data hex, or `undefined`.
|
|
114
|
+
*/
|
|
115
|
+
function toRevertDataHex(input) {
|
|
116
|
+
if (isHex(input)) {
|
|
117
|
+
return input;
|
|
118
|
+
}
|
|
119
|
+
if (typeof input !== 'object' || input === null) {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
const { data } = input;
|
|
123
|
+
if (isHex(data)) {
|
|
124
|
+
return data;
|
|
125
|
+
}
|
|
126
|
+
if (typeof data === 'object' && data !== null && isHex(data.data)) {
|
|
127
|
+
return data.data;
|
|
128
|
+
}
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Type guard for non-empty `0x`-prefixed hex strings.
|
|
133
|
+
*
|
|
134
|
+
* @param value - Value to test.
|
|
135
|
+
* @returns Whether the value is a non-empty hex string.
|
|
136
|
+
*/
|
|
137
|
+
function isHex(value) {
|
|
138
|
+
return typeof value === 'string' && value.startsWith('0x') && value !== '0x';
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Decode raw revert data into a human-readable string.
|
|
142
|
+
*
|
|
143
|
+
* @param data - Raw revert data hex.
|
|
144
|
+
* @returns Decoded message, or `undefined` if undecodable.
|
|
145
|
+
*/
|
|
146
|
+
function decodeMessage(data) {
|
|
147
|
+
if (!data || data === '0x') {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
if (data.length < 10) {
|
|
151
|
+
return `execution reverted (${data})`;
|
|
152
|
+
}
|
|
153
|
+
const selector = data.slice(0, 10).toLowerCase();
|
|
154
|
+
const payload = `0x${data.slice(10)}`;
|
|
155
|
+
if (selector === ERROR_SELECTOR) {
|
|
156
|
+
try {
|
|
157
|
+
const [reason] = defaultAbiCoder.decode(['string'], payload);
|
|
158
|
+
return typeof reason === 'string' ? reason : undefined;
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (selector === PANIC_SELECTOR) {
|
|
165
|
+
try {
|
|
166
|
+
const [code] = defaultAbiCoder.decode(['uint256'], payload);
|
|
167
|
+
const codeHex = code.toHexString().toLowerCase();
|
|
168
|
+
const description = PANIC_CODE_MESSAGES[codeHex] ?? 'Unknown panic';
|
|
169
|
+
return `Panic: ${description}`;
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return `Custom error: ${selector}`;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Emit a single structured debug line for a decoded revert.
|
|
179
|
+
*
|
|
180
|
+
* @param source - Source label, when known.
|
|
181
|
+
* @param revert - Resolved Revert.
|
|
182
|
+
*/
|
|
183
|
+
function logRevert(source, revert) {
|
|
184
|
+
log('Decoded revert', source ?? 'unknown', revert);
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=revert-reason.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revert-reason.mjs","sourceRoot":"","sources":["../../src/utils/revert-reason.ts"],"names":[],"mappings":"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","sourcesContent":["import { defaultAbiCoder } from '@ethersproject/abi';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport type { Hex } from '@metamask/utils';\n\nimport { createModuleLogger, projectLogger } from '../logger';\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type { Revert, TransactionParams } from '../types';\nimport { rpcRequest } from './provider';\n\nconst log = createModuleLogger(projectLogger, 'revert-reason');\n\nconst ERROR_SELECTOR = '0x08c379a0';\nconst PANIC_SELECTOR = '0x4e487b71';\n\n/**\n * Solidity panic code descriptions.\n *\n * @see https://docs.soliditylang.org/en/latest/control-structures.html#panic-via-assert-and-error-via-require\n */\nconst PANIC_CODE_MESSAGES: Record<string, string> = {\n '0x00': 'Generic compiler panic',\n '0x01': 'Assertion failed',\n '0x11': 'Arithmetic overflow or underflow',\n '0x12': 'Division or modulo by zero',\n '0x21': 'Invalid enum value',\n '0x22': 'Incorrectly encoded storage byte array',\n '0x31': 'Pop on empty array',\n '0x32': 'Array index out of bounds',\n '0x41': 'Memory allocation overflow',\n '0x51': 'Call to zero-initialized function',\n};\n\n/**\n * Input accepted by `decodeRevert`. Either raw revert data hex, or a\n * thrown JSON-RPC error carrying the data on `data` (standard) or\n * nested `data.data` (some older node forks).\n */\ntype RevertInput =\n | Hex\n | undefined\n | { data?: Hex | { data?: Hex } | null }\n | null;\n\n/**\n * Error thrown by `PendingTransactionTracker` when a transaction failed\n * on-chain, carrying any decoded revert.\n */\nexport class OnChainFailureError extends Error {\n readonly revert?: Revert;\n\n constructor(revert?: Revert) {\n const suffix = revert?.message ? `: ${revert.message}` : '';\n super(`Transaction failed on-chain${suffix}`);\n this.name = 'OnChainFailureError';\n this.revert = revert;\n }\n}\n\n/**\n * Decode an EVM revert into a `Revert` containing both the decoded\n * human-readable message and the original raw `data`. Accepts either a\n * raw revert data hex string, or a thrown JSON-RPC error of the shape\n * `{ data: Hex | { data: Hex } }`. Handles `Error(string)`,\n * `Panic(uint256)`, and falls back to a raw `Custom error: 0x<selector>`\n * reference for unknown custom errors.\n *\n * @param input - Raw revert data hex, or a thrown JSON-RPC error.\n * @param source - Optional label included in debug logs to identify the\n * caller (e.g. `gas`, `simulation`).\n * @returns A `Revert` if any data was found, otherwise `undefined`.\n */\nexport function decodeRevert(\n input: RevertInput,\n source?: string,\n): Revert | undefined {\n const data = toRevertDataHex(input);\n if (!data) {\n return undefined;\n }\n\n const message = decodeMessage(data);\n const revert: Revert = {\n ...(message ? { message } : {}),\n data,\n };\n\n logRevert(source, revert);\n return revert;\n}\n\n/**\n * Replay a transaction that failed on-chain via `eth_estimateGas` to\n * recover the revert reason. `eth_estimateGas` is used instead of\n * `eth_call` to avoid `RetryOnEmptyMiddleware`, which retries reverted\n * `eth_call` responses 10 times and discards the original error data.\n *\n * Always resolves; never throws.\n *\n * @param input - Extraction inputs.\n * @param input.messenger - Transaction controller messenger.\n * @param input.networkClientId - Network client ID to replay against.\n * @param input.txParams - Transaction parameters for the failed tx.\n * @returns A `Revert`, or `undefined` if none could be observed.\n */\nexport async function extractRevert({\n messenger,\n networkClientId,\n txParams,\n}: {\n messenger: TransactionControllerMessenger;\n networkClientId: NetworkClientId;\n txParams: TransactionParams;\n}): Promise<Revert | undefined> {\n if (!txParams?.to && !txParams?.data) {\n return undefined;\n }\n\n const callParams: Record<string, string> = {};\n if (txParams.from) {\n callParams.from = txParams.from;\n }\n if (txParams.to) {\n callParams.to = txParams.to;\n }\n if (txParams.data) {\n callParams.data = txParams.data;\n }\n if (txParams.value) {\n callParams.value = txParams.value;\n }\n\n try {\n await rpcRequest({\n messenger,\n networkClientId,\n // `eth_estimateGas` is used instead of `eth_call` to bypass\n // `RetryOnEmptyMiddleware`, which retries reverted `eth_call`\n // responses and discards the original revert data.\n method: 'eth_estimateGas',\n params: [callParams],\n });\n return undefined;\n } catch (error: unknown) {\n return decodeRevert(error as RevertInput, 'receipt');\n }\n}\n\n/**\n * Coerce a `RevertInput` to a non-empty revert data hex string.\n *\n * @param input - Raw hex or thrown JSON-RPC error.\n * @returns The revert data hex, or `undefined`.\n */\nfunction toRevertDataHex(input: RevertInput): Hex | undefined {\n if (isHex(input)) {\n return input;\n }\n\n if (typeof input !== 'object' || input === null) {\n return undefined;\n }\n\n const { data } = input;\n if (isHex(data)) {\n return data;\n }\n\n if (typeof data === 'object' && data !== null && isHex(data.data)) {\n return data.data;\n }\n\n return undefined;\n}\n\n/**\n * Type guard for non-empty `0x`-prefixed hex strings.\n *\n * @param value - Value to test.\n * @returns Whether the value is a non-empty hex string.\n */\nfunction isHex(value: unknown): value is Hex {\n return typeof value === 'string' && value.startsWith('0x') && value !== '0x';\n}\n\n/**\n * Decode raw revert data into a human-readable string.\n *\n * @param data - Raw revert data hex.\n * @returns Decoded message, or `undefined` if undecodable.\n */\nfunction decodeMessage(data: Hex | undefined): string | undefined {\n if (!data || data === '0x') {\n return undefined;\n }\n\n if (data.length < 10) {\n return `execution reverted (${data})`;\n }\n\n const selector = data.slice(0, 10).toLowerCase();\n const payload = `0x${data.slice(10)}`;\n\n if (selector === ERROR_SELECTOR) {\n try {\n const [reason] = defaultAbiCoder.decode(['string'], payload);\n return typeof reason === 'string' ? reason : undefined;\n } catch {\n return undefined;\n }\n }\n\n if (selector === PANIC_SELECTOR) {\n try {\n const [code] = defaultAbiCoder.decode(['uint256'], payload) as [\n { toHexString: () => string },\n ];\n const codeHex = code.toHexString().toLowerCase() as Hex;\n const description = PANIC_CODE_MESSAGES[codeHex] ?? 'Unknown panic';\n return `Panic: ${description}`;\n } catch {\n return undefined;\n }\n }\n\n return `Custom error: ${selector}`;\n}\n\n/**\n * Emit a single structured debug line for a decoded revert.\n *\n * @param source - Source label, when known.\n * @param revert - Resolved Revert.\n */\nfunction logRevert(source: string | undefined, revert: Revert): void {\n log('Decoded revert', source ?? 'unknown', revert);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask/transaction-controller",
|
|
3
|
-
"version": "65.
|
|
3
|
+
"version": "65.1.0",
|
|
4
4
|
"description": "Stores transactions alongside their periodically updated statuses and manages interactions such as approval and cancellation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ethereum",
|
|
@@ -60,15 +60,15 @@
|
|
|
60
60
|
"@ethersproject/contracts": "^5.7.0",
|
|
61
61
|
"@ethersproject/providers": "^5.7.0",
|
|
62
62
|
"@ethersproject/wallet": "^5.7.0",
|
|
63
|
-
"@metamask/accounts-controller": "^
|
|
63
|
+
"@metamask/accounts-controller": "^38.0.0",
|
|
64
64
|
"@metamask/approval-controller": "^9.0.1",
|
|
65
65
|
"@metamask/base-controller": "^9.1.0",
|
|
66
66
|
"@metamask/controller-utils": "^11.20.0",
|
|
67
67
|
"@metamask/core-backend": "^6.2.1",
|
|
68
68
|
"@metamask/gas-fee-controller": "^26.1.1",
|
|
69
|
-
"@metamask/messenger": "^1.
|
|
69
|
+
"@metamask/messenger": "^1.2.0",
|
|
70
70
|
"@metamask/metamask-eth-abis": "^3.1.1",
|
|
71
|
-
"@metamask/network-controller": "^30.0
|
|
71
|
+
"@metamask/network-controller": "^30.1.0",
|
|
72
72
|
"@metamask/nonce-tracker": "^6.0.0",
|
|
73
73
|
"@metamask/remote-feature-flag-controller": "^4.2.0",
|
|
74
74
|
"@metamask/rpc-errors": "^7.0.2",
|