mirror of https://github.com/crytic/slither
commit
9fe27d375f
@ -1,84 +0,0 @@ |
||||
#!/usr/bin/env bash |
||||
|
||||
### Test Detectors |
||||
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)" |
||||
|
||||
CURRENT_PATH=$(pwd) |
||||
TRAVIS_PATH='/home/travis/build/crytic/slither' |
||||
|
||||
# test_slither file.sol detectors |
||||
test_slither(){ |
||||
|
||||
expected="$DIR/../tests/expected_json/$(basename "$1" .sol).$2.json" |
||||
|
||||
# run slither detector on input file and save output as json |
||||
if ! slither "$1" --solc-disable-warnings --detect "$2" --json "$DIR/tmp-test.json"; |
||||
then |
||||
echo "Slither crashed" |
||||
exit 255 |
||||
fi |
||||
|
||||
if [ ! -f "$DIR/tmp-test.json" ]; then |
||||
echo "" |
||||
echo "Missing generated file" |
||||
echo "" |
||||
exit 1 |
||||
fi |
||||
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$DIR/tmp-test.json" -i |
||||
result=$(python "$DIR/json_diff.py" "$expected" "$DIR/tmp-test.json") |
||||
|
||||
rm "$DIR/tmp-test.json" |
||||
if [ "$result" != "{}" ]; then |
||||
echo "" |
||||
echo "failed test of file: $1, detector: $2" |
||||
echo "" |
||||
echo "$result" |
||||
echo "" |
||||
exit 1 |
||||
fi |
||||
|
||||
# run slither detector on input file and save output as json |
||||
if ! slither "$1" --solc-disable-warnings --detect "$2" --legacy-ast --json "$DIR/tmp-test.json"; |
||||
then |
||||
echo "Slither crashed" |
||||
exit 255 |
||||
fi |
||||
|
||||
if [ ! -f "$DIR/tmp-test.json" ]; then |
||||
echo "" |
||||
echo "Missing generated file" |
||||
echo "" |
||||
exit 1 |
||||
fi |
||||
|
||||
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$DIR/tmp-test.json" -i |
||||
result=$(python "$DIR/json_diff.py" "$expected" "$DIR/tmp-test.json") |
||||
|
||||
rm "$DIR/tmp-test.json" |
||||
if [ "$result" != "{}" ]; then |
||||
echo "" |
||||
echo "failed test of file: $1, detector: $2" |
||||
echo "" |
||||
echo "$result" |
||||
echo "" |
||||
exit 1 |
||||
fi |
||||
} |
||||
|
||||
# generate_expected_json file.sol detectors |
||||
generate_expected_json(){ |
||||
# generate output filename |
||||
# e.g. file: uninitialized.sol detector: uninitialized-state |
||||
# ---> uninitialized.uninitialized-state.json |
||||
output_filename="$DIR/../tests/expected_json/$(basename "$1" .sol).$2.json" |
||||
output_filename_txt="$DIR/../tests/expected_json/$(basename "$1" .sol).$2.txt" |
||||
|
||||
# run slither detector on input file and save output as json |
||||
slither "$1" --solc-disable-warnings --detect "$2" --json "$output_filename" > "$output_filename_txt" 2>&1 |
||||
|
||||
|
||||
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$output_filename" -i |
||||
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$output_filename_txt" -i |
||||
} |
||||
|
@ -1,27 +0,0 @@ |
||||
import sys |
||||
import json |
||||
from pprint import pprint |
||||
from deepdiff import DeepDiff # pip install deepdiff |
||||
|
||||
|
||||
if len(sys.argv) != 3: |
||||
print("Usage: python json_diff.py 1.json 2.json") |
||||
sys.exit(-1) |
||||
|
||||
with open(sys.argv[1], encoding="utf8") as f: |
||||
d1 = json.load(f) |
||||
|
||||
with open(sys.argv[2], encoding="utf8") as f: |
||||
d2 = json.load(f) |
||||
|
||||
|
||||
# Remove description field to allow non deterministic print |
||||
for elem in d1: |
||||
if "description" in elem: |
||||
del elem["description"] |
||||
for elem in d2: |
||||
if "description" in elem: |
||||
del elem["description"] |
||||
|
||||
|
||||
pprint(DeepDiff(d1, d2, ignore_order=True, verbose_level=2)) |
@ -1,106 +0,0 @@ |
||||
""" |
||||
Check for state variables too similar |
||||
Do not check contract inheritance |
||||
""" |
||||
import difflib |
||||
from typing import List, Set, Tuple |
||||
|
||||
from slither.core.declarations.contract import Contract |
||||
from slither.core.variables.local_variable import LocalVariable |
||||
from slither.detectors.abstract_detector import ( |
||||
AbstractDetector, |
||||
DetectorClassification, |
||||
DETECTOR_INFO, |
||||
) |
||||
from slither.utils.output import Output |
||||
|
||||
|
||||
class SimilarVarsDetection(AbstractDetector): |
||||
""" |
||||
Variable similar detector |
||||
""" |
||||
|
||||
ARGUMENT = "similar-names" |
||||
HELP = "Variable names are too similar" |
||||
IMPACT = DetectorClassification.INFORMATIONAL |
||||
CONFIDENCE = DetectorClassification.MEDIUM |
||||
|
||||
WIKI = ( |
||||
"https://github.com/crytic/slither/wiki/Detector-Documentation#variable-names-too-similar" |
||||
) |
||||
|
||||
WIKI_TITLE = "Variable names too similar" |
||||
WIKI_DESCRIPTION = "Detect variables with names that are too similar." |
||||
WIKI_EXPLOIT_SCENARIO = "Bob uses several variables with similar names. As a result, his code is difficult to review." |
||||
WIKI_RECOMMENDATION = "Prevent variables from having similar names." |
||||
|
||||
@staticmethod |
||||
def similar(seq1: str, seq2: str) -> bool: |
||||
"""Test the name similarity |
||||
|
||||
Two name are similar if difflib.SequenceMatcher on the lowercase |
||||
version of the name is greater than 0.90 |
||||
See: https://docs.python.org/2/library/difflib.html |
||||
Args: |
||||
seq1 (str): first name |
||||
seq2 (str): second name |
||||
Returns: |
||||
bool: true if names are similar |
||||
""" |
||||
val = difflib.SequenceMatcher(a=seq1, b=seq2).ratio() |
||||
ret = val > 0.90 |
||||
return ret |
||||
|
||||
@staticmethod |
||||
def detect_sim(contract: Contract) -> Set[Tuple[LocalVariable, LocalVariable]]: |
||||
"""Detect variables with similar name |
||||
|
||||
Returns: |
||||
bool: true if variables have similar name |
||||
""" |
||||
all_var = [x.variables for x in contract.functions] |
||||
all_var = [x for l in all_var for x in l] |
||||
|
||||
contract_var = contract.variables |
||||
|
||||
all_var = list(set(all_var + contract_var)) |
||||
|
||||
ret = set() |
||||
# pylint: disable=consider-using-enumerate |
||||
for i in range(len(all_var)): |
||||
v1 = all_var[i] |
||||
_v1_name_lower = v1.name.lower() |
||||
for j in range(i, len(all_var)): |
||||
v2 = all_var[j] |
||||
if len(v1.name) != len(v2.name): |
||||
continue |
||||
_v2_name_lower = v2.name.lower() |
||||
if _v1_name_lower != _v2_name_lower: |
||||
if SimilarVarsDetection.similar(_v1_name_lower, _v2_name_lower): |
||||
ret.add((v1, v2)) |
||||
|
||||
return ret |
||||
|
||||
def _detect(self) -> List[Output]: |
||||
"""Detect similar variables name |
||||
|
||||
Returns: |
||||
list: {'vuln', 'filename,'contract','vars'} |
||||
""" |
||||
results = [] |
||||
for c in self.contracts: |
||||
allVars = self.detect_sim(c) |
||||
if allVars: |
||||
for (v1, v2) in sorted(allVars, key=lambda x: (x[0].name, x[1].name)): |
||||
v_left = v1 if v1.name < v2.name else v2 |
||||
v_right = v2 if v_left == v1 else v1 |
||||
info: DETECTOR_INFO = [ |
||||
"Variable ", |
||||
v_left, |
||||
" is too similar to ", |
||||
v_right, |
||||
"\n", |
||||
] |
||||
json = self.generate_result(info) |
||||
results.append(json) |
||||
return results |
@ -1,5 +1,5 @@ |
||||
# slither-documentation |
||||
|
||||
`slither-documentation` uses [codex](https://beta.openai.com) to generate natspec documenation. |
||||
`slither-documentation` uses [codex](https://platform.openai.com) to generate natspec documenation. |
||||
|
||||
This tool is experimental. See [solmate documentation](https://github.com/montyly/solmate/pull/1) for an example of usage. |
||||
|
@ -1,2 +0,0 @@ |
||||
Variable Similar.f().testVariable (tests/e2e/detectors/test_data/similar-names/0.4.25/similar_variables.sol#3) is too similar to Similar.f().textVariable (tests/e2e/detectors/test_data/similar-names/0.4.25/similar_variables.sol#4) |
||||
|
@ -1,2 +0,0 @@ |
||||
Variable Similar.f().testVariable (tests/e2e/detectors/test_data/similar-names/0.5.16/similar_variables.sol#3) is too similar to Similar.f().textVariable (tests/e2e/detectors/test_data/similar-names/0.5.16/similar_variables.sol#4) |
||||
|
@ -1,2 +0,0 @@ |
||||
Variable Similar.f().testVariable (tests/e2e/detectors/test_data/similar-names/0.6.11/similar_variables.sol#3) is too similar to Similar.f().textVariable (tests/e2e/detectors/test_data/similar-names/0.6.11/similar_variables.sol#4) |
||||
|
@ -1,2 +0,0 @@ |
||||
Variable Similar.f().testVariable (tests/e2e/detectors/test_data/similar-names/0.7.6/similar_variables.sol#3) is too similar to Similar.f().textVariable (tests/e2e/detectors/test_data/similar-names/0.7.6/similar_variables.sol#4) |
||||
|
@ -0,0 +1 @@ |
||||
AnyInitializer (tests/e2e/detectors/test_data/unprotected-upgrade/0.4.25/AnyInitializer.sol#3-15) is an upgradeable contract that does not protect its initialize functions: AnyInitializer.anyName() (tests/e2e/detectors/test_data/unprotected-upgrade/0.4.25/AnyInitializer.sol#6-9). Anyone can delete the contract with: AnyInitializer.kill() (tests/e2e/detectors/test_data/unprotected-upgrade/0.4.25/AnyInitializer.sol#11-14) |
@ -0,0 +1 @@ |
||||
Reinitializer (tests/e2e/detectors/test_data/unprotected-upgrade/0.4.25/Reinitializer.sol#3-15) is an upgradeable contract that does not protect its initialize functions: Reinitializer.initialize() (tests/e2e/detectors/test_data/unprotected-upgrade/0.4.25/Reinitializer.sol#6-9). Anyone can delete the contract with: Reinitializer.kill() (tests/e2e/detectors/test_data/unprotected-upgrade/0.4.25/Reinitializer.sol#11-14) |
@ -0,0 +1 @@ |
||||
AnyInitializer (tests/e2e/detectors/test_data/unprotected-upgrade/0.5.16/AnyInitializer.sol#3-15) is an upgradeable contract that does not protect its initialize functions: AnyInitializer.anyName() (tests/e2e/detectors/test_data/unprotected-upgrade/0.5.16/AnyInitializer.sol#6-9). Anyone can delete the contract with: AnyInitializer.kill() (tests/e2e/detectors/test_data/unprotected-upgrade/0.5.16/AnyInitializer.sol#11-14) |
@ -0,0 +1 @@ |
||||
Reinitializer (tests/e2e/detectors/test_data/unprotected-upgrade/0.5.16/Reinitializer.sol#3-15) is an upgradeable contract that does not protect its initialize functions: Reinitializer.initialize() (tests/e2e/detectors/test_data/unprotected-upgrade/0.5.16/Reinitializer.sol#6-9). Anyone can delete the contract with: Reinitializer.kill() (tests/e2e/detectors/test_data/unprotected-upgrade/0.5.16/Reinitializer.sol#11-14) |
@ -0,0 +1 @@ |
||||
AnyInitializer (tests/e2e/detectors/test_data/unprotected-upgrade/0.6.11/AnyInitializer.sol#3-15) is an upgradeable contract that does not protect its initialize functions: AnyInitializer.anyName() (tests/e2e/detectors/test_data/unprotected-upgrade/0.6.11/AnyInitializer.sol#6-9). Anyone can delete the contract with: AnyInitializer.kill() (tests/e2e/detectors/test_data/unprotected-upgrade/0.6.11/AnyInitializer.sol#11-14) |
@ -0,0 +1 @@ |
||||
Reinitializer (tests/e2e/detectors/test_data/unprotected-upgrade/0.6.11/Reinitializer.sol#3-15) is an upgradeable contract that does not protect its initialize functions: Reinitializer.initialize() (tests/e2e/detectors/test_data/unprotected-upgrade/0.6.11/Reinitializer.sol#6-9). Anyone can delete the contract with: Reinitializer.kill() (tests/e2e/detectors/test_data/unprotected-upgrade/0.6.11/Reinitializer.sol#11-14) |
@ -0,0 +1 @@ |
||||
AnyInitializer (tests/e2e/detectors/test_data/unprotected-upgrade/0.7.6/AnyInitializer.sol#3-15) is an upgradeable contract that does not protect its initialize functions: AnyInitializer.anyName() (tests/e2e/detectors/test_data/unprotected-upgrade/0.7.6/AnyInitializer.sol#6-9). Anyone can delete the contract with: AnyInitializer.kill() (tests/e2e/detectors/test_data/unprotected-upgrade/0.7.6/AnyInitializer.sol#11-14) |
@ -0,0 +1 @@ |
||||
Reinitializer (tests/e2e/detectors/test_data/unprotected-upgrade/0.7.6/Reinitializer.sol#3-15) is an upgradeable contract that does not protect its initialize functions: Reinitializer.initialize() (tests/e2e/detectors/test_data/unprotected-upgrade/0.7.6/Reinitializer.sol#6-9). Anyone can delete the contract with: Reinitializer.kill() (tests/e2e/detectors/test_data/unprotected-upgrade/0.7.6/Reinitializer.sol#11-14) |
@ -0,0 +1 @@ |
||||
AnyInitializer (tests/e2e/detectors/test_data/unprotected-upgrade/0.8.15/AnyInitializer.sol#3-15) is an upgradeable contract that does not protect its initialize functions: AnyInitializer.anyName() (tests/e2e/detectors/test_data/unprotected-upgrade/0.8.15/AnyInitializer.sol#6-9). Anyone can delete the contract with: AnyInitializer.kill() (tests/e2e/detectors/test_data/unprotected-upgrade/0.8.15/AnyInitializer.sol#11-14) |
@ -0,0 +1 @@ |
||||
Reinitializer (tests/e2e/detectors/test_data/unprotected-upgrade/0.8.15/Reinitializer.sol#3-15) is an upgradeable contract that does not protect its initialize functions: Reinitializer.initialize() (tests/e2e/detectors/test_data/unprotected-upgrade/0.8.15/Reinitializer.sol#6-9). Anyone can delete the contract with: Reinitializer.kill() (tests/e2e/detectors/test_data/unprotected-upgrade/0.8.15/Reinitializer.sol#11-14) |
@ -1,7 +0,0 @@ |
||||
contract Similar { |
||||
function f() public returns (uint) { |
||||
uint testVariable = 1; |
||||
uint textVariable = 2; |
||||
return testVariable + textVariable; |
||||
} |
||||
} |
Binary file not shown.
@ -1,7 +0,0 @@ |
||||
contract Similar { |
||||
function f() public returns (uint) { |
||||
uint testVariable = 1; |
||||
uint textVariable = 2; |
||||
return testVariable + textVariable; |
||||
} |
||||
} |
Binary file not shown.
@ -1,7 +0,0 @@ |
||||
contract Similar { |
||||
function f() public returns (uint) { |
||||
uint testVariable = 1; |
||||
uint textVariable = 2; |
||||
return testVariable + textVariable; |
||||
} |
||||
} |
Binary file not shown.
@ -1,7 +0,0 @@ |
||||
contract Similar { |
||||
function f() public returns (uint) { |
||||
uint testVariable = 1; |
||||
uint textVariable = 2; |
||||
return testVariable + textVariable; |
||||
} |
||||
} |
Binary file not shown.
@ -0,0 +1,15 @@ |
||||
import "./Initializable.sol"; |
||||
|
||||
contract AnyInitializer is Initializable { |
||||
address owner; |
||||
|
||||
function anyName() external initializer { |
||||
require(owner == address(0)); |
||||
owner = msg.sender; |
||||
} |
||||
|
||||
function kill() external { |
||||
require(msg.sender == owner); |
||||
selfdestruct(owner); |
||||
} |
||||
} |
Binary file not shown.
@ -1,5 +1,9 @@ |
||||
contract Initializable{ |
||||
contract Initializable { |
||||
modifier initializer() { |
||||
_; |
||||
} |
||||
|
||||
modifier reinitializer(uint64 version) { |
||||
_; |
||||
} |
||||
} |
@ -0,0 +1,15 @@ |
||||
import "./Initializable.sol"; |
||||
|
||||
contract Reinitializer is Initializable { |
||||
address owner; |
||||
|
||||
function initialize() external reinitializer(2) { |
||||
require(owner == address(0)); |
||||
owner = msg.sender; |
||||
} |
||||
|
||||
function kill() external { |
||||
require(msg.sender == owner); |
||||
selfdestruct(owner); |
||||
} |
||||
} |
Binary file not shown.
@ -0,0 +1,15 @@ |
||||
import "./Initializable.sol"; |
||||
|
||||
contract AnyInitializer is Initializable { |
||||
address payable owner; |
||||
|
||||
function anyName() external initializer { |
||||
require(owner == address(0)); |
||||
owner = msg.sender; |
||||
} |
||||
|
||||
function kill() external { |
||||
require(msg.sender == owner); |
||||
selfdestruct(owner); |
||||
} |
||||
} |
Binary file not shown.
@ -1,5 +1,9 @@ |
||||
contract Initializable{ |
||||
contract Initializable { |
||||
modifier initializer() { |
||||
_; |
||||
} |
||||
|
||||
modifier reinitializer(uint64 version) { |
||||
_; |
||||
} |
||||
} |
@ -0,0 +1,15 @@ |
||||
import "./Initializable.sol"; |
||||
|
||||
contract Reinitializer is Initializable { |
||||
address payable owner; |
||||
|
||||
function initialize() external reinitializer(2) { |
||||
require(owner == address(0)); |
||||
owner = msg.sender; |
||||
} |
||||
|
||||
function kill() external { |
||||
require(msg.sender == owner); |
||||
selfdestruct(owner); |
||||
} |
||||
} |
Binary file not shown.
@ -0,0 +1,15 @@ |
||||
import "./Initializable.sol"; |
||||
|
||||
contract AnyInitializer is Initializable { |
||||
address payable owner; |
||||
|
||||
function anyName() external initializer { |
||||
require(owner == address(0)); |
||||
owner = payable(msg.sender); |
||||
} |
||||
|
||||
function kill() external { |
||||
require(msg.sender == owner); |
||||
selfdestruct(owner); |
||||
} |
||||
} |
Binary file not shown.
@ -1,5 +1,9 @@ |
||||
contract Initializable{ |
||||
contract Initializable { |
||||
modifier initializer() { |
||||
_; |
||||
} |
||||
|
||||
modifier reinitializer(uint64 version) { |
||||
_; |
||||
} |
||||
} |
@ -0,0 +1,15 @@ |
||||
import "./Initializable.sol"; |
||||
|
||||
contract Reinitializer is Initializable { |
||||
address payable owner; |
||||
|
||||
function initialize() external reinitializer(2) { |
||||
require(owner == address(0)); |
||||
owner = payable(msg.sender); |
||||
} |
||||
|
||||
function kill() external { |
||||
require(msg.sender == owner); |
||||
selfdestruct(owner); |
||||
} |
||||
} |
Binary file not shown.
@ -0,0 +1,15 @@ |
||||
import "./Initializable.sol"; |
||||
|
||||
contract AnyInitializer is Initializable { |
||||
address payable owner; |
||||
|
||||
function anyName() external initializer { |
||||
require(owner == address(0)); |
||||
owner = payable(msg.sender); |
||||
} |
||||
|
||||
function kill() external { |
||||
require(msg.sender == owner); |
||||
selfdestruct(owner); |
||||
} |
||||
} |
Binary file not shown.
@ -0,0 +1,15 @@ |
||||
import "./Initializable.sol"; |
||||
|
||||
contract Reinitializer is Initializable { |
||||
address payable owner; |
||||
|
||||
function initialize() external reinitializer(2) { |
||||
require(owner == address(0)); |
||||
owner = payable(msg.sender); |
||||
} |
||||
|
||||
function kill() external { |
||||
require(msg.sender == owner); |
||||
selfdestruct(owner); |
||||
} |
||||
} |
Binary file not shown.
@ -0,0 +1,15 @@ |
||||
import "./Initializable.sol"; |
||||
|
||||
contract AnyInitializer is Initializable { |
||||
address payable owner; |
||||
|
||||
function anyName() external initializer { |
||||
require(owner == address(0)); |
||||
owner = payable(msg.sender); |
||||
} |
||||
|
||||
function kill() external { |
||||
require(msg.sender == owner); |
||||
selfdestruct(owner); |
||||
} |
||||
} |
Binary file not shown.
@ -0,0 +1,15 @@ |
||||
import "./Initializable.sol"; |
||||
|
||||
contract Reinitializer is Initializable { |
||||
address payable owner; |
||||
|
||||
function initialize() external reinitializer(2) { |
||||
require(owner == address(0)); |
||||
owner = payable(msg.sender); |
||||
} |
||||
|
||||
function kill() external { |
||||
require(msg.sender == owner); |
||||
selfdestruct(owner); |
||||
} |
||||
} |
Binary file not shown.
@ -1,7 +1,21 @@ |
||||
import "./A.sol"; |
||||
|
||||
contract C is A { |
||||
interface MyInterfaceX { |
||||
function count() external view returns (uint256); |
||||
|
||||
function increment() external; |
||||
} |
||||
|
||||
contract C is A, MyInterfaceX { |
||||
function c_main() public pure { |
||||
a_main(); |
||||
} |
||||
|
||||
function count() external view override returns (uint256){ |
||||
return 1; |
||||
} |
||||
|
||||
function increment() external override { |
||||
|
||||
} |
||||
} |
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,41 @@ |
||||
// SPDX-License-Identifier: MIT |
||||
pragma solidity ^0.8.13; |
||||
|
||||
import { |
||||
ParentContract |
||||
} from "./ParentContract.sol"; |
||||
|
||||
import { |
||||
MainErrors as Errors |
||||
} from "./../errors/MainErrors.sol"; |
||||
|
||||
|
||||
contract MainContract is ParentContract { |
||||
|
||||
|
||||
function functionWithMainError1(uint256 a, uint256 b) external pure returns (uint256) { |
||||
if (a == b) { |
||||
revert Errors.MainError1(); |
||||
} |
||||
// Add some arithmetic operations here |
||||
return a + b; |
||||
} |
||||
|
||||
function functionWithMainError2(uint256 a, uint256 b) external pure returns (uint256) { |
||||
if (a < b) { |
||||
revert Errors.MainError2(); |
||||
} |
||||
// Add some arithmetic operations here |
||||
return a - b; |
||||
} |
||||
|
||||
function functionWithMainError3(uint256 a, uint256 b) external pure returns (uint256) { |
||||
if (b == 0) { |
||||
revert Errors.MainError3(); |
||||
} |
||||
// Add some arithmetic operations here |
||||
return a * b; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,30 @@ |
||||
// SPDX-License-Identifier: MIT |
||||
pragma solidity ^0.8.13; |
||||
|
||||
|
||||
import { |
||||
AccessControlErrors as Errors |
||||
} from "../errors/ParentContractErrors.sol"; |
||||
|
||||
|
||||
contract ParentContract { |
||||
|
||||
|
||||
function functionWithAccessControlErrors1(uint256 a, uint256 b) external pure returns (uint256) { |
||||
if (a == b) { |
||||
revert Errors.AccessControlErrors1(); |
||||
} |
||||
// Add some arithmetic operations here |
||||
return a + b; |
||||
} |
||||
|
||||
function functionWithAccessControlErrors2(uint256 a, uint256 b) external pure returns (uint256) { |
||||
if (a < b) { |
||||
revert Errors.AccessControlErrors2(); |
||||
} |
||||
// Add some arithmetic operations here |
||||
return a - b; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,9 @@ |
||||
// SPDX-License-Identifier: MIT |
||||
pragma solidity ^0.8.13; |
||||
|
||||
// TODO: remove unused errors |
||||
library MainErrors { |
||||
error MainError1(); |
||||
error MainError2(); |
||||
error MainError3(); |
||||
} |
@ -0,0 +1,7 @@ |
||||
// SPDX-License-Identifier: MIT |
||||
pragma solidity ^0.8.13; |
||||
|
||||
library AccessControlErrors { |
||||
error AccessControlErrors1(); |
||||
error AccessControlErrors2(); |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue