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
package/src/internal/hardhat-network/stack-traces/mapped-inlined-internal-functions-heuristics.ts
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file includes Solidity tracing heuristics for solc starting with version
|
|
3
|
-
* 0.6.9.
|
|
4
|
-
*
|
|
5
|
-
* This solc version introduced a significant change to how sourcemaps are
|
|
6
|
-
* handled for inline yul/internal functions. These were mapped to the
|
|
7
|
-
* unmapped/-1 file before, which lead to many unmapped reverts. Now, they are
|
|
8
|
-
* mapped to the part of the Solidity source that lead to their inlining.
|
|
9
|
-
*
|
|
10
|
-
* This change is a very positive change, as errors would point to the correct
|
|
11
|
-
* line by default. The only problem is that we used to rely very heavily on
|
|
12
|
-
* unmapped reverts to decide when our error detection heuristics were to be
|
|
13
|
-
* run. In fact, this heuristics were first introduced because of unmapped
|
|
14
|
-
* reverts.
|
|
15
|
-
*
|
|
16
|
-
* Instead of synthetically completing stack traces when unmapped reverts occur,
|
|
17
|
-
* we now start from complete stack traces and adjust them if we can provide
|
|
18
|
-
* more meaningful errors.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import semver from "semver";
|
|
22
|
-
|
|
23
|
-
import {
|
|
24
|
-
DecodedEvmMessageTrace,
|
|
25
|
-
isDecodedCallTrace,
|
|
26
|
-
isDecodedCreateTrace,
|
|
27
|
-
isEvmStep,
|
|
28
|
-
} from "./message-trace";
|
|
29
|
-
import { Opcode } from "./opcodes";
|
|
30
|
-
import {
|
|
31
|
-
SolidityStackTrace,
|
|
32
|
-
StackTraceEntryType,
|
|
33
|
-
} from "./solidity-stack-trace";
|
|
34
|
-
|
|
35
|
-
const FIRST_SOLC_VERSION_WITH_MAPPED_SMALL_INTERNAL_FUNCTIONS = "0.6.9";
|
|
36
|
-
|
|
37
|
-
export function stackTraceMayRequireAdjustments(
|
|
38
|
-
stackTrace: SolidityStackTrace,
|
|
39
|
-
decodedTrace: DecodedEvmMessageTrace
|
|
40
|
-
): boolean {
|
|
41
|
-
if (stackTrace.length === 0) {
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const lastFrame = stackTrace[stackTrace.length - 1];
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
lastFrame.type === StackTraceEntryType.REVERT_ERROR &&
|
|
49
|
-
!lastFrame.isInvalidOpcodeError &&
|
|
50
|
-
lastFrame.message.isEmpty() &&
|
|
51
|
-
semver.gte(
|
|
52
|
-
decodedTrace.bytecode.compilerVersion,
|
|
53
|
-
FIRST_SOLC_VERSION_WITH_MAPPED_SMALL_INTERNAL_FUNCTIONS
|
|
54
|
-
)
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export function adjustStackTrace(
|
|
59
|
-
stackTrace: SolidityStackTrace,
|
|
60
|
-
decodedTrace: DecodedEvmMessageTrace
|
|
61
|
-
): SolidityStackTrace {
|
|
62
|
-
const start = stackTrace.slice(0, -1);
|
|
63
|
-
const [revert] = stackTrace.slice(-1);
|
|
64
|
-
|
|
65
|
-
if (isNonContractAccountCalledError(decodedTrace)) {
|
|
66
|
-
return [
|
|
67
|
-
...start,
|
|
68
|
-
{
|
|
69
|
-
type: StackTraceEntryType.NONCONTRACT_ACCOUNT_CALLED_ERROR,
|
|
70
|
-
sourceReference: revert.sourceReference!,
|
|
71
|
-
},
|
|
72
|
-
];
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (isConstructorInvalidParamsError(decodedTrace)) {
|
|
76
|
-
return [
|
|
77
|
-
...start,
|
|
78
|
-
{
|
|
79
|
-
type: StackTraceEntryType.INVALID_PARAMS_ERROR,
|
|
80
|
-
sourceReference: revert.sourceReference!,
|
|
81
|
-
},
|
|
82
|
-
];
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (isCallInvalidParamsError(decodedTrace)) {
|
|
86
|
-
return [
|
|
87
|
-
...start,
|
|
88
|
-
{
|
|
89
|
-
type: StackTraceEntryType.INVALID_PARAMS_ERROR,
|
|
90
|
-
sourceReference: revert.sourceReference!,
|
|
91
|
-
},
|
|
92
|
-
];
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return stackTrace;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function isNonContractAccountCalledError(
|
|
99
|
-
decodedTrace: DecodedEvmMessageTrace
|
|
100
|
-
): boolean {
|
|
101
|
-
return matchOpcodes(decodedTrace, -9, [
|
|
102
|
-
Opcode.EXTCODESIZE,
|
|
103
|
-
Opcode.ISZERO,
|
|
104
|
-
Opcode.DUP1,
|
|
105
|
-
Opcode.ISZERO,
|
|
106
|
-
]);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function isConstructorInvalidParamsError(decodedTrace: DecodedEvmMessageTrace) {
|
|
110
|
-
if (!isDecodedCreateTrace(decodedTrace)) {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return (
|
|
115
|
-
matchOpcodes(decodedTrace, -20, [Opcode.CODESIZE]) &&
|
|
116
|
-
matchOpcodes(decodedTrace, -15, [Opcode.CODECOPY]) &&
|
|
117
|
-
matchOpcodes(decodedTrace, -7, [Opcode.LT, Opcode.ISZERO])
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function isCallInvalidParamsError(decodedTrace: DecodedEvmMessageTrace) {
|
|
122
|
-
if (!isDecodedCallTrace(decodedTrace)) {
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return (
|
|
127
|
-
matchOpcodes(decodedTrace, -11, [Opcode.CALLDATASIZE]) &&
|
|
128
|
-
matchOpcodes(decodedTrace, -7, [Opcode.LT, Opcode.ISZERO])
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function matchOpcode(
|
|
133
|
-
decodedTrace: DecodedEvmMessageTrace,
|
|
134
|
-
stepIndex: number,
|
|
135
|
-
opcode: Opcode
|
|
136
|
-
): boolean {
|
|
137
|
-
const [step] = decodedTrace.steps.slice(stepIndex, stepIndex + 1);
|
|
138
|
-
|
|
139
|
-
if (step === undefined || !isEvmStep(step)) {
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const instruction = decodedTrace.bytecode.getInstruction(step.pc);
|
|
144
|
-
|
|
145
|
-
return instruction.opcode === opcode;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function matchOpcodes(
|
|
149
|
-
decodedTrace: DecodedEvmMessageTrace,
|
|
150
|
-
firstStepIndex: number,
|
|
151
|
-
opcodes: Opcode[]
|
|
152
|
-
): boolean {
|
|
153
|
-
let index = firstStepIndex;
|
|
154
|
-
for (const opcode of opcodes) {
|
|
155
|
-
if (!matchOpcode(decodedTrace, index, opcode)) {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
index += 1;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
return true;
|
|
163
|
-
}
|
|
@@ -1,409 +0,0 @@
|
|
|
1
|
-
import { bytesToHex as bufferToHex } from "@nomicfoundation/ethereumjs-util";
|
|
2
|
-
|
|
3
|
-
import { AbiHelpers } from "../../util/abi-helpers";
|
|
4
|
-
|
|
5
|
-
import { Opcode } from "./opcodes";
|
|
6
|
-
|
|
7
|
-
/* eslint-disable @nomicfoundation/hardhat-internal-rules/only-hardhat-error */
|
|
8
|
-
|
|
9
|
-
export enum JumpType {
|
|
10
|
-
NOT_JUMP,
|
|
11
|
-
INTO_FUNCTION,
|
|
12
|
-
OUTOF_FUNCTION,
|
|
13
|
-
INTERNAL_JUMP,
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export enum ContractType {
|
|
17
|
-
CONTRACT,
|
|
18
|
-
LIBRARY,
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export enum ContractFunctionType {
|
|
22
|
-
CONSTRUCTOR,
|
|
23
|
-
FUNCTION,
|
|
24
|
-
FALLBACK,
|
|
25
|
-
RECEIVE,
|
|
26
|
-
GETTER,
|
|
27
|
-
MODIFIER,
|
|
28
|
-
FREE_FUNCTION,
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export enum ContractFunctionVisibility {
|
|
32
|
-
PRIVATE,
|
|
33
|
-
INTERNAL,
|
|
34
|
-
PUBLIC,
|
|
35
|
-
EXTERNAL,
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export class SourceFile {
|
|
39
|
-
public readonly contracts: Contract[] = [];
|
|
40
|
-
public readonly functions: ContractFunction[] = [];
|
|
41
|
-
|
|
42
|
-
constructor(
|
|
43
|
-
public readonly sourceName: string,
|
|
44
|
-
public readonly content: string
|
|
45
|
-
) {}
|
|
46
|
-
|
|
47
|
-
public addContract(contract: Contract) {
|
|
48
|
-
if (contract.location.file !== this) {
|
|
49
|
-
throw new Error("Trying to add a contract from another file");
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
this.contracts.push(contract);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
public addFunction(func: ContractFunction) {
|
|
56
|
-
if (func.location.file !== this) {
|
|
57
|
-
throw new Error("Trying to add a function from another file");
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
this.functions.push(func);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
public getContainingFunction(
|
|
64
|
-
location: SourceLocation
|
|
65
|
-
): ContractFunction | undefined {
|
|
66
|
-
// TODO: Optimize this with a binary search or an internal tree
|
|
67
|
-
|
|
68
|
-
for (const func of this.functions) {
|
|
69
|
-
if (func.location.contains(location)) {
|
|
70
|
-
return func;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return undefined;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export class SourceLocation {
|
|
79
|
-
private _line: number | undefined;
|
|
80
|
-
|
|
81
|
-
constructor(
|
|
82
|
-
public readonly file: SourceFile,
|
|
83
|
-
public readonly offset: number,
|
|
84
|
-
public readonly length: number
|
|
85
|
-
) {}
|
|
86
|
-
|
|
87
|
-
public getStartingLineNumber(): number {
|
|
88
|
-
if (this._line === undefined) {
|
|
89
|
-
this._line = 1;
|
|
90
|
-
|
|
91
|
-
for (const c of this.file.content.slice(0, this.offset)) {
|
|
92
|
-
if (c === "\n") {
|
|
93
|
-
this._line += 1;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return this._line;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
public getContainingFunction(): ContractFunction | undefined {
|
|
102
|
-
return this.file.getContainingFunction(this);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
public contains(other: SourceLocation) {
|
|
106
|
-
if (this.file !== other.file) {
|
|
107
|
-
return false;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (other.offset < this.offset) {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return other.offset + other.length <= this.offset + this.length;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
public equals(other: SourceLocation) {
|
|
118
|
-
return (
|
|
119
|
-
this.file === other.file &&
|
|
120
|
-
this.offset === other.offset &&
|
|
121
|
-
this.length === other.length
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export class Contract {
|
|
127
|
-
public readonly localFunctions: ContractFunction[] = [];
|
|
128
|
-
public readonly customErrors: CustomError[] = [];
|
|
129
|
-
|
|
130
|
-
private _constructor: ContractFunction | undefined;
|
|
131
|
-
private _fallback: ContractFunction | undefined;
|
|
132
|
-
private _receive: ContractFunction | undefined;
|
|
133
|
-
private readonly _selectorHexToFunction: Map<string, ContractFunction> =
|
|
134
|
-
new Map();
|
|
135
|
-
|
|
136
|
-
constructor(
|
|
137
|
-
public readonly name: string,
|
|
138
|
-
public readonly type: ContractType,
|
|
139
|
-
public readonly location: SourceLocation
|
|
140
|
-
) {}
|
|
141
|
-
|
|
142
|
-
public get constructorFunction(): ContractFunction | undefined {
|
|
143
|
-
return this._constructor;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
public get fallback(): ContractFunction | undefined {
|
|
147
|
-
return this._fallback;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
public get receive(): ContractFunction | undefined {
|
|
151
|
-
return this._receive;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
public addLocalFunction(func: ContractFunction) {
|
|
155
|
-
if (func.contract !== this) {
|
|
156
|
-
throw new Error("Function isn't local");
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (
|
|
160
|
-
func.visibility === ContractFunctionVisibility.PUBLIC ||
|
|
161
|
-
func.visibility === ContractFunctionVisibility.EXTERNAL
|
|
162
|
-
) {
|
|
163
|
-
if (
|
|
164
|
-
func.type === ContractFunctionType.FUNCTION ||
|
|
165
|
-
func.type === ContractFunctionType.GETTER
|
|
166
|
-
) {
|
|
167
|
-
this._selectorHexToFunction.set(bufferToHex(func.selector!), func);
|
|
168
|
-
} else if (func.type === ContractFunctionType.CONSTRUCTOR) {
|
|
169
|
-
this._constructor = func;
|
|
170
|
-
} else if (func.type === ContractFunctionType.FALLBACK) {
|
|
171
|
-
this._fallback = func;
|
|
172
|
-
} else if (func.type === ContractFunctionType.RECEIVE) {
|
|
173
|
-
this._receive = func;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
this.localFunctions.push(func);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
public addCustomError(customError: CustomError) {
|
|
181
|
-
this.customErrors.push(customError);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
public addNextLinearizedBaseContract(baseContract: Contract) {
|
|
185
|
-
if (this._fallback === undefined && baseContract._fallback !== undefined) {
|
|
186
|
-
this._fallback = baseContract._fallback;
|
|
187
|
-
}
|
|
188
|
-
if (this._receive === undefined && baseContract._receive !== undefined) {
|
|
189
|
-
this._receive = baseContract._receive;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
for (const baseContractFunction of baseContract.localFunctions) {
|
|
193
|
-
if (
|
|
194
|
-
baseContractFunction.type !== ContractFunctionType.GETTER &&
|
|
195
|
-
baseContractFunction.type !== ContractFunctionType.FUNCTION
|
|
196
|
-
) {
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (
|
|
201
|
-
baseContractFunction.visibility !== ContractFunctionVisibility.PUBLIC &&
|
|
202
|
-
baseContractFunction.visibility !== ContractFunctionVisibility.EXTERNAL
|
|
203
|
-
) {
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const selectorHex = bufferToHex(baseContractFunction.selector!);
|
|
208
|
-
if (!this._selectorHexToFunction.has(selectorHex)) {
|
|
209
|
-
this._selectorHexToFunction.set(selectorHex, baseContractFunction);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
public getFunctionFromSelector(
|
|
215
|
-
selector: Uint8Array
|
|
216
|
-
): ContractFunction | undefined {
|
|
217
|
-
return this._selectorHexToFunction.get(bufferToHex(selector));
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* We compute selectors manually, which is particularly hard. We do this
|
|
222
|
-
* because we need to map selectors to AST nodes, and it seems easier to start
|
|
223
|
-
* from the AST node. This is surprisingly super hard: things like inherited
|
|
224
|
-
* enums, structs and ABIv2 complicate it.
|
|
225
|
-
*
|
|
226
|
-
* As we know that that can fail, we run a heuristic that tries to correct
|
|
227
|
-
* incorrect selectors. What it does is checking the `evm.methodIdentifiers`
|
|
228
|
-
* compiler output, and detect missing selectors. Then we take those and
|
|
229
|
-
* find contract functions with the same name. If there are multiple of those
|
|
230
|
-
* we can't do anything. If there is a single one, it must have an incorrect
|
|
231
|
-
* selector, so we update it with the `evm.methodIdentifiers`'s value.
|
|
232
|
-
*/
|
|
233
|
-
public correctSelector(functionName: string, selector: Buffer): boolean {
|
|
234
|
-
const functions = Array.from(this._selectorHexToFunction.values()).filter(
|
|
235
|
-
(cf) => cf.name === functionName
|
|
236
|
-
);
|
|
237
|
-
|
|
238
|
-
if (functions.length !== 1) {
|
|
239
|
-
return false;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const functionToCorrect = functions[0];
|
|
243
|
-
|
|
244
|
-
if (functionToCorrect.selector !== undefined) {
|
|
245
|
-
this._selectorHexToFunction.delete(
|
|
246
|
-
bufferToHex(functionToCorrect.selector)
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
functionToCorrect.selector = selector;
|
|
251
|
-
this._selectorHexToFunction.set(bufferToHex(selector), functionToCorrect);
|
|
252
|
-
return true;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
export class ContractFunction {
|
|
257
|
-
constructor(
|
|
258
|
-
public readonly name: string,
|
|
259
|
-
public readonly type: ContractFunctionType,
|
|
260
|
-
public readonly location: SourceLocation,
|
|
261
|
-
public readonly contract?: Contract,
|
|
262
|
-
public readonly visibility?: ContractFunctionVisibility,
|
|
263
|
-
public readonly isPayable?: boolean,
|
|
264
|
-
public selector?: Uint8Array,
|
|
265
|
-
public readonly paramTypes?: any[]
|
|
266
|
-
) {
|
|
267
|
-
if (contract !== undefined && !contract.location.contains(location)) {
|
|
268
|
-
throw new Error("Incompatible contract and function location");
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
public isValidCalldata(calldata: Uint8Array): boolean {
|
|
273
|
-
if (this.paramTypes === undefined) {
|
|
274
|
-
// if we don't know the param types, we just assume that the call is valid
|
|
275
|
-
return true;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return AbiHelpers.isValidCalldata(this.paramTypes, calldata);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
export class CustomError {
|
|
283
|
-
/**
|
|
284
|
-
* Return a CustomError from the given ABI information: the name
|
|
285
|
-
* of the error and its inputs. Returns undefined if it can't build
|
|
286
|
-
* the CustomError.
|
|
287
|
-
*/
|
|
288
|
-
public static fromABI(name: string, inputs: any[]): CustomError | undefined {
|
|
289
|
-
const selector = AbiHelpers.computeSelector(name, inputs);
|
|
290
|
-
|
|
291
|
-
if (selector !== undefined) {
|
|
292
|
-
return new CustomError(selector, name, inputs);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
private constructor(
|
|
297
|
-
public readonly selector: Uint8Array,
|
|
298
|
-
public readonly name: string,
|
|
299
|
-
public readonly paramTypes: any[]
|
|
300
|
-
) {}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
export class Instruction {
|
|
304
|
-
constructor(
|
|
305
|
-
public readonly pc: number,
|
|
306
|
-
public readonly opcode: Opcode,
|
|
307
|
-
public readonly jumpType: JumpType,
|
|
308
|
-
public readonly pushData?: Buffer,
|
|
309
|
-
public readonly location?: SourceLocation
|
|
310
|
-
) {}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Checks equality with another Instruction.
|
|
314
|
-
*/
|
|
315
|
-
public equals(other: Instruction): boolean {
|
|
316
|
-
if (this.pc !== other.pc) {
|
|
317
|
-
return false;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if (this.opcode !== other.opcode) {
|
|
321
|
-
return false;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (this.jumpType !== other.jumpType) {
|
|
325
|
-
return false;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (this.pushData !== undefined) {
|
|
329
|
-
if (other.pushData === undefined) {
|
|
330
|
-
return false;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
if (!this.pushData.equals(other.pushData)) {
|
|
334
|
-
return false;
|
|
335
|
-
}
|
|
336
|
-
} else if (other.pushData !== undefined) {
|
|
337
|
-
return false;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
if (this.location !== undefined) {
|
|
341
|
-
if (other.location === undefined) {
|
|
342
|
-
return false;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
if (!this.location.equals(other.location)) {
|
|
346
|
-
return false;
|
|
347
|
-
}
|
|
348
|
-
} else if (other.location !== undefined) {
|
|
349
|
-
return false;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
return true;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
interface ImmutableReference {
|
|
357
|
-
start: number;
|
|
358
|
-
length: number;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
export class Bytecode {
|
|
362
|
-
private readonly _pcToInstruction: Map<number, Instruction> = new Map();
|
|
363
|
-
|
|
364
|
-
constructor(
|
|
365
|
-
public readonly contract: Contract,
|
|
366
|
-
public readonly isDeployment: boolean,
|
|
367
|
-
public readonly normalizedCode: Buffer,
|
|
368
|
-
public readonly instructions: Instruction[],
|
|
369
|
-
public readonly libraryAddressPositions: number[],
|
|
370
|
-
public readonly immutableReferences: ImmutableReference[],
|
|
371
|
-
public readonly compilerVersion: string
|
|
372
|
-
) {
|
|
373
|
-
for (const inst of instructions) {
|
|
374
|
-
this._pcToInstruction.set(inst.pc, inst);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
public getInstruction(pc: number): Instruction {
|
|
379
|
-
const inst = this._pcToInstruction.get(pc);
|
|
380
|
-
|
|
381
|
-
if (inst === undefined) {
|
|
382
|
-
throw new Error(`There's no instruction at pc ${pc}`);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
return inst;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
public hasInstruction(pc: number): boolean {
|
|
389
|
-
return this._pcToInstruction.has(pc);
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* Checks equality with another Bytecode.
|
|
394
|
-
*/
|
|
395
|
-
public equals(other: Bytecode): boolean {
|
|
396
|
-
if (this._pcToInstruction.size !== other._pcToInstruction.size) {
|
|
397
|
-
return false;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
for (const [key, val] of this._pcToInstruction) {
|
|
401
|
-
const otherVal = other._pcToInstruction.get(key);
|
|
402
|
-
if (otherVal === undefined || !val.equals(otherVal)) {
|
|
403
|
-
return false;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
return true;
|
|
408
|
-
}
|
|
409
|
-
}
|