solidhunter_lib/rules/best_practises/
payable_fallback.rs1use osmium_libs_solidity_ast_extractor::retriever::{
2 retrieve_contract_nodes, retrieve_functions_nodes,
3};
4use osmium_libs_solidity_ast_extractor::{ItemFunction, Mutability, Spanned};
5
6use crate::linter::SolidFile;
7use crate::rules::types::*;
8use crate::types::*;
9
10pub const RULE_ID: &str = "payable-fallback";
12
13const DEFAULT_SEVERITY: Severity = Severity::WARNING;
15const DEFAULT_MESSAGE: &str = "When fallback is not payable you will not be able to receive ether";
16
17pub struct PayableFallback {
18 data: RuleEntry,
19}
20
21impl RuleType for PayableFallback {
22 fn diagnose(&self, file: &SolidFile, _files: &[SolidFile]) -> Vec<LintDiag> {
23 let mut res = Vec::new();
24 let reports = check_fallback_payable(file);
25
26 for report in reports.into_iter().flatten() {
27 res.push(LintDiag {
28 id: RULE_ID.to_string(),
29 severity: self.data.severity,
30 range: report,
31 code: None,
32 source: None,
33 message: DEFAULT_MESSAGE.to_string(),
34 uri: file.path.clone(),
35 });
36 }
37 res
38 }
39}
40
41fn check_fallback_payable(file: &SolidFile) -> Vec<Option<Range>> {
42 let mut res: Vec<Option<Range>> = Vec::new();
43
44 let contracts = retrieve_contract_nodes(&file.data);
45 for contract in contracts {
46 let functions = retrieve_functions_nodes(&contract);
47
48 for function in functions {
49 if function.kind.is_fallback()
50 || (function.kind.is_function() && function.name.is_none())
51 {
52 res = check_attribute(res, function);
53 }
54 }
55 }
56 res
57}
58
59fn check_attribute(mut res: Vec<Option<Range>>, function: ItemFunction) -> Vec<Option<Range>> {
60 let mut is_payable = false;
61 for attributes in function.attributes.iter() {
62 if attributes.mutability().is_some()
63 && Mutability::is_payable(attributes.mutability().unwrap())
64 {
65 is_payable = true;
66 }
67 }
68 if !is_payable {
69 res.push(create_report(function));
70 }
71 res
72}
73
74fn create_report(function: ItemFunction) -> Option<Range> {
75 Some(Range {
76 start: Position {
77 line: function.attributes.span().start().line,
78 character: function.attributes.span().start().column + 1,
79 },
80 end: Position {
81 line: function.attributes.span().end().line,
82 character: function.attributes.span().end().column,
83 },
84 })
85}
86
87impl PayableFallback {
88 pub fn create(data: RuleEntry) -> Box<dyn RuleType> {
89 let rule = PayableFallback { data };
90 Box::new(rule)
91 }
92
93 pub fn create_default() -> RuleEntry {
94 RuleEntry {
95 id: RULE_ID.to_string(),
96 severity: DEFAULT_SEVERITY,
97 data: None,
98 }
99 }
100}