-
Notifications
You must be signed in to change notification settings - Fork 179
/
Copy pathgas-custom-errors.js
125 lines (115 loc) · 3.61 KB
/
gas-custom-errors.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
const semver = require('semver')
const BaseChecker = require('../base-checker')
const { severityDescription } = require('../../doc/utils')
const DEFAULT_SEVERITY = 'warn'
const BASE_VERSION = '>=0.8.4'
const ruleId = 'gas-custom-errors'
const meta = {
type: 'gas-consumption',
docs: {
description:
'Enforces the use of Custom Errors over Require with strings error and Revert statements',
category: 'Gas Consumption Rules',
options: [
{
description: severityDescription,
default: DEFAULT_SEVERITY,
},
],
notes: [
{
note: 'This rules applies to Solidity version 0.8.4 and higher',
},
],
examples: {
good: [
{
description: 'Use of Custom Errors',
code: 'revert CustomErrorFunction();',
},
{
description: 'Use of Custom Errors with arguments',
code: 'revert CustomErrorFunction({ msg: "Insufficient Balance" });',
},
{
description: 'Use of Require with Custom Error with arguments',
code: 'require(success, CustomErrorFunction({ msg: "Insufficient Balance" });',
},
{
description: 'Use of Require with function call and Custom Error',
code: 'require(isAuthorized(account), CustomErrorFunction();',
},
{
description: 'Use of Require with binary comparison and Custom Error',
code: 'require(a > b, CustomErrorFunction();',
},
],
bad: [
{
description: 'Use of require statement',
code: 'require(userBalance >= availableAmount, "Insufficient Balance");',
},
{
description: 'Use of plain revert statement',
code: 'revert();',
},
{
description: 'Use of revert statement with message',
code: 'revert("Insufficient Balance");',
},
],
},
},
isDefault: false,
recommended: true,
defaultSetup: DEFAULT_SEVERITY,
schema: null,
}
class GasCustomErrorsChecker extends BaseChecker {
constructor(reporter) {
super(reporter, ruleId, meta)
this.solidityVersion = 0
}
isVersionGreater() {
return semver.intersects(this.solidityVersion, BASE_VERSION)
}
PragmaDirective(node) {
if (node.type === 'PragmaDirective' && node.name === 'solidity') {
this.solidityVersion = node.value
}
}
FunctionCall(node) {
let errorStr = ''
if (this.isVersionGreater(node)) {
if (node.expression.name === 'require') {
// If no second argument or second argument is a string, flag it
if (node.arguments.length < 2) {
// No second argument
errorStr = 'require'
} else {
const secondArg = node.arguments[1]
if (secondArg.type === 'StringLiteral') {
// e.g. require(cond, "Error message");
errorStr = 'require'
} else if (secondArg.type !== 'FunctionCall') {
// e.g. require(cond, 42) or require(cond, someVar)
// Probably not a custom error, so still flag
errorStr = 'require'
}
// else if secondArg.type === 'FunctionCall':
// e.g. require(cond, MyCustomError())
// We skip, because it’s presumably a custom error
}
} else if (
node.expression.name === 'revert' &&
(node.arguments.length === 0 || node.arguments[0].type === 'StringLiteral')
) {
errorStr = 'revert'
}
if (errorStr !== '') {
this.error(node, `GC: Use Custom Errors instead of ${errorStr} statements`)
}
}
}
}
module.exports = GasCustomErrorsChecker