hardhat 2.22.11 → 2.22.13
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/internal/hardhat-network/provider/provider.d.ts +2 -3
- package/internal/hardhat-network/provider/provider.d.ts.map +1 -1
- package/internal/hardhat-network/provider/provider.js +5 -19
- package/internal/hardhat-network/provider/provider.js.map +1 -1
- package/internal/hardhat-network/provider/return-data.d.ts +2 -15
- package/internal/hardhat-network/provider/return-data.d.ts.map +1 -1
- package/internal/hardhat-network/provider/return-data.js +2 -50
- package/internal/hardhat-network/provider/return-data.js.map +1 -1
- package/internal/hardhat-network/provider/vm/exit.d.ts +2 -20
- package/internal/hardhat-network/provider/vm/exit.d.ts.map +1 -1
- package/internal/hardhat-network/provider/vm/exit.js +3 -78
- package/internal/hardhat-network/provider/vm/exit.js.map +1 -1
- package/internal/hardhat-network/stack-traces/compiler-to-model.d.ts +2 -3
- package/internal/hardhat-network/stack-traces/compiler-to-model.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/compiler-to-model.js +2 -351
- package/internal/hardhat-network/stack-traces/compiler-to-model.js.map +1 -1
- package/internal/hardhat-network/stack-traces/debug.d.ts +2 -7
- package/internal/hardhat-network/stack-traces/debug.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/debug.js +3 -143
- package/internal/hardhat-network/stack-traces/debug.js.map +1 -1
- package/internal/hardhat-network/stack-traces/library-utils.d.ts +2 -11
- package/internal/hardhat-network/stack-traces/library-utils.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/library-utils.js +3 -61
- package/internal/hardhat-network/stack-traces/library-utils.js.map +1 -1
- package/internal/hardhat-network/stack-traces/logger.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/logger.js +0 -221
- package/internal/hardhat-network/stack-traces/logger.js.map +1 -1
- package/internal/hardhat-network/stack-traces/message-trace.d.ts +2 -51
- package/internal/hardhat-network/stack-traces/message-trace.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/message-trace.js +0 -46
- package/internal/hardhat-network/stack-traces/message-trace.js.map +1 -1
- package/internal/hardhat-network/stack-traces/solidity-errors.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/solidity-errors.js +58 -53
- package/internal/hardhat-network/stack-traces/solidity-errors.js.map +1 -1
- package/internal/hardhat-network/stack-traces/solidity-stack-trace.d.ts +4 -155
- package/internal/hardhat-network/stack-traces/solidity-stack-trace.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/solidity-stack-trace.js +12 -37
- package/internal/hardhat-network/stack-traces/solidity-stack-trace.js.map +1 -1
- package/internal/hardhat-network/stack-traces/solidityTracer.d.ts +2 -13
- package/internal/hardhat-network/stack-traces/solidityTracer.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/solidityTracer.js +2 -162
- package/internal/hardhat-network/stack-traces/solidityTracer.js.map +1 -1
- package/internal/hardhat-network/stack-traces/vm-trace-decoder.d.ts +4 -15
- package/internal/hardhat-network/stack-traces/vm-trace-decoder.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/vm-trace-decoder.js +6 -70
- package/internal/hardhat-network/stack-traces/vm-trace-decoder.js.map +1 -1
- package/internal/hardhat-network/stack-traces/vm-tracer.d.ts +2 -19
- package/internal/hardhat-network/stack-traces/vm-tracer.d.ts.map +1 -1
- package/internal/hardhat-network/stack-traces/vm-tracer.js +3 -150
- package/internal/hardhat-network/stack-traces/vm-tracer.js.map +1 -1
- package/package.json +2 -2
- package/src/internal/hardhat-network/provider/provider.ts +11 -24
- package/src/internal/hardhat-network/provider/return-data.ts +5 -73
- package/src/internal/hardhat-network/provider/vm/exit.ts +4 -92
- package/src/internal/hardhat-network/stack-traces/compiler-to-model.ts +5 -697
- package/src/internal/hardhat-network/stack-traces/debug.ts +5 -218
- package/src/internal/hardhat-network/stack-traces/library-utils.ts +5 -90
- package/src/internal/hardhat-network/stack-traces/logger.ts +0 -221
- package/src/internal/hardhat-network/stack-traces/message-trace.ts +5 -122
- package/src/internal/hardhat-network/stack-traces/solidity-errors.ts +16 -15
- package/src/internal/hardhat-network/stack-traces/solidity-stack-trace.ts +83 -186
- package/src/internal/hardhat-network/stack-traces/solidityTracer.ts +5 -253
- package/src/internal/hardhat-network/stack-traces/vm-trace-decoder.ts +15 -108
- package/src/internal/hardhat-network/stack-traces/vm-tracer.ts +5 -206
- package/internal/hardhat-network/stack-traces/contracts-identifier.d.ts +0 -15
- package/internal/hardhat-network/stack-traces/contracts-identifier.d.ts.map +0 -1
- package/internal/hardhat-network/stack-traces/contracts-identifier.js +0 -166
- package/internal/hardhat-network/stack-traces/contracts-identifier.js.map +0 -1
- package/internal/hardhat-network/stack-traces/error-inferrer.d.ts +0 -85
- package/internal/hardhat-network/stack-traces/error-inferrer.d.ts.map +0 -1
- package/internal/hardhat-network/stack-traces/error-inferrer.js +0 -1168
- package/internal/hardhat-network/stack-traces/error-inferrer.js.map +0 -1
- package/internal/hardhat-network/stack-traces/mapped-inlined-internal-functions-heuristics.d.ts +0 -24
- package/internal/hardhat-network/stack-traces/mapped-inlined-internal-functions-heuristics.d.ts.map +0 -1
- package/internal/hardhat-network/stack-traces/mapped-inlined-internal-functions-heuristics.js +0 -116
- package/internal/hardhat-network/stack-traces/mapped-inlined-internal-functions-heuristics.js.map +0 -1
- package/internal/hardhat-network/stack-traces/model.d.ts +0 -140
- package/internal/hardhat-network/stack-traces/model.d.ts.map +0 -1
- package/internal/hardhat-network/stack-traces/model.js +0 -328
- package/internal/hardhat-network/stack-traces/model.js.map +0 -1
- package/internal/hardhat-network/stack-traces/opcodes.d.ts +0 -266
- package/internal/hardhat-network/stack-traces/opcodes.d.ts.map +0 -1
- package/internal/hardhat-network/stack-traces/opcodes.js +0 -320
- package/internal/hardhat-network/stack-traces/opcodes.js.map +0 -1
- package/internal/hardhat-network/stack-traces/source-maps.d.ts +0 -13
- package/internal/hardhat-network/stack-traces/source-maps.d.ts.map +0 -1
- package/internal/hardhat-network/stack-traces/source-maps.js +0 -106
- package/internal/hardhat-network/stack-traces/source-maps.js.map +0 -1
- package/src/internal/hardhat-network/stack-traces/contracts-identifier.ts +0 -235
- package/src/internal/hardhat-network/stack-traces/error-inferrer.ts +0 -1845
- package/src/internal/hardhat-network/stack-traces/mapped-inlined-internal-functions-heuristics.ts +0 -163
- package/src/internal/hardhat-network/stack-traces/model.ts +0 -409
- package/src/internal/hardhat-network/stack-traces/opcodes.ts +0 -344
- package/src/internal/hardhat-network/stack-traces/source-maps.ts +0 -167
|
@@ -1,1845 +0,0 @@
|
|
|
1
|
-
/* eslint "@typescript-eslint/no-non-null-assertion": "error" */
|
|
2
|
-
import { defaultAbiCoder as abi } from "@ethersproject/abi";
|
|
3
|
-
import { equalsBytes } from "@nomicfoundation/ethereumjs-util";
|
|
4
|
-
import semver from "semver";
|
|
5
|
-
|
|
6
|
-
import { assertHardhatInvariant } from "../../core/errors";
|
|
7
|
-
import { AbiHelpers } from "../../util/abi-helpers";
|
|
8
|
-
import { ReturnData } from "../provider/return-data";
|
|
9
|
-
import { ExitCode } from "../provider/vm/exit";
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
DecodedCallMessageTrace,
|
|
13
|
-
DecodedCreateMessageTrace,
|
|
14
|
-
DecodedEvmMessageTrace,
|
|
15
|
-
EvmStep,
|
|
16
|
-
isCreateTrace,
|
|
17
|
-
isDecodedCallTrace,
|
|
18
|
-
isDecodedCreateTrace,
|
|
19
|
-
isEvmStep,
|
|
20
|
-
isPrecompileTrace,
|
|
21
|
-
MessageTrace,
|
|
22
|
-
} from "./message-trace";
|
|
23
|
-
import {
|
|
24
|
-
Bytecode,
|
|
25
|
-
ContractFunction,
|
|
26
|
-
ContractFunctionType,
|
|
27
|
-
ContractType,
|
|
28
|
-
Instruction,
|
|
29
|
-
JumpType,
|
|
30
|
-
SourceLocation,
|
|
31
|
-
} from "./model";
|
|
32
|
-
import { isCall, isCreate, Opcode } from "./opcodes";
|
|
33
|
-
import {
|
|
34
|
-
CallFailedErrorStackTraceEntry,
|
|
35
|
-
CallstackEntryStackTraceEntry,
|
|
36
|
-
CONSTRUCTOR_FUNCTION_NAME,
|
|
37
|
-
CustomErrorStackTraceEntry,
|
|
38
|
-
FALLBACK_FUNCTION_NAME,
|
|
39
|
-
InternalFunctionCallStackEntry,
|
|
40
|
-
OtherExecutionErrorStackTraceEntry,
|
|
41
|
-
PanicErrorStackTraceEntry,
|
|
42
|
-
RECEIVE_FUNCTION_NAME,
|
|
43
|
-
RevertErrorStackTraceEntry,
|
|
44
|
-
SolidityStackTrace,
|
|
45
|
-
SolidityStackTraceEntry,
|
|
46
|
-
SourceReference,
|
|
47
|
-
StackTraceEntryType,
|
|
48
|
-
UnmappedSolc063RevertErrorStackTraceEntry,
|
|
49
|
-
} from "./solidity-stack-trace";
|
|
50
|
-
|
|
51
|
-
const FIRST_SOLC_VERSION_CREATE_PARAMS_VALIDATION = "0.5.9";
|
|
52
|
-
const FIRST_SOLC_VERSION_RECEIVE_FUNCTION = "0.6.0";
|
|
53
|
-
const FIRST_SOLC_VERSION_WITH_UNMAPPED_REVERTS = "0.6.3";
|
|
54
|
-
|
|
55
|
-
export interface SubmessageData {
|
|
56
|
-
messageTrace: MessageTrace;
|
|
57
|
-
stacktrace: SolidityStackTrace;
|
|
58
|
-
stepIndex: number;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/* eslint-disable @nomicfoundation/hardhat-internal-rules/only-hardhat-error */
|
|
62
|
-
|
|
63
|
-
export class ErrorInferrer {
|
|
64
|
-
public inferBeforeTracingCallMessage(
|
|
65
|
-
trace: DecodedCallMessageTrace
|
|
66
|
-
): SolidityStackTrace | undefined {
|
|
67
|
-
if (this._isDirectLibraryCall(trace)) {
|
|
68
|
-
return this._getDirectLibraryCallErrorStackTrace(trace);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const calledFunction = trace.bytecode.contract.getFunctionFromSelector(
|
|
72
|
-
trace.calldata.slice(0, 4)
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
if (
|
|
76
|
-
calledFunction !== undefined &&
|
|
77
|
-
this._isFunctionNotPayableError(trace, calledFunction)
|
|
78
|
-
) {
|
|
79
|
-
return [
|
|
80
|
-
{
|
|
81
|
-
type: StackTraceEntryType.FUNCTION_NOT_PAYABLE_ERROR,
|
|
82
|
-
sourceReference: this._getFunctionStartSourceReference(
|
|
83
|
-
trace,
|
|
84
|
-
calledFunction
|
|
85
|
-
),
|
|
86
|
-
value: trace.value,
|
|
87
|
-
},
|
|
88
|
-
];
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (this._isMissingFunctionAndFallbackError(trace, calledFunction)) {
|
|
92
|
-
if (this._emptyCalldataAndNoReceive(trace)) {
|
|
93
|
-
return [
|
|
94
|
-
{
|
|
95
|
-
type: StackTraceEntryType.MISSING_FALLBACK_OR_RECEIVE_ERROR,
|
|
96
|
-
sourceReference:
|
|
97
|
-
this._getContractStartWithoutFunctionSourceReference(trace),
|
|
98
|
-
},
|
|
99
|
-
];
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return [
|
|
103
|
-
{
|
|
104
|
-
type: StackTraceEntryType.UNRECOGNIZED_FUNCTION_WITHOUT_FALLBACK_ERROR,
|
|
105
|
-
sourceReference:
|
|
106
|
-
this._getContractStartWithoutFunctionSourceReference(trace),
|
|
107
|
-
},
|
|
108
|
-
];
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (this._isFallbackNotPayableError(trace, calledFunction)) {
|
|
112
|
-
if (this._emptyCalldataAndNoReceive(trace)) {
|
|
113
|
-
return [
|
|
114
|
-
{
|
|
115
|
-
type: StackTraceEntryType.FALLBACK_NOT_PAYABLE_AND_NO_RECEIVE_ERROR,
|
|
116
|
-
sourceReference: this._getFallbackStartSourceReference(trace),
|
|
117
|
-
value: trace.value,
|
|
118
|
-
},
|
|
119
|
-
];
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return [
|
|
123
|
-
{
|
|
124
|
-
type: StackTraceEntryType.FALLBACK_NOT_PAYABLE_ERROR,
|
|
125
|
-
sourceReference: this._getFallbackStartSourceReference(trace),
|
|
126
|
-
value: trace.value,
|
|
127
|
-
},
|
|
128
|
-
];
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
public inferBeforeTracingCreateMessage(
|
|
133
|
-
trace: DecodedCreateMessageTrace
|
|
134
|
-
): SolidityStackTrace | undefined {
|
|
135
|
-
if (this._isConstructorNotPayableError(trace)) {
|
|
136
|
-
return [
|
|
137
|
-
{
|
|
138
|
-
type: StackTraceEntryType.FUNCTION_NOT_PAYABLE_ERROR,
|
|
139
|
-
sourceReference: this._getConstructorStartSourceReference(trace),
|
|
140
|
-
value: trace.value,
|
|
141
|
-
},
|
|
142
|
-
];
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (this._isConstructorInvalidArgumentsError(trace)) {
|
|
146
|
-
return [
|
|
147
|
-
{
|
|
148
|
-
type: StackTraceEntryType.INVALID_PARAMS_ERROR,
|
|
149
|
-
sourceReference: this._getConstructorStartSourceReference(trace),
|
|
150
|
-
},
|
|
151
|
-
];
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
public inferAfterTracing(
|
|
156
|
-
trace: DecodedEvmMessageTrace,
|
|
157
|
-
stacktrace: SolidityStackTrace,
|
|
158
|
-
functionJumpdests: Instruction[],
|
|
159
|
-
jumpedIntoFunction: boolean,
|
|
160
|
-
lastSubmessageData: SubmessageData | undefined
|
|
161
|
-
): SolidityStackTrace {
|
|
162
|
-
return (
|
|
163
|
-
this._checkLastSubmessage(trace, stacktrace, lastSubmessageData) ??
|
|
164
|
-
this._checkFailedLastCall(trace, stacktrace) ??
|
|
165
|
-
this._checkLastInstruction(
|
|
166
|
-
trace,
|
|
167
|
-
stacktrace,
|
|
168
|
-
functionJumpdests,
|
|
169
|
-
jumpedIntoFunction
|
|
170
|
-
) ??
|
|
171
|
-
this._checkNonContractCalled(trace, stacktrace) ??
|
|
172
|
-
this._checkSolidity063UnmappedRevert(trace, stacktrace) ??
|
|
173
|
-
this._checkContractTooLarge(trace) ??
|
|
174
|
-
this._otherExecutionErrorStacktrace(trace, stacktrace)
|
|
175
|
-
);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
public filterRedundantFrames(
|
|
179
|
-
stacktrace: SolidityStackTrace
|
|
180
|
-
): SolidityStackTrace {
|
|
181
|
-
return stacktrace.filter((frame, i) => {
|
|
182
|
-
if (i + 1 === stacktrace.length) {
|
|
183
|
-
return true;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const nextFrame = stacktrace[i + 1];
|
|
187
|
-
|
|
188
|
-
// we can only filter frames if we know their sourceReference
|
|
189
|
-
// and the one from the next frame
|
|
190
|
-
if (
|
|
191
|
-
frame.sourceReference === undefined ||
|
|
192
|
-
nextFrame.sourceReference === undefined
|
|
193
|
-
) {
|
|
194
|
-
return true;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// look TWO frames ahead to determine if this is a specific occurrence of
|
|
198
|
-
// a redundant CALLSTACK_ENTRY frame observed when using Solidity 0.8.5:
|
|
199
|
-
if (
|
|
200
|
-
frame.type === StackTraceEntryType.CALLSTACK_ENTRY &&
|
|
201
|
-
i + 2 < stacktrace.length &&
|
|
202
|
-
stacktrace[i + 2].sourceReference !== undefined &&
|
|
203
|
-
stacktrace[i + 2].type === StackTraceEntryType.RETURNDATA_SIZE_ERROR
|
|
204
|
-
) {
|
|
205
|
-
// ! below for tsc. we confirmed existence in the enclosing conditional.
|
|
206
|
-
const thatSrcRef = stacktrace[i + 2].sourceReference;
|
|
207
|
-
if (
|
|
208
|
-
thatSrcRef !== undefined &&
|
|
209
|
-
frame.sourceReference.range[0] === thatSrcRef.range[0] &&
|
|
210
|
-
frame.sourceReference.range[1] === thatSrcRef.range[1] &&
|
|
211
|
-
frame.sourceReference.line === thatSrcRef.line
|
|
212
|
-
) {
|
|
213
|
-
return false;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// constructors contain the whole contract, so we ignore them
|
|
218
|
-
if (
|
|
219
|
-
frame.sourceReference.function === "constructor" &&
|
|
220
|
-
nextFrame.sourceReference.function !== "constructor"
|
|
221
|
-
) {
|
|
222
|
-
return true;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// this is probably a recursive call
|
|
226
|
-
if (
|
|
227
|
-
i > 0 &&
|
|
228
|
-
frame.type === nextFrame.type &&
|
|
229
|
-
frame.sourceReference.range[0] === nextFrame.sourceReference.range[0] &&
|
|
230
|
-
frame.sourceReference.range[1] === nextFrame.sourceReference.range[1] &&
|
|
231
|
-
frame.sourceReference.line === nextFrame.sourceReference.line
|
|
232
|
-
) {
|
|
233
|
-
return true;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (
|
|
237
|
-
frame.sourceReference.range[0] <= nextFrame.sourceReference.range[0] &&
|
|
238
|
-
frame.sourceReference.range[1] >= nextFrame.sourceReference.range[1]
|
|
239
|
-
) {
|
|
240
|
-
return false;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
return true;
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Heuristics
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Check if the last submessage can be used to generate the stack trace.
|
|
251
|
-
*/
|
|
252
|
-
private _checkLastSubmessage(
|
|
253
|
-
trace: DecodedEvmMessageTrace,
|
|
254
|
-
stacktrace: SolidityStackTrace,
|
|
255
|
-
lastSubmessageData: SubmessageData | undefined
|
|
256
|
-
): SolidityStackTrace | undefined {
|
|
257
|
-
if (lastSubmessageData === undefined) {
|
|
258
|
-
return undefined;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const inferredStacktrace = [...stacktrace];
|
|
262
|
-
|
|
263
|
-
// get the instruction before the submessage and add it to the stack trace
|
|
264
|
-
const callStep = trace.steps[lastSubmessageData.stepIndex - 1];
|
|
265
|
-
|
|
266
|
-
if (!isEvmStep(callStep)) {
|
|
267
|
-
throw new Error(
|
|
268
|
-
"This should not happen: MessageTrace should be preceded by a EVM step"
|
|
269
|
-
);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const callInst = trace.bytecode.getInstruction(callStep.pc);
|
|
273
|
-
const callStackFrame = instructionToCallstackStackTraceEntry(
|
|
274
|
-
trace.bytecode,
|
|
275
|
-
callInst
|
|
276
|
-
);
|
|
277
|
-
|
|
278
|
-
const lastMessageFailed = lastSubmessageData.messageTrace.exit.isError();
|
|
279
|
-
if (lastMessageFailed) {
|
|
280
|
-
// add the call/create that generated the message to the stack trace
|
|
281
|
-
inferredStacktrace.push(callStackFrame);
|
|
282
|
-
|
|
283
|
-
if (
|
|
284
|
-
this._isSubtraceErrorPropagated(trace, lastSubmessageData.stepIndex) ||
|
|
285
|
-
this._isProxyErrorPropagated(trace, lastSubmessageData.stepIndex)
|
|
286
|
-
) {
|
|
287
|
-
inferredStacktrace.push(...lastSubmessageData.stacktrace);
|
|
288
|
-
|
|
289
|
-
if (
|
|
290
|
-
this._isContractCallRunOutOfGasError(
|
|
291
|
-
trace,
|
|
292
|
-
lastSubmessageData.stepIndex
|
|
293
|
-
)
|
|
294
|
-
) {
|
|
295
|
-
const lastFrame = inferredStacktrace.pop();
|
|
296
|
-
assertHardhatInvariant(
|
|
297
|
-
lastFrame !== undefined,
|
|
298
|
-
"Expected inferred stack trace to have at least one frame"
|
|
299
|
-
);
|
|
300
|
-
inferredStacktrace.push({
|
|
301
|
-
type: StackTraceEntryType.CONTRACT_CALL_RUN_OUT_OF_GAS_ERROR,
|
|
302
|
-
sourceReference: lastFrame.sourceReference,
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
return this._fixInitialModifier(trace, inferredStacktrace);
|
|
307
|
-
}
|
|
308
|
-
} else {
|
|
309
|
-
const isReturnDataSizeError = this._failsRightAfterCall(
|
|
310
|
-
trace,
|
|
311
|
-
lastSubmessageData.stepIndex
|
|
312
|
-
);
|
|
313
|
-
if (isReturnDataSizeError) {
|
|
314
|
-
inferredStacktrace.push({
|
|
315
|
-
type: StackTraceEntryType.RETURNDATA_SIZE_ERROR,
|
|
316
|
-
sourceReference: callStackFrame.sourceReference,
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
return this._fixInitialModifier(trace, inferredStacktrace);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Check if the last call/create that was done failed.
|
|
326
|
-
*/
|
|
327
|
-
private _checkFailedLastCall(
|
|
328
|
-
trace: DecodedEvmMessageTrace,
|
|
329
|
-
stacktrace: SolidityStackTrace
|
|
330
|
-
): SolidityStackTrace | undefined {
|
|
331
|
-
for (let stepIndex = trace.steps.length - 2; stepIndex >= 0; stepIndex--) {
|
|
332
|
-
const step = trace.steps[stepIndex];
|
|
333
|
-
const nextStep = trace.steps[stepIndex + 1];
|
|
334
|
-
|
|
335
|
-
if (!isEvmStep(step)) {
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
const inst = trace.bytecode.getInstruction(step.pc);
|
|
340
|
-
|
|
341
|
-
const isCallOrCreate = isCall(inst.opcode) || isCreate(inst.opcode);
|
|
342
|
-
|
|
343
|
-
if (isCallOrCreate && isEvmStep(nextStep)) {
|
|
344
|
-
if (this._isCallFailedError(trace, stepIndex, inst)) {
|
|
345
|
-
const inferredStacktrace = [
|
|
346
|
-
...stacktrace,
|
|
347
|
-
this._callInstructionToCallFailedToExecuteStackTraceEntry(
|
|
348
|
-
trace.bytecode,
|
|
349
|
-
inst
|
|
350
|
-
),
|
|
351
|
-
];
|
|
352
|
-
|
|
353
|
-
return this._fixInitialModifier(trace, inferredStacktrace);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Check if the execution stopped with a revert or an invalid opcode.
|
|
361
|
-
*/
|
|
362
|
-
private _checkRevertOrInvalidOpcode(
|
|
363
|
-
trace: DecodedEvmMessageTrace,
|
|
364
|
-
stacktrace: SolidityStackTrace,
|
|
365
|
-
lastInstruction: Instruction,
|
|
366
|
-
functionJumpdests: Instruction[],
|
|
367
|
-
jumpedIntoFunction: boolean
|
|
368
|
-
): SolidityStackTrace | undefined {
|
|
369
|
-
if (
|
|
370
|
-
lastInstruction.opcode !== Opcode.REVERT &&
|
|
371
|
-
lastInstruction.opcode !== Opcode.INVALID
|
|
372
|
-
) {
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
const inferredStacktrace = [...stacktrace];
|
|
377
|
-
|
|
378
|
-
if (
|
|
379
|
-
lastInstruction.location !== undefined &&
|
|
380
|
-
(!isDecodedCallTrace(trace) || jumpedIntoFunction)
|
|
381
|
-
) {
|
|
382
|
-
// There should always be a function here, but that's not the case with optimizations.
|
|
383
|
-
//
|
|
384
|
-
// If this is a create trace, we already checked args and nonpayable failures before
|
|
385
|
-
// calling this function.
|
|
386
|
-
//
|
|
387
|
-
// If it's a call trace, we already jumped into a function. But optimizations can happen.
|
|
388
|
-
const failingFunction = lastInstruction.location.getContainingFunction();
|
|
389
|
-
|
|
390
|
-
// If the failure is in a modifier we add an entry with the function/constructor
|
|
391
|
-
if (
|
|
392
|
-
failingFunction !== undefined &&
|
|
393
|
-
failingFunction.type === ContractFunctionType.MODIFIER
|
|
394
|
-
) {
|
|
395
|
-
inferredStacktrace.push(
|
|
396
|
-
this._getEntryBeforeFailureInModifier(trace, functionJumpdests)
|
|
397
|
-
);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const panicStacktrace = this._checkPanic(
|
|
402
|
-
trace,
|
|
403
|
-
inferredStacktrace,
|
|
404
|
-
lastInstruction
|
|
405
|
-
);
|
|
406
|
-
if (panicStacktrace !== undefined) {
|
|
407
|
-
return panicStacktrace;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
const customErrorStacktrace = this._checkCustomErrors(
|
|
411
|
-
trace,
|
|
412
|
-
inferredStacktrace,
|
|
413
|
-
lastInstruction
|
|
414
|
-
);
|
|
415
|
-
if (customErrorStacktrace !== undefined) {
|
|
416
|
-
return customErrorStacktrace;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
if (
|
|
420
|
-
lastInstruction.location !== undefined &&
|
|
421
|
-
(!isDecodedCallTrace(trace) || jumpedIntoFunction)
|
|
422
|
-
) {
|
|
423
|
-
const failingFunction = lastInstruction.location.getContainingFunction();
|
|
424
|
-
|
|
425
|
-
if (failingFunction !== undefined) {
|
|
426
|
-
inferredStacktrace.push(
|
|
427
|
-
this._instructionWithinFunctionToRevertStackTraceEntry(
|
|
428
|
-
trace,
|
|
429
|
-
lastInstruction
|
|
430
|
-
)
|
|
431
|
-
);
|
|
432
|
-
} else if (isDecodedCallTrace(trace)) {
|
|
433
|
-
// This is here because of the optimizations
|
|
434
|
-
const functionSelector =
|
|
435
|
-
trace.bytecode.contract.getFunctionFromSelector(
|
|
436
|
-
trace.calldata.slice(0, 4)
|
|
437
|
-
);
|
|
438
|
-
|
|
439
|
-
// in general this shouldn't happen, but it does when viaIR is enabled,
|
|
440
|
-
// "optimizerSteps": "u" is used, and the called function is fallback or
|
|
441
|
-
// receive
|
|
442
|
-
if (functionSelector === undefined) {
|
|
443
|
-
return;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
inferredStacktrace.push({
|
|
447
|
-
type: StackTraceEntryType.REVERT_ERROR,
|
|
448
|
-
sourceReference: this._getFunctionStartSourceReference(
|
|
449
|
-
trace,
|
|
450
|
-
functionSelector
|
|
451
|
-
),
|
|
452
|
-
message: new ReturnData(trace.returnData),
|
|
453
|
-
isInvalidOpcodeError: lastInstruction.opcode === Opcode.INVALID,
|
|
454
|
-
});
|
|
455
|
-
} else {
|
|
456
|
-
// This is here because of the optimizations
|
|
457
|
-
inferredStacktrace.push({
|
|
458
|
-
type: StackTraceEntryType.REVERT_ERROR,
|
|
459
|
-
sourceReference: this._getConstructorStartSourceReference(trace),
|
|
460
|
-
message: new ReturnData(trace.returnData),
|
|
461
|
-
isInvalidOpcodeError: lastInstruction.opcode === Opcode.INVALID,
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
return this._fixInitialModifier(trace, inferredStacktrace);
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
// If the revert instruction is not mapped but there is return data,
|
|
469
|
-
// we add the frame anyway, sith the best sourceReference we can get
|
|
470
|
-
if (lastInstruction.location === undefined && trace.returnData.length > 0) {
|
|
471
|
-
const revertFrame: RevertErrorStackTraceEntry = {
|
|
472
|
-
type: StackTraceEntryType.REVERT_ERROR,
|
|
473
|
-
sourceReference:
|
|
474
|
-
this._getLastSourceReference(trace) ??
|
|
475
|
-
this._getContractStartWithoutFunctionSourceReference(trace),
|
|
476
|
-
message: new ReturnData(trace.returnData),
|
|
477
|
-
isInvalidOpcodeError: lastInstruction.opcode === Opcode.INVALID,
|
|
478
|
-
};
|
|
479
|
-
inferredStacktrace.push(revertFrame);
|
|
480
|
-
|
|
481
|
-
return this._fixInitialModifier(trace, inferredStacktrace);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
/**
|
|
486
|
-
* Check if the trace reverted with a panic error.
|
|
487
|
-
*/
|
|
488
|
-
private _checkPanic(
|
|
489
|
-
trace: DecodedEvmMessageTrace,
|
|
490
|
-
stacktrace: SolidityStackTrace,
|
|
491
|
-
lastInstruction: Instruction
|
|
492
|
-
): SolidityStackTrace | undefined {
|
|
493
|
-
if (!this._isPanicReturnData(trace.returnData)) {
|
|
494
|
-
return;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
// If the last frame is an internal function, it means that the trace
|
|
498
|
-
// jumped there to return the panic. If that's the case, we remove that
|
|
499
|
-
// frame.
|
|
500
|
-
const lastFrame = stacktrace[stacktrace.length - 1];
|
|
501
|
-
if (
|
|
502
|
-
lastFrame?.type === StackTraceEntryType.INTERNAL_FUNCTION_CALLSTACK_ENTRY
|
|
503
|
-
) {
|
|
504
|
-
stacktrace.splice(-1);
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
const panicReturnData = new ReturnData(trace.returnData);
|
|
508
|
-
const errorCode = panicReturnData.decodePanic();
|
|
509
|
-
|
|
510
|
-
// if the error comes from a call to a zero-initialized function,
|
|
511
|
-
// we remove the last frame, which represents the call, to avoid
|
|
512
|
-
// having duplicated frames
|
|
513
|
-
if (errorCode === 0x51n) {
|
|
514
|
-
stacktrace.splice(-1);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
const inferredStacktrace = [...stacktrace];
|
|
518
|
-
inferredStacktrace.push(
|
|
519
|
-
this._instructionWithinFunctionToPanicStackTraceEntry(
|
|
520
|
-
trace,
|
|
521
|
-
lastInstruction,
|
|
522
|
-
errorCode
|
|
523
|
-
)
|
|
524
|
-
);
|
|
525
|
-
|
|
526
|
-
return this._fixInitialModifier(trace, inferredStacktrace);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
private _checkCustomErrors(
|
|
530
|
-
trace: DecodedEvmMessageTrace,
|
|
531
|
-
stacktrace: SolidityStackTrace,
|
|
532
|
-
lastInstruction: Instruction
|
|
533
|
-
): SolidityStackTrace | undefined {
|
|
534
|
-
const returnData = new ReturnData(trace.returnData);
|
|
535
|
-
|
|
536
|
-
if (returnData.isEmpty() || returnData.isErrorReturnData()) {
|
|
537
|
-
// if there is no return data, or if it's a Error(string),
|
|
538
|
-
// then it can't be a custom error
|
|
539
|
-
return;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
const rawReturnData = Buffer.from(returnData.value).toString("hex");
|
|
543
|
-
let errorMessage = `reverted with an unrecognized custom error (return data: 0x${rawReturnData})`;
|
|
544
|
-
|
|
545
|
-
for (const customError of trace.bytecode.contract.customErrors) {
|
|
546
|
-
if (returnData.matchesSelector(customError.selector)) {
|
|
547
|
-
// if the return data matches a custom error in the called contract,
|
|
548
|
-
// we format the message using the returnData and the custom error instance
|
|
549
|
-
const decodedValues = abi.decode(
|
|
550
|
-
customError.paramTypes,
|
|
551
|
-
returnData.value.slice(4)
|
|
552
|
-
);
|
|
553
|
-
|
|
554
|
-
const params = AbiHelpers.formatValues([...decodedValues]);
|
|
555
|
-
errorMessage = `reverted with custom error '${customError.name}(${params})'`;
|
|
556
|
-
break;
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
const inferredStacktrace = [...stacktrace];
|
|
561
|
-
inferredStacktrace.push(
|
|
562
|
-
this._instructionWithinFunctionToCustomErrorStackTraceEntry(
|
|
563
|
-
trace,
|
|
564
|
-
lastInstruction,
|
|
565
|
-
errorMessage
|
|
566
|
-
)
|
|
567
|
-
);
|
|
568
|
-
|
|
569
|
-
return this._fixInitialModifier(trace, inferredStacktrace);
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
/**
|
|
573
|
-
* Check last instruction to try to infer the error.
|
|
574
|
-
*/
|
|
575
|
-
private _checkLastInstruction(
|
|
576
|
-
trace: DecodedEvmMessageTrace,
|
|
577
|
-
stacktrace: SolidityStackTrace,
|
|
578
|
-
functionJumpdests: Instruction[],
|
|
579
|
-
jumpedIntoFunction: boolean
|
|
580
|
-
): SolidityStackTrace | undefined {
|
|
581
|
-
if (trace.steps.length === 0) {
|
|
582
|
-
return;
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
const lastStep = trace.steps[trace.steps.length - 1];
|
|
586
|
-
|
|
587
|
-
if (!isEvmStep(lastStep)) {
|
|
588
|
-
throw new Error(
|
|
589
|
-
"This should not happen: MessageTrace ends with a subtrace"
|
|
590
|
-
);
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
const lastInstruction = trace.bytecode.getInstruction(lastStep.pc);
|
|
594
|
-
|
|
595
|
-
const revertOrInvalidStacktrace = this._checkRevertOrInvalidOpcode(
|
|
596
|
-
trace,
|
|
597
|
-
stacktrace,
|
|
598
|
-
lastInstruction,
|
|
599
|
-
functionJumpdests,
|
|
600
|
-
jumpedIntoFunction
|
|
601
|
-
);
|
|
602
|
-
|
|
603
|
-
if (revertOrInvalidStacktrace !== undefined) {
|
|
604
|
-
return revertOrInvalidStacktrace;
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
if (isDecodedCallTrace(trace) && !jumpedIntoFunction) {
|
|
608
|
-
if (
|
|
609
|
-
this._hasFailedInsideTheFallbackFunction(trace) ||
|
|
610
|
-
this._hasFailedInsideTheReceiveFunction(trace)
|
|
611
|
-
) {
|
|
612
|
-
return [
|
|
613
|
-
this._instructionWithinFunctionToRevertStackTraceEntry(
|
|
614
|
-
trace,
|
|
615
|
-
lastInstruction
|
|
616
|
-
),
|
|
617
|
-
];
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
// Sometimes we do fail inside of a function but there's no jump into
|
|
621
|
-
if (lastInstruction.location !== undefined) {
|
|
622
|
-
const failingFunction =
|
|
623
|
-
lastInstruction.location.getContainingFunction();
|
|
624
|
-
if (failingFunction !== undefined) {
|
|
625
|
-
return [
|
|
626
|
-
{
|
|
627
|
-
type: StackTraceEntryType.REVERT_ERROR,
|
|
628
|
-
sourceReference: this._getFunctionStartSourceReference(
|
|
629
|
-
trace,
|
|
630
|
-
failingFunction
|
|
631
|
-
),
|
|
632
|
-
message: new ReturnData(trace.returnData),
|
|
633
|
-
isInvalidOpcodeError: lastInstruction.opcode === Opcode.INVALID,
|
|
634
|
-
},
|
|
635
|
-
];
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
const calledFunction = trace.bytecode.contract.getFunctionFromSelector(
|
|
640
|
-
trace.calldata.slice(0, 4)
|
|
641
|
-
);
|
|
642
|
-
|
|
643
|
-
if (calledFunction !== undefined) {
|
|
644
|
-
const isValidCalldata = calledFunction.isValidCalldata(
|
|
645
|
-
trace.calldata.slice(4)
|
|
646
|
-
);
|
|
647
|
-
|
|
648
|
-
if (!isValidCalldata) {
|
|
649
|
-
return [
|
|
650
|
-
{
|
|
651
|
-
type: StackTraceEntryType.INVALID_PARAMS_ERROR,
|
|
652
|
-
sourceReference: this._getFunctionStartSourceReference(
|
|
653
|
-
trace,
|
|
654
|
-
calledFunction
|
|
655
|
-
),
|
|
656
|
-
},
|
|
657
|
-
];
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
if (this._solidity063MaybeUnmappedRevert(trace)) {
|
|
662
|
-
const revertFrame =
|
|
663
|
-
this._solidity063GetFrameForUnmappedRevertBeforeFunction(trace);
|
|
664
|
-
|
|
665
|
-
if (revertFrame !== undefined) {
|
|
666
|
-
return [revertFrame];
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
return [this._getOtherErrorBeforeCalledFunctionStackTraceEntry(trace)];
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
private _checkNonContractCalled(
|
|
675
|
-
trace: DecodedEvmMessageTrace,
|
|
676
|
-
stacktrace: SolidityStackTrace
|
|
677
|
-
): SolidityStackTrace | undefined {
|
|
678
|
-
if (this._isCalledNonContractAccountError(trace)) {
|
|
679
|
-
const sourceReference = this._getLastSourceReference(trace);
|
|
680
|
-
|
|
681
|
-
// We are sure this is not undefined because there was at least a call instruction
|
|
682
|
-
assertHardhatInvariant(
|
|
683
|
-
sourceReference !== undefined,
|
|
684
|
-
"Expected source reference to be defined"
|
|
685
|
-
);
|
|
686
|
-
|
|
687
|
-
const nonContractCalledFrame: SolidityStackTraceEntry = {
|
|
688
|
-
type: StackTraceEntryType.NONCONTRACT_ACCOUNT_CALLED_ERROR,
|
|
689
|
-
sourceReference,
|
|
690
|
-
};
|
|
691
|
-
|
|
692
|
-
return [...stacktrace, nonContractCalledFrame];
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
private _checkSolidity063UnmappedRevert(
|
|
697
|
-
trace: DecodedEvmMessageTrace,
|
|
698
|
-
stacktrace: SolidityStackTrace
|
|
699
|
-
): SolidityStackTrace | undefined {
|
|
700
|
-
if (this._solidity063MaybeUnmappedRevert(trace)) {
|
|
701
|
-
const revertFrame =
|
|
702
|
-
this._solidity063GetFrameForUnmappedRevertWithinFunction(trace);
|
|
703
|
-
|
|
704
|
-
if (revertFrame !== undefined) {
|
|
705
|
-
return [...stacktrace, revertFrame];
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
private _checkContractTooLarge(
|
|
711
|
-
trace: DecodedEvmMessageTrace
|
|
712
|
-
): SolidityStackTrace | undefined {
|
|
713
|
-
if (isCreateTrace(trace) && this._isContractTooLargeError(trace)) {
|
|
714
|
-
return [
|
|
715
|
-
{
|
|
716
|
-
type: StackTraceEntryType.CONTRACT_TOO_LARGE_ERROR,
|
|
717
|
-
sourceReference: this._getConstructorStartSourceReference(trace),
|
|
718
|
-
},
|
|
719
|
-
];
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
private _otherExecutionErrorStacktrace(
|
|
724
|
-
trace: DecodedEvmMessageTrace,
|
|
725
|
-
stacktrace: SolidityStackTrace
|
|
726
|
-
): SolidityStackTrace {
|
|
727
|
-
const otherExecutionErrorFrame: SolidityStackTraceEntry = {
|
|
728
|
-
type: StackTraceEntryType.OTHER_EXECUTION_ERROR,
|
|
729
|
-
sourceReference: this._getLastSourceReference(trace),
|
|
730
|
-
};
|
|
731
|
-
|
|
732
|
-
return [...stacktrace, otherExecutionErrorFrame];
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
// Helpers
|
|
736
|
-
|
|
737
|
-
private _fixInitialModifier(
|
|
738
|
-
trace: DecodedEvmMessageTrace,
|
|
739
|
-
stacktrace: SolidityStackTrace
|
|
740
|
-
): SolidityStackTrace {
|
|
741
|
-
const firstEntry = stacktrace[0];
|
|
742
|
-
if (
|
|
743
|
-
firstEntry !== undefined &&
|
|
744
|
-
firstEntry.type === StackTraceEntryType.CALLSTACK_ENTRY &&
|
|
745
|
-
firstEntry.functionType === ContractFunctionType.MODIFIER
|
|
746
|
-
) {
|
|
747
|
-
return [
|
|
748
|
-
this._getEntryBeforeInitialModifierCallstackEntry(trace),
|
|
749
|
-
...stacktrace,
|
|
750
|
-
];
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
return stacktrace;
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
private _isDirectLibraryCall(trace: DecodedCallMessageTrace): boolean {
|
|
757
|
-
return (
|
|
758
|
-
trace.depth === 0 && trace.bytecode.contract.type === ContractType.LIBRARY
|
|
759
|
-
);
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
private _getDirectLibraryCallErrorStackTrace(
|
|
763
|
-
trace: DecodedCallMessageTrace
|
|
764
|
-
): SolidityStackTrace {
|
|
765
|
-
const func = trace.bytecode.contract.getFunctionFromSelector(
|
|
766
|
-
trace.calldata.slice(0, 4)
|
|
767
|
-
);
|
|
768
|
-
|
|
769
|
-
if (func !== undefined) {
|
|
770
|
-
return [
|
|
771
|
-
{
|
|
772
|
-
type: StackTraceEntryType.DIRECT_LIBRARY_CALL_ERROR,
|
|
773
|
-
sourceReference: this._getFunctionStartSourceReference(trace, func),
|
|
774
|
-
},
|
|
775
|
-
];
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
return [
|
|
779
|
-
{
|
|
780
|
-
type: StackTraceEntryType.DIRECT_LIBRARY_CALL_ERROR,
|
|
781
|
-
sourceReference:
|
|
782
|
-
this._getContractStartWithoutFunctionSourceReference(trace),
|
|
783
|
-
},
|
|
784
|
-
];
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
private _isFunctionNotPayableError(
|
|
788
|
-
trace: DecodedCallMessageTrace,
|
|
789
|
-
calledFunction: ContractFunction
|
|
790
|
-
): boolean {
|
|
791
|
-
// This error doesn't return data
|
|
792
|
-
if (trace.returnData.length > 0) {
|
|
793
|
-
return false;
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
if (trace.value <= 0n) {
|
|
797
|
-
return false;
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
// Libraries don't have a nonpayable check
|
|
801
|
-
if (trace.bytecode.contract.type === ContractType.LIBRARY) {
|
|
802
|
-
return false;
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
return calledFunction.isPayable === undefined || !calledFunction.isPayable;
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
private _getFunctionStartSourceReference(
|
|
809
|
-
trace: DecodedEvmMessageTrace,
|
|
810
|
-
func: ContractFunction
|
|
811
|
-
): SourceReference {
|
|
812
|
-
return {
|
|
813
|
-
sourceName: func.location.file.sourceName,
|
|
814
|
-
sourceContent: func.location.file.content,
|
|
815
|
-
contract: trace.bytecode.contract.name,
|
|
816
|
-
function: func.name,
|
|
817
|
-
line: func.location.getStartingLineNumber(),
|
|
818
|
-
range: [
|
|
819
|
-
func.location.offset,
|
|
820
|
-
func.location.offset + func.location.length,
|
|
821
|
-
],
|
|
822
|
-
};
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
private _isMissingFunctionAndFallbackError(
|
|
826
|
-
trace: DecodedCallMessageTrace,
|
|
827
|
-
calledFunction: ContractFunction | undefined
|
|
828
|
-
): boolean {
|
|
829
|
-
// This error doesn't return data
|
|
830
|
-
if (trace.returnData.length > 0) {
|
|
831
|
-
return false;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
// the called function exists in the contract
|
|
835
|
-
if (calledFunction !== undefined) {
|
|
836
|
-
return false;
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
// there's a receive function and no calldata
|
|
840
|
-
if (
|
|
841
|
-
trace.calldata.length === 0 &&
|
|
842
|
-
trace.bytecode.contract.receive !== undefined
|
|
843
|
-
) {
|
|
844
|
-
return false;
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
return trace.bytecode.contract.fallback === undefined;
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
private _emptyCalldataAndNoReceive(trace: DecodedCallMessageTrace): boolean {
|
|
851
|
-
// this only makes sense when receive functions are available
|
|
852
|
-
if (
|
|
853
|
-
semver.lt(
|
|
854
|
-
trace.bytecode.compilerVersion,
|
|
855
|
-
FIRST_SOLC_VERSION_RECEIVE_FUNCTION
|
|
856
|
-
)
|
|
857
|
-
) {
|
|
858
|
-
return false;
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
return (
|
|
862
|
-
trace.calldata.length === 0 &&
|
|
863
|
-
trace.bytecode.contract.receive === undefined
|
|
864
|
-
);
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
private _getContractStartWithoutFunctionSourceReference(
|
|
868
|
-
trace: DecodedEvmMessageTrace
|
|
869
|
-
): SourceReference {
|
|
870
|
-
const location = trace.bytecode.contract.location;
|
|
871
|
-
return {
|
|
872
|
-
sourceName: location.file.sourceName,
|
|
873
|
-
sourceContent: location.file.content,
|
|
874
|
-
contract: trace.bytecode.contract.name,
|
|
875
|
-
line: location.getStartingLineNumber(),
|
|
876
|
-
range: [location.offset, location.offset + location.length],
|
|
877
|
-
};
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
private _isFallbackNotPayableError(
|
|
881
|
-
trace: DecodedCallMessageTrace,
|
|
882
|
-
calledFunction: ContractFunction | undefined
|
|
883
|
-
): boolean {
|
|
884
|
-
if (calledFunction !== undefined) {
|
|
885
|
-
return false;
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
// This error doesn't return data
|
|
889
|
-
if (trace.returnData.length > 0) {
|
|
890
|
-
return false;
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
if (trace.value <= 0n) {
|
|
894
|
-
return false;
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
if (trace.bytecode.contract.fallback === undefined) {
|
|
898
|
-
return false;
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
const isPayable = trace.bytecode.contract.fallback.isPayable;
|
|
902
|
-
|
|
903
|
-
return isPayable === undefined || !isPayable;
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
private _getFallbackStartSourceReference(
|
|
907
|
-
trace: DecodedCallMessageTrace
|
|
908
|
-
): SourceReference {
|
|
909
|
-
const func = trace.bytecode.contract.fallback;
|
|
910
|
-
|
|
911
|
-
if (func === undefined) {
|
|
912
|
-
throw new Error(
|
|
913
|
-
"This shouldn't happen: trying to get fallback source reference from a contract without fallback"
|
|
914
|
-
);
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
return {
|
|
918
|
-
sourceName: func.location.file.sourceName,
|
|
919
|
-
sourceContent: func.location.file.content,
|
|
920
|
-
contract: trace.bytecode.contract.name,
|
|
921
|
-
function: FALLBACK_FUNCTION_NAME,
|
|
922
|
-
line: func.location.getStartingLineNumber(),
|
|
923
|
-
range: [
|
|
924
|
-
func.location.offset,
|
|
925
|
-
func.location.offset + func.location.length,
|
|
926
|
-
],
|
|
927
|
-
};
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
private _isConstructorNotPayableError(
|
|
931
|
-
trace: DecodedCreateMessageTrace
|
|
932
|
-
): boolean {
|
|
933
|
-
// This error doesn't return data
|
|
934
|
-
if (trace.returnData.length > 0) {
|
|
935
|
-
return false;
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
const constructor = trace.bytecode.contract.constructorFunction;
|
|
939
|
-
|
|
940
|
-
// This function is only matters with contracts that have constructors defined. The ones that
|
|
941
|
-
// don't are abstract contracts, or their constructor doesn't take any argument.
|
|
942
|
-
if (constructor === undefined) {
|
|
943
|
-
return false;
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
return (
|
|
947
|
-
trace.value > 0n &&
|
|
948
|
-
(constructor.isPayable === undefined || !constructor.isPayable)
|
|
949
|
-
);
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
/**
|
|
953
|
-
* Returns a source reference pointing to the constructor if it exists, or to the contract
|
|
954
|
-
* otherwise.
|
|
955
|
-
*/
|
|
956
|
-
private _getConstructorStartSourceReference(
|
|
957
|
-
trace: DecodedCreateMessageTrace
|
|
958
|
-
): SourceReference {
|
|
959
|
-
const contract = trace.bytecode.contract;
|
|
960
|
-
const constructor = contract.constructorFunction;
|
|
961
|
-
|
|
962
|
-
const line =
|
|
963
|
-
constructor !== undefined
|
|
964
|
-
? constructor.location.getStartingLineNumber()
|
|
965
|
-
: contract.location.getStartingLineNumber();
|
|
966
|
-
|
|
967
|
-
return {
|
|
968
|
-
sourceName: contract.location.file.sourceName,
|
|
969
|
-
sourceContent: contract.location.file.content,
|
|
970
|
-
contract: contract.name,
|
|
971
|
-
function: CONSTRUCTOR_FUNCTION_NAME,
|
|
972
|
-
line,
|
|
973
|
-
range: [
|
|
974
|
-
contract.location.offset,
|
|
975
|
-
contract.location.offset + contract.location.length,
|
|
976
|
-
],
|
|
977
|
-
};
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
private _isConstructorInvalidArgumentsError(
|
|
981
|
-
trace: DecodedCreateMessageTrace
|
|
982
|
-
): boolean {
|
|
983
|
-
// This error doesn't return data
|
|
984
|
-
if (trace.returnData.length > 0) {
|
|
985
|
-
return false;
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
const contract = trace.bytecode.contract;
|
|
989
|
-
const constructor = contract.constructorFunction;
|
|
990
|
-
|
|
991
|
-
// This function is only matters with contracts that have constructors defined. The ones that
|
|
992
|
-
// don't are abstract contracts, or their constructor doesn't take any argument.
|
|
993
|
-
if (constructor === undefined) {
|
|
994
|
-
return false;
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
if (
|
|
998
|
-
semver.lt(
|
|
999
|
-
trace.bytecode.compilerVersion,
|
|
1000
|
-
FIRST_SOLC_VERSION_CREATE_PARAMS_VALIDATION
|
|
1001
|
-
)
|
|
1002
|
-
) {
|
|
1003
|
-
return false;
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
const lastStep = trace.steps[trace.steps.length - 1];
|
|
1007
|
-
if (!isEvmStep(lastStep)) {
|
|
1008
|
-
return false;
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
const lastInst = trace.bytecode.getInstruction(lastStep.pc);
|
|
1012
|
-
if (lastInst.opcode !== Opcode.REVERT || lastInst.location !== undefined) {
|
|
1013
|
-
return false;
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
let hasReadDeploymentCodeSize = false;
|
|
1017
|
-
|
|
1018
|
-
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
1019
|
-
for (let stepIndex = 0; stepIndex < trace.steps.length; stepIndex++) {
|
|
1020
|
-
const step = trace.steps[stepIndex];
|
|
1021
|
-
if (!isEvmStep(step)) {
|
|
1022
|
-
return false;
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
const inst = trace.bytecode.getInstruction(step.pc);
|
|
1026
|
-
|
|
1027
|
-
if (
|
|
1028
|
-
inst.location !== undefined &&
|
|
1029
|
-
!contract.location.equals(inst.location) &&
|
|
1030
|
-
!constructor.location.equals(inst.location)
|
|
1031
|
-
) {
|
|
1032
|
-
return false;
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
if (inst.opcode === Opcode.CODESIZE && isCreateTrace(trace)) {
|
|
1036
|
-
hasReadDeploymentCodeSize = true;
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
return hasReadDeploymentCodeSize;
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
private _getEntryBeforeInitialModifierCallstackEntry(
|
|
1044
|
-
trace: DecodedEvmMessageTrace
|
|
1045
|
-
): SolidityStackTraceEntry {
|
|
1046
|
-
if (isDecodedCreateTrace(trace)) {
|
|
1047
|
-
return {
|
|
1048
|
-
type: StackTraceEntryType.CALLSTACK_ENTRY,
|
|
1049
|
-
sourceReference: this._getConstructorStartSourceReference(trace),
|
|
1050
|
-
functionType: ContractFunctionType.CONSTRUCTOR,
|
|
1051
|
-
};
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
const calledFunction = trace.bytecode.contract.getFunctionFromSelector(
|
|
1055
|
-
trace.calldata.slice(0, 4)
|
|
1056
|
-
);
|
|
1057
|
-
|
|
1058
|
-
if (calledFunction !== undefined) {
|
|
1059
|
-
return {
|
|
1060
|
-
type: StackTraceEntryType.CALLSTACK_ENTRY,
|
|
1061
|
-
sourceReference: this._getFunctionStartSourceReference(
|
|
1062
|
-
trace,
|
|
1063
|
-
calledFunction
|
|
1064
|
-
),
|
|
1065
|
-
functionType: ContractFunctionType.FUNCTION,
|
|
1066
|
-
};
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
// If it failed or made a call from within a modifier, and the selector doesn't match
|
|
1070
|
-
// any function, it must have a fallback.
|
|
1071
|
-
return {
|
|
1072
|
-
type: StackTraceEntryType.CALLSTACK_ENTRY,
|
|
1073
|
-
sourceReference: this._getFallbackStartSourceReference(trace),
|
|
1074
|
-
functionType: ContractFunctionType.FALLBACK,
|
|
1075
|
-
};
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
private _getLastSourceReference(
|
|
1079
|
-
trace: DecodedEvmMessageTrace
|
|
1080
|
-
): SourceReference | undefined {
|
|
1081
|
-
for (let i = trace.steps.length - 1; i >= 0; i--) {
|
|
1082
|
-
const step = trace.steps[i];
|
|
1083
|
-
if (!isEvmStep(step)) {
|
|
1084
|
-
continue;
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
const inst = trace.bytecode.getInstruction(step.pc);
|
|
1088
|
-
|
|
1089
|
-
if (inst.location === undefined) {
|
|
1090
|
-
continue;
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
const sourceReference = sourceLocationToSourceReference(
|
|
1094
|
-
trace.bytecode,
|
|
1095
|
-
inst.location
|
|
1096
|
-
);
|
|
1097
|
-
|
|
1098
|
-
if (sourceReference !== undefined) {
|
|
1099
|
-
return sourceReference;
|
|
1100
|
-
}
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
return undefined;
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
private _hasFailedInsideTheFallbackFunction(
|
|
1107
|
-
trace: DecodedCallMessageTrace
|
|
1108
|
-
): boolean {
|
|
1109
|
-
const contract = trace.bytecode.contract;
|
|
1110
|
-
|
|
1111
|
-
if (contract.fallback === undefined) {
|
|
1112
|
-
return false;
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
return this._hasFailedInsideFunction(trace, contract.fallback);
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
private _hasFailedInsideTheReceiveFunction(
|
|
1119
|
-
trace: DecodedCallMessageTrace
|
|
1120
|
-
): boolean {
|
|
1121
|
-
const contract = trace.bytecode.contract;
|
|
1122
|
-
|
|
1123
|
-
if (contract.receive === undefined) {
|
|
1124
|
-
return false;
|
|
1125
|
-
}
|
|
1126
|
-
|
|
1127
|
-
return this._hasFailedInsideFunction(trace, contract.receive);
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
private _hasFailedInsideFunction(
|
|
1131
|
-
trace: DecodedCallMessageTrace,
|
|
1132
|
-
func: ContractFunction
|
|
1133
|
-
) {
|
|
1134
|
-
const lastStep = trace.steps[trace.steps.length - 1] as EvmStep;
|
|
1135
|
-
const lastInstruction = trace.bytecode.getInstruction(lastStep.pc);
|
|
1136
|
-
|
|
1137
|
-
return (
|
|
1138
|
-
lastInstruction.location !== undefined &&
|
|
1139
|
-
lastInstruction.opcode === Opcode.REVERT &&
|
|
1140
|
-
func.location.contains(lastInstruction.location)
|
|
1141
|
-
);
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
private _instructionWithinFunctionToRevertStackTraceEntry(
|
|
1145
|
-
trace: DecodedEvmMessageTrace,
|
|
1146
|
-
inst: Instruction
|
|
1147
|
-
): RevertErrorStackTraceEntry {
|
|
1148
|
-
const sourceReference = sourceLocationToSourceReference(
|
|
1149
|
-
trace.bytecode,
|
|
1150
|
-
inst.location
|
|
1151
|
-
);
|
|
1152
|
-
assertHardhatInvariant(
|
|
1153
|
-
sourceReference !== undefined,
|
|
1154
|
-
"Expected source reference to be defined"
|
|
1155
|
-
);
|
|
1156
|
-
|
|
1157
|
-
return {
|
|
1158
|
-
type: StackTraceEntryType.REVERT_ERROR,
|
|
1159
|
-
sourceReference,
|
|
1160
|
-
message: new ReturnData(trace.returnData),
|
|
1161
|
-
isInvalidOpcodeError: inst.opcode === Opcode.INVALID,
|
|
1162
|
-
};
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
|
-
private _instructionWithinFunctionToUnmappedSolc063RevertErrorStackTraceEntry(
|
|
1166
|
-
trace: DecodedEvmMessageTrace,
|
|
1167
|
-
inst: Instruction
|
|
1168
|
-
): UnmappedSolc063RevertErrorStackTraceEntry {
|
|
1169
|
-
const sourceReference = sourceLocationToSourceReference(
|
|
1170
|
-
trace.bytecode,
|
|
1171
|
-
inst.location
|
|
1172
|
-
);
|
|
1173
|
-
|
|
1174
|
-
return {
|
|
1175
|
-
type: StackTraceEntryType.UNMAPPED_SOLC_0_6_3_REVERT_ERROR,
|
|
1176
|
-
sourceReference,
|
|
1177
|
-
};
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
private _instructionWithinFunctionToPanicStackTraceEntry(
|
|
1181
|
-
trace: DecodedEvmMessageTrace,
|
|
1182
|
-
inst: Instruction,
|
|
1183
|
-
errorCode: bigint
|
|
1184
|
-
): PanicErrorStackTraceEntry {
|
|
1185
|
-
const lastSourceReference = this._getLastSourceReference(trace);
|
|
1186
|
-
return {
|
|
1187
|
-
type: StackTraceEntryType.PANIC_ERROR,
|
|
1188
|
-
sourceReference:
|
|
1189
|
-
sourceLocationToSourceReference(trace.bytecode, inst.location) ??
|
|
1190
|
-
lastSourceReference,
|
|
1191
|
-
errorCode,
|
|
1192
|
-
};
|
|
1193
|
-
}
|
|
1194
|
-
|
|
1195
|
-
private _instructionWithinFunctionToCustomErrorStackTraceEntry(
|
|
1196
|
-
trace: DecodedEvmMessageTrace,
|
|
1197
|
-
inst: Instruction,
|
|
1198
|
-
message: string
|
|
1199
|
-
): CustomErrorStackTraceEntry {
|
|
1200
|
-
const lastSourceReference = this._getLastSourceReference(trace);
|
|
1201
|
-
|
|
1202
|
-
assertHardhatInvariant(
|
|
1203
|
-
lastSourceReference !== undefined,
|
|
1204
|
-
"Expected last source reference to be defined"
|
|
1205
|
-
);
|
|
1206
|
-
|
|
1207
|
-
return {
|
|
1208
|
-
type: StackTraceEntryType.CUSTOM_ERROR,
|
|
1209
|
-
sourceReference:
|
|
1210
|
-
sourceLocationToSourceReference(trace.bytecode, inst.location) ??
|
|
1211
|
-
lastSourceReference,
|
|
1212
|
-
message,
|
|
1213
|
-
};
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
|
-
private _solidity063MaybeUnmappedRevert(trace: DecodedEvmMessageTrace) {
|
|
1217
|
-
if (trace.steps.length === 0) {
|
|
1218
|
-
return false;
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
const lastStep = trace.steps[trace.steps.length - 1];
|
|
1222
|
-
if (!isEvmStep(lastStep)) {
|
|
1223
|
-
return false;
|
|
1224
|
-
}
|
|
1225
|
-
|
|
1226
|
-
const lastInst = trace.bytecode.getInstruction(lastStep.pc);
|
|
1227
|
-
|
|
1228
|
-
return (
|
|
1229
|
-
semver.satisfies(
|
|
1230
|
-
trace.bytecode.compilerVersion,
|
|
1231
|
-
`^${FIRST_SOLC_VERSION_WITH_UNMAPPED_REVERTS}`
|
|
1232
|
-
) && lastInst.opcode === Opcode.REVERT
|
|
1233
|
-
);
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
|
-
// Solidity 0.6.3 unmapped reverts special handling
|
|
1237
|
-
// For more info: https://github.com/ethereum/solidity/issues/9006
|
|
1238
|
-
private _solidity063GetFrameForUnmappedRevertBeforeFunction(
|
|
1239
|
-
trace: DecodedCallMessageTrace
|
|
1240
|
-
) {
|
|
1241
|
-
let revertFrame =
|
|
1242
|
-
this._solidity063GetFrameForUnmappedRevertWithinFunction(trace);
|
|
1243
|
-
|
|
1244
|
-
if (
|
|
1245
|
-
revertFrame === undefined ||
|
|
1246
|
-
revertFrame.sourceReference === undefined
|
|
1247
|
-
) {
|
|
1248
|
-
if (
|
|
1249
|
-
trace.bytecode.contract.receive === undefined ||
|
|
1250
|
-
trace.calldata.length > 0
|
|
1251
|
-
) {
|
|
1252
|
-
if (trace.bytecode.contract.fallback !== undefined) {
|
|
1253
|
-
// Failed within the fallback
|
|
1254
|
-
const location = trace.bytecode.contract.fallback.location;
|
|
1255
|
-
revertFrame = {
|
|
1256
|
-
type: StackTraceEntryType.UNMAPPED_SOLC_0_6_3_REVERT_ERROR,
|
|
1257
|
-
sourceReference: {
|
|
1258
|
-
contract: trace.bytecode.contract.name,
|
|
1259
|
-
function: FALLBACK_FUNCTION_NAME,
|
|
1260
|
-
sourceName: location.file.sourceName,
|
|
1261
|
-
sourceContent: location.file.content,
|
|
1262
|
-
line: location.getStartingLineNumber(),
|
|
1263
|
-
range: [location.offset, location.offset + location.length],
|
|
1264
|
-
},
|
|
1265
|
-
};
|
|
1266
|
-
|
|
1267
|
-
this._solidity063CorrectLineNumber(revertFrame);
|
|
1268
|
-
}
|
|
1269
|
-
} else {
|
|
1270
|
-
// Failed within the receive function
|
|
1271
|
-
const location = trace.bytecode.contract.receive.location;
|
|
1272
|
-
revertFrame = {
|
|
1273
|
-
type: StackTraceEntryType.UNMAPPED_SOLC_0_6_3_REVERT_ERROR,
|
|
1274
|
-
sourceReference: {
|
|
1275
|
-
contract: trace.bytecode.contract.name,
|
|
1276
|
-
function: RECEIVE_FUNCTION_NAME,
|
|
1277
|
-
sourceName: location.file.sourceName,
|
|
1278
|
-
sourceContent: location.file.content,
|
|
1279
|
-
line: location.getStartingLineNumber(),
|
|
1280
|
-
range: [location.offset, location.offset + location.length],
|
|
1281
|
-
},
|
|
1282
|
-
};
|
|
1283
|
-
|
|
1284
|
-
this._solidity063CorrectLineNumber(revertFrame);
|
|
1285
|
-
}
|
|
1286
|
-
}
|
|
1287
|
-
return revertFrame;
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
private _getOtherErrorBeforeCalledFunctionStackTraceEntry(
|
|
1291
|
-
trace: DecodedCallMessageTrace
|
|
1292
|
-
): OtherExecutionErrorStackTraceEntry {
|
|
1293
|
-
return {
|
|
1294
|
-
type: StackTraceEntryType.OTHER_EXECUTION_ERROR,
|
|
1295
|
-
sourceReference:
|
|
1296
|
-
this._getContractStartWithoutFunctionSourceReference(trace),
|
|
1297
|
-
};
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
private _isCalledNonContractAccountError(
|
|
1301
|
-
trace: DecodedEvmMessageTrace
|
|
1302
|
-
): boolean {
|
|
1303
|
-
// We could change this to checking that the last valid location maps to a call, but
|
|
1304
|
-
// it's way more complex as we need to get the ast node from that location.
|
|
1305
|
-
|
|
1306
|
-
const lastIndex = this._getLastInstructionWithValidLocationStepIndex(trace);
|
|
1307
|
-
if (lastIndex === undefined || lastIndex === 0) {
|
|
1308
|
-
return false;
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
const lastStep = trace.steps[lastIndex] as EvmStep; // We know this is an EVM step
|
|
1312
|
-
const lastInst = trace.bytecode.getInstruction(lastStep.pc);
|
|
1313
|
-
if (lastInst.opcode !== Opcode.ISZERO) {
|
|
1314
|
-
return false;
|
|
1315
|
-
}
|
|
1316
|
-
|
|
1317
|
-
const prevStep = trace.steps[lastIndex - 1] as EvmStep; // We know this is an EVM step
|
|
1318
|
-
const prevInst = trace.bytecode.getInstruction(prevStep.pc);
|
|
1319
|
-
return prevInst.opcode === Opcode.EXTCODESIZE;
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
|
-
private _solidity063GetFrameForUnmappedRevertWithinFunction(
|
|
1323
|
-
trace: DecodedEvmMessageTrace
|
|
1324
|
-
): UnmappedSolc063RevertErrorStackTraceEntry | undefined {
|
|
1325
|
-
// If we are within a function there's a last valid location. It may
|
|
1326
|
-
// be the entire contract.
|
|
1327
|
-
const prevInst = this._getLastInstructionWithValidLocation(trace);
|
|
1328
|
-
const lastStep = trace.steps[trace.steps.length - 1] as EvmStep;
|
|
1329
|
-
const nextInstPc = lastStep.pc + 1;
|
|
1330
|
-
const hasNextInst = trace.bytecode.hasInstruction(nextInstPc);
|
|
1331
|
-
|
|
1332
|
-
if (hasNextInst) {
|
|
1333
|
-
const nextInst = trace.bytecode.getInstruction(nextInstPc);
|
|
1334
|
-
const prevLoc = prevInst?.location;
|
|
1335
|
-
const nextLoc = nextInst.location;
|
|
1336
|
-
const prevFunc = prevLoc?.getContainingFunction();
|
|
1337
|
-
const nextFunc = nextLoc?.getContainingFunction();
|
|
1338
|
-
|
|
1339
|
-
// This is probably a require. This means that we have the exact
|
|
1340
|
-
// line, but the stack trace may be degraded (e.g. missing our
|
|
1341
|
-
// synthetic call frames when failing in a modifier) so we still
|
|
1342
|
-
// add this frame as UNMAPPED_SOLC_0_6_3_REVERT_ERROR
|
|
1343
|
-
if (
|
|
1344
|
-
prevFunc !== undefined &&
|
|
1345
|
-
nextLoc !== undefined &&
|
|
1346
|
-
prevLoc !== undefined &&
|
|
1347
|
-
prevLoc.equals(nextLoc)
|
|
1348
|
-
) {
|
|
1349
|
-
return this._instructionWithinFunctionToUnmappedSolc063RevertErrorStackTraceEntry(
|
|
1350
|
-
trace,
|
|
1351
|
-
nextInst
|
|
1352
|
-
);
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
let revertFrame: UnmappedSolc063RevertErrorStackTraceEntry | undefined;
|
|
1356
|
-
|
|
1357
|
-
// If the previous and next location don't match, we try to use the
|
|
1358
|
-
// previous one if it's inside a function, otherwise we use the next one
|
|
1359
|
-
if (prevFunc !== undefined && prevInst !== undefined) {
|
|
1360
|
-
revertFrame =
|
|
1361
|
-
this._instructionWithinFunctionToUnmappedSolc063RevertErrorStackTraceEntry(
|
|
1362
|
-
trace,
|
|
1363
|
-
prevInst
|
|
1364
|
-
);
|
|
1365
|
-
} else if (nextFunc !== undefined) {
|
|
1366
|
-
revertFrame =
|
|
1367
|
-
this._instructionWithinFunctionToUnmappedSolc063RevertErrorStackTraceEntry(
|
|
1368
|
-
trace,
|
|
1369
|
-
nextInst
|
|
1370
|
-
);
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
|
-
if (revertFrame !== undefined) {
|
|
1374
|
-
this._solidity063CorrectLineNumber(revertFrame);
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
|
-
return revertFrame;
|
|
1378
|
-
}
|
|
1379
|
-
|
|
1380
|
-
if (isCreateTrace(trace) && prevInst !== undefined) {
|
|
1381
|
-
// Solidity is smart enough to stop emitting extra instructions after
|
|
1382
|
-
// an unconditional revert happens in a constructor. If this is the case
|
|
1383
|
-
// we just return a special error.
|
|
1384
|
-
const constructorRevertFrame: UnmappedSolc063RevertErrorStackTraceEntry =
|
|
1385
|
-
this._instructionWithinFunctionToUnmappedSolc063RevertErrorStackTraceEntry(
|
|
1386
|
-
trace,
|
|
1387
|
-
prevInst
|
|
1388
|
-
);
|
|
1389
|
-
|
|
1390
|
-
// When the latest instruction is not within a function we need
|
|
1391
|
-
// some default sourceReference to show to the user
|
|
1392
|
-
if (constructorRevertFrame.sourceReference === undefined) {
|
|
1393
|
-
const location = trace.bytecode.contract.location;
|
|
1394
|
-
const defaultSourceReference: SourceReference = {
|
|
1395
|
-
function: CONSTRUCTOR_FUNCTION_NAME,
|
|
1396
|
-
contract: trace.bytecode.contract.name,
|
|
1397
|
-
sourceName: location.file.sourceName,
|
|
1398
|
-
sourceContent: location.file.content,
|
|
1399
|
-
line: location.getStartingLineNumber(),
|
|
1400
|
-
range: [location.offset, location.offset + location.length],
|
|
1401
|
-
};
|
|
1402
|
-
|
|
1403
|
-
if (trace.bytecode.contract.constructorFunction !== undefined) {
|
|
1404
|
-
defaultSourceReference.line =
|
|
1405
|
-
trace.bytecode.contract.constructorFunction.location.getStartingLineNumber();
|
|
1406
|
-
}
|
|
1407
|
-
|
|
1408
|
-
constructorRevertFrame.sourceReference = defaultSourceReference;
|
|
1409
|
-
} else {
|
|
1410
|
-
this._solidity063CorrectLineNumber(constructorRevertFrame);
|
|
1411
|
-
}
|
|
1412
|
-
|
|
1413
|
-
return constructorRevertFrame;
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
|
-
if (prevInst !== undefined) {
|
|
1417
|
-
// We may as well just be in a function or modifier and just happen
|
|
1418
|
-
// to be at the last instruction of the runtime bytecode.
|
|
1419
|
-
// In this case we just return whatever the last mapped intruction
|
|
1420
|
-
// points to.
|
|
1421
|
-
const latestInstructionRevertFrame: UnmappedSolc063RevertErrorStackTraceEntry =
|
|
1422
|
-
this._instructionWithinFunctionToUnmappedSolc063RevertErrorStackTraceEntry(
|
|
1423
|
-
trace,
|
|
1424
|
-
prevInst
|
|
1425
|
-
);
|
|
1426
|
-
|
|
1427
|
-
if (latestInstructionRevertFrame.sourceReference !== undefined) {
|
|
1428
|
-
this._solidity063CorrectLineNumber(latestInstructionRevertFrame);
|
|
1429
|
-
}
|
|
1430
|
-
return latestInstructionRevertFrame;
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
private _isContractTooLargeError(trace: DecodedCreateMessageTrace) {
|
|
1435
|
-
return trace.exit.kind === ExitCode.CODESIZE_EXCEEDS_MAXIMUM;
|
|
1436
|
-
}
|
|
1437
|
-
|
|
1438
|
-
private _solidity063CorrectLineNumber(
|
|
1439
|
-
revertFrame: UnmappedSolc063RevertErrorStackTraceEntry
|
|
1440
|
-
) {
|
|
1441
|
-
if (revertFrame.sourceReference === undefined) {
|
|
1442
|
-
return;
|
|
1443
|
-
}
|
|
1444
|
-
|
|
1445
|
-
const lines = revertFrame.sourceReference.sourceContent.split("\n");
|
|
1446
|
-
|
|
1447
|
-
const currentLine = lines[revertFrame.sourceReference.line - 1];
|
|
1448
|
-
|
|
1449
|
-
if (currentLine.includes("require") || currentLine.includes("revert")) {
|
|
1450
|
-
return;
|
|
1451
|
-
}
|
|
1452
|
-
|
|
1453
|
-
const nextLines = lines.slice(revertFrame.sourceReference.line);
|
|
1454
|
-
const firstNonEmptyLine = nextLines.findIndex((l) => l.trim() !== "");
|
|
1455
|
-
|
|
1456
|
-
if (firstNonEmptyLine === -1) {
|
|
1457
|
-
return;
|
|
1458
|
-
}
|
|
1459
|
-
|
|
1460
|
-
const nextLine = nextLines[firstNonEmptyLine];
|
|
1461
|
-
|
|
1462
|
-
if (nextLine.includes("require") || nextLine.includes("revert")) {
|
|
1463
|
-
revertFrame.sourceReference.line += 1 + firstNonEmptyLine;
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1467
|
-
private _getLastInstructionWithValidLocationStepIndex(
|
|
1468
|
-
trace: DecodedEvmMessageTrace
|
|
1469
|
-
): number | undefined {
|
|
1470
|
-
for (let i = trace.steps.length - 1; i >= 0; i--) {
|
|
1471
|
-
const step = trace.steps[i];
|
|
1472
|
-
|
|
1473
|
-
if (!isEvmStep(step)) {
|
|
1474
|
-
return undefined;
|
|
1475
|
-
}
|
|
1476
|
-
|
|
1477
|
-
const inst = trace.bytecode.getInstruction(step.pc);
|
|
1478
|
-
|
|
1479
|
-
if (inst.location !== undefined) {
|
|
1480
|
-
return i;
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
return undefined;
|
|
1485
|
-
}
|
|
1486
|
-
|
|
1487
|
-
private _getLastInstructionWithValidLocation(
|
|
1488
|
-
trace: DecodedEvmMessageTrace
|
|
1489
|
-
): Instruction | undefined {
|
|
1490
|
-
const lastLocationIndex =
|
|
1491
|
-
this._getLastInstructionWithValidLocationStepIndex(trace);
|
|
1492
|
-
|
|
1493
|
-
if (lastLocationIndex === undefined) {
|
|
1494
|
-
return undefined;
|
|
1495
|
-
}
|
|
1496
|
-
|
|
1497
|
-
const lastLocationStep = trace.steps[lastLocationIndex];
|
|
1498
|
-
if (isEvmStep(lastLocationStep)) {
|
|
1499
|
-
const lastInstructionWithLocation = trace.bytecode.getInstruction(
|
|
1500
|
-
lastLocationStep.pc
|
|
1501
|
-
);
|
|
1502
|
-
return lastInstructionWithLocation;
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
return undefined;
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
private _callInstructionToCallFailedToExecuteStackTraceEntry(
|
|
1509
|
-
bytecode: Bytecode,
|
|
1510
|
-
callInst: Instruction
|
|
1511
|
-
): CallFailedErrorStackTraceEntry {
|
|
1512
|
-
const sourceReference = sourceLocationToSourceReference(
|
|
1513
|
-
bytecode,
|
|
1514
|
-
callInst.location
|
|
1515
|
-
);
|
|
1516
|
-
assertHardhatInvariant(
|
|
1517
|
-
sourceReference !== undefined,
|
|
1518
|
-
"Expected source reference to be defined"
|
|
1519
|
-
);
|
|
1520
|
-
|
|
1521
|
-
// Calls only happen within functions
|
|
1522
|
-
return {
|
|
1523
|
-
type: StackTraceEntryType.CALL_FAILED_ERROR,
|
|
1524
|
-
sourceReference,
|
|
1525
|
-
};
|
|
1526
|
-
}
|
|
1527
|
-
|
|
1528
|
-
private _getEntryBeforeFailureInModifier(
|
|
1529
|
-
trace: DecodedEvmMessageTrace,
|
|
1530
|
-
functionJumpdests: Instruction[]
|
|
1531
|
-
): CallstackEntryStackTraceEntry | InternalFunctionCallStackEntry {
|
|
1532
|
-
// If there's a jumpdest, this modifier belongs to the last function that it represents
|
|
1533
|
-
if (functionJumpdests.length > 0) {
|
|
1534
|
-
return instructionToCallstackStackTraceEntry(
|
|
1535
|
-
trace.bytecode,
|
|
1536
|
-
functionJumpdests[functionJumpdests.length - 1]
|
|
1537
|
-
);
|
|
1538
|
-
}
|
|
1539
|
-
|
|
1540
|
-
// This function is only called after we jumped into the initial function in call traces, so
|
|
1541
|
-
// there should always be at least a function jumpdest.
|
|
1542
|
-
if (!isDecodedCreateTrace(trace)) {
|
|
1543
|
-
throw new Error(
|
|
1544
|
-
"This shouldn't happen: a call trace has no functionJumpdest but has already jumped into a function"
|
|
1545
|
-
);
|
|
1546
|
-
}
|
|
1547
|
-
|
|
1548
|
-
// If there's no jump dest, we point to the constructor.
|
|
1549
|
-
return {
|
|
1550
|
-
type: StackTraceEntryType.CALLSTACK_ENTRY,
|
|
1551
|
-
sourceReference: this._getConstructorStartSourceReference(trace),
|
|
1552
|
-
functionType: ContractFunctionType.CONSTRUCTOR,
|
|
1553
|
-
};
|
|
1554
|
-
}
|
|
1555
|
-
|
|
1556
|
-
private _failsRightAfterCall(
|
|
1557
|
-
trace: DecodedEvmMessageTrace,
|
|
1558
|
-
callSubtraceStepIndex: number
|
|
1559
|
-
): boolean {
|
|
1560
|
-
const lastStep = trace.steps[trace.steps.length - 1];
|
|
1561
|
-
if (!isEvmStep(lastStep)) {
|
|
1562
|
-
return false;
|
|
1563
|
-
}
|
|
1564
|
-
|
|
1565
|
-
const lastInst = trace.bytecode.getInstruction(lastStep.pc);
|
|
1566
|
-
if (lastInst.opcode !== Opcode.REVERT) {
|
|
1567
|
-
return false;
|
|
1568
|
-
}
|
|
1569
|
-
|
|
1570
|
-
const callOpcodeStep = trace.steps[callSubtraceStepIndex - 1] as EvmStep;
|
|
1571
|
-
const callInst = trace.bytecode.getInstruction(callOpcodeStep.pc);
|
|
1572
|
-
|
|
1573
|
-
// Calls are always made from within functions
|
|
1574
|
-
assertHardhatInvariant(
|
|
1575
|
-
callInst.location !== undefined,
|
|
1576
|
-
"Expected call instruction location to be defined"
|
|
1577
|
-
);
|
|
1578
|
-
|
|
1579
|
-
return this._isLastLocation(
|
|
1580
|
-
trace,
|
|
1581
|
-
callSubtraceStepIndex + 1,
|
|
1582
|
-
callInst.location
|
|
1583
|
-
);
|
|
1584
|
-
}
|
|
1585
|
-
|
|
1586
|
-
private _isCallFailedError(
|
|
1587
|
-
trace: DecodedEvmMessageTrace,
|
|
1588
|
-
instIndex: number,
|
|
1589
|
-
callInstruction: Instruction
|
|
1590
|
-
): boolean {
|
|
1591
|
-
const callLocation = callInstruction.location;
|
|
1592
|
-
|
|
1593
|
-
// Calls are always made from within functions
|
|
1594
|
-
assertHardhatInvariant(
|
|
1595
|
-
callLocation !== undefined,
|
|
1596
|
-
"Expected call location to be defined"
|
|
1597
|
-
);
|
|
1598
|
-
|
|
1599
|
-
return this._isLastLocation(trace, instIndex, callLocation);
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
private _isLastLocation(
|
|
1603
|
-
trace: DecodedEvmMessageTrace,
|
|
1604
|
-
fromStep: number,
|
|
1605
|
-
location: SourceLocation
|
|
1606
|
-
): boolean {
|
|
1607
|
-
for (let i = fromStep; i < trace.steps.length; i++) {
|
|
1608
|
-
const step = trace.steps[i];
|
|
1609
|
-
|
|
1610
|
-
if (!isEvmStep(step)) {
|
|
1611
|
-
return false;
|
|
1612
|
-
}
|
|
1613
|
-
|
|
1614
|
-
const stepInst = trace.bytecode.getInstruction(step.pc);
|
|
1615
|
-
|
|
1616
|
-
if (stepInst.location === undefined) {
|
|
1617
|
-
continue;
|
|
1618
|
-
}
|
|
1619
|
-
|
|
1620
|
-
if (!location.equals(stepInst.location)) {
|
|
1621
|
-
return false;
|
|
1622
|
-
}
|
|
1623
|
-
}
|
|
1624
|
-
|
|
1625
|
-
return true;
|
|
1626
|
-
}
|
|
1627
|
-
|
|
1628
|
-
private _isSubtraceErrorPropagated(
|
|
1629
|
-
trace: DecodedEvmMessageTrace,
|
|
1630
|
-
callSubtraceStepIndex: number
|
|
1631
|
-
): boolean {
|
|
1632
|
-
const call = trace.steps[callSubtraceStepIndex] as MessageTrace;
|
|
1633
|
-
|
|
1634
|
-
if (!equalsBytes(trace.returnData, call.returnData)) {
|
|
1635
|
-
return false;
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
if (
|
|
1639
|
-
trace.exit.kind === ExitCode.OUT_OF_GAS &&
|
|
1640
|
-
call.exit.kind === ExitCode.OUT_OF_GAS
|
|
1641
|
-
) {
|
|
1642
|
-
return true;
|
|
1643
|
-
}
|
|
1644
|
-
|
|
1645
|
-
// If the return data is not empty, and it's still the same, we assume it
|
|
1646
|
-
// is being propagated
|
|
1647
|
-
if (trace.returnData.length > 0) {
|
|
1648
|
-
return true;
|
|
1649
|
-
}
|
|
1650
|
-
|
|
1651
|
-
return this._failsRightAfterCall(trace, callSubtraceStepIndex);
|
|
1652
|
-
}
|
|
1653
|
-
|
|
1654
|
-
private _isProxyErrorPropagated(
|
|
1655
|
-
trace: DecodedEvmMessageTrace,
|
|
1656
|
-
callSubtraceStepIndex: number
|
|
1657
|
-
): boolean {
|
|
1658
|
-
if (!isDecodedCallTrace(trace)) {
|
|
1659
|
-
return false;
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
const callStep = trace.steps[callSubtraceStepIndex - 1];
|
|
1663
|
-
if (!isEvmStep(callStep)) {
|
|
1664
|
-
return false;
|
|
1665
|
-
}
|
|
1666
|
-
|
|
1667
|
-
const callInst = trace.bytecode.getInstruction(callStep.pc);
|
|
1668
|
-
if (callInst.opcode !== Opcode.DELEGATECALL) {
|
|
1669
|
-
return false;
|
|
1670
|
-
}
|
|
1671
|
-
|
|
1672
|
-
const subtrace = trace.steps[callSubtraceStepIndex];
|
|
1673
|
-
if (isEvmStep(subtrace)) {
|
|
1674
|
-
return false;
|
|
1675
|
-
}
|
|
1676
|
-
|
|
1677
|
-
if (isPrecompileTrace(subtrace)) {
|
|
1678
|
-
return false;
|
|
1679
|
-
}
|
|
1680
|
-
|
|
1681
|
-
// If we can't recognize the implementation we'd better don't consider it as such
|
|
1682
|
-
if (subtrace.bytecode === undefined) {
|
|
1683
|
-
return false;
|
|
1684
|
-
}
|
|
1685
|
-
|
|
1686
|
-
if (subtrace.bytecode.contract.type === ContractType.LIBRARY) {
|
|
1687
|
-
return false;
|
|
1688
|
-
}
|
|
1689
|
-
|
|
1690
|
-
if (!equalsBytes(trace.returnData, subtrace.returnData)) {
|
|
1691
|
-
return false;
|
|
1692
|
-
}
|
|
1693
|
-
|
|
1694
|
-
for (let i = callSubtraceStepIndex + 1; i < trace.steps.length; i++) {
|
|
1695
|
-
const step = trace.steps[i];
|
|
1696
|
-
if (!isEvmStep(step)) {
|
|
1697
|
-
return false;
|
|
1698
|
-
}
|
|
1699
|
-
|
|
1700
|
-
const inst = trace.bytecode.getInstruction(step.pc);
|
|
1701
|
-
|
|
1702
|
-
// All the remaining locations should be valid, as they are part of the inline asm
|
|
1703
|
-
if (inst.location === undefined) {
|
|
1704
|
-
return false;
|
|
1705
|
-
}
|
|
1706
|
-
|
|
1707
|
-
if (
|
|
1708
|
-
inst.jumpType === JumpType.INTO_FUNCTION ||
|
|
1709
|
-
inst.jumpType === JumpType.OUTOF_FUNCTION
|
|
1710
|
-
) {
|
|
1711
|
-
return false;
|
|
1712
|
-
}
|
|
1713
|
-
}
|
|
1714
|
-
|
|
1715
|
-
const lastStep = trace.steps[trace.steps.length - 1] as EvmStep;
|
|
1716
|
-
const lastInst = trace.bytecode.getInstruction(lastStep.pc);
|
|
1717
|
-
|
|
1718
|
-
return lastInst.opcode === Opcode.REVERT;
|
|
1719
|
-
}
|
|
1720
|
-
|
|
1721
|
-
private _isContractCallRunOutOfGasError(
|
|
1722
|
-
trace: DecodedEvmMessageTrace,
|
|
1723
|
-
callStepIndex: number
|
|
1724
|
-
): boolean {
|
|
1725
|
-
if (trace.returnData.length > 0) {
|
|
1726
|
-
return false;
|
|
1727
|
-
}
|
|
1728
|
-
|
|
1729
|
-
if (trace.exit.kind !== ExitCode.REVERT) {
|
|
1730
|
-
return false;
|
|
1731
|
-
}
|
|
1732
|
-
|
|
1733
|
-
const call = trace.steps[callStepIndex] as MessageTrace;
|
|
1734
|
-
if (call.exit.kind !== ExitCode.OUT_OF_GAS) {
|
|
1735
|
-
return false;
|
|
1736
|
-
}
|
|
1737
|
-
|
|
1738
|
-
return this._failsRightAfterCall(trace, callStepIndex);
|
|
1739
|
-
}
|
|
1740
|
-
|
|
1741
|
-
private _isPanicReturnData(returnData: Uint8Array): boolean {
|
|
1742
|
-
return new ReturnData(returnData).isPanicReturnData();
|
|
1743
|
-
}
|
|
1744
|
-
}
|
|
1745
|
-
|
|
1746
|
-
export function instructionToCallstackStackTraceEntry(
|
|
1747
|
-
bytecode: Bytecode,
|
|
1748
|
-
inst: Instruction
|
|
1749
|
-
): CallstackEntryStackTraceEntry | InternalFunctionCallStackEntry {
|
|
1750
|
-
// This means that a jump is made from within an internal solc function.
|
|
1751
|
-
// These are normally made from yul code, so they don't map to any Solidity
|
|
1752
|
-
// function
|
|
1753
|
-
if (inst.location === undefined) {
|
|
1754
|
-
const location = bytecode.contract.location;
|
|
1755
|
-
return {
|
|
1756
|
-
type: StackTraceEntryType.INTERNAL_FUNCTION_CALLSTACK_ENTRY,
|
|
1757
|
-
pc: inst.pc,
|
|
1758
|
-
sourceReference: {
|
|
1759
|
-
sourceName: bytecode.contract.location.file.sourceName,
|
|
1760
|
-
sourceContent: bytecode.contract.location.file.content,
|
|
1761
|
-
contract: bytecode.contract.name,
|
|
1762
|
-
function: undefined,
|
|
1763
|
-
line: bytecode.contract.location.getStartingLineNumber(),
|
|
1764
|
-
range: [location.offset, location.offset + location.length],
|
|
1765
|
-
},
|
|
1766
|
-
};
|
|
1767
|
-
}
|
|
1768
|
-
|
|
1769
|
-
const func = inst.location?.getContainingFunction();
|
|
1770
|
-
|
|
1771
|
-
if (func !== undefined) {
|
|
1772
|
-
const sourceReference = sourceLocationToSourceReference(
|
|
1773
|
-
bytecode,
|
|
1774
|
-
inst.location
|
|
1775
|
-
);
|
|
1776
|
-
assertHardhatInvariant(
|
|
1777
|
-
sourceReference !== undefined,
|
|
1778
|
-
"Expected source reference to be defined"
|
|
1779
|
-
);
|
|
1780
|
-
|
|
1781
|
-
return {
|
|
1782
|
-
type: StackTraceEntryType.CALLSTACK_ENTRY,
|
|
1783
|
-
sourceReference,
|
|
1784
|
-
functionType: func.type,
|
|
1785
|
-
};
|
|
1786
|
-
}
|
|
1787
|
-
|
|
1788
|
-
assertHardhatInvariant(
|
|
1789
|
-
inst.location !== undefined,
|
|
1790
|
-
"Expected instruction location to be defined"
|
|
1791
|
-
);
|
|
1792
|
-
|
|
1793
|
-
return {
|
|
1794
|
-
type: StackTraceEntryType.CALLSTACK_ENTRY,
|
|
1795
|
-
sourceReference: {
|
|
1796
|
-
function: undefined,
|
|
1797
|
-
contract: bytecode.contract.name,
|
|
1798
|
-
sourceName: inst.location.file.sourceName,
|
|
1799
|
-
sourceContent: inst.location.file.content,
|
|
1800
|
-
line: inst.location.getStartingLineNumber(),
|
|
1801
|
-
range: [
|
|
1802
|
-
inst.location.offset,
|
|
1803
|
-
inst.location.offset + inst.location.length,
|
|
1804
|
-
],
|
|
1805
|
-
},
|
|
1806
|
-
functionType: ContractFunctionType.FUNCTION,
|
|
1807
|
-
};
|
|
1808
|
-
}
|
|
1809
|
-
|
|
1810
|
-
function sourceLocationToSourceReference(
|
|
1811
|
-
bytecode: Bytecode,
|
|
1812
|
-
location?: SourceLocation
|
|
1813
|
-
): SourceReference | undefined {
|
|
1814
|
-
if (location === undefined) {
|
|
1815
|
-
return undefined;
|
|
1816
|
-
}
|
|
1817
|
-
|
|
1818
|
-
const func = location.getContainingFunction();
|
|
1819
|
-
|
|
1820
|
-
if (func === undefined) {
|
|
1821
|
-
return undefined;
|
|
1822
|
-
}
|
|
1823
|
-
|
|
1824
|
-
let funcName = func.name;
|
|
1825
|
-
|
|
1826
|
-
if (func.type === ContractFunctionType.CONSTRUCTOR) {
|
|
1827
|
-
funcName = CONSTRUCTOR_FUNCTION_NAME;
|
|
1828
|
-
} else if (func.type === ContractFunctionType.FALLBACK) {
|
|
1829
|
-
funcName = FALLBACK_FUNCTION_NAME;
|
|
1830
|
-
} else if (func.type === ContractFunctionType.RECEIVE) {
|
|
1831
|
-
funcName = RECEIVE_FUNCTION_NAME;
|
|
1832
|
-
}
|
|
1833
|
-
|
|
1834
|
-
return {
|
|
1835
|
-
function: funcName,
|
|
1836
|
-
contract:
|
|
1837
|
-
func.type === ContractFunctionType.FREE_FUNCTION
|
|
1838
|
-
? undefined
|
|
1839
|
-
: bytecode.contract.name,
|
|
1840
|
-
sourceName: func.location.file.sourceName,
|
|
1841
|
-
sourceContent: func.location.file.content,
|
|
1842
|
-
line: location.getStartingLineNumber(),
|
|
1843
|
-
range: [location.offset, location.offset + location.length],
|
|
1844
|
-
};
|
|
1845
|
-
}
|