use leo_errors::Formatted;
use leo_span::Span;
use std::fmt::Display;
const CODE_PREFIX: &str = "CEI";
const CODE_MASK: i32 = 13000;
pub(crate) fn check_after_interaction(operation: impl Display, span: Span) -> Formatted {
Formatted::warning(
CODE_PREFIX,
CODE_MASK,
format!("{operation} runs after an interaction (`Final.run()`)"),
span,
)
.with_note("Under the Checks-Effects-Interactions pattern, all checks (reads, asserts) must precede any `.run()` calls in the same execution path.")
.with_help("Move this check above the `.run()` call to avoid reentrancy issues.")
}
pub(crate) fn effect_after_interaction(operation: impl Display, span: Span) -> Formatted {
Formatted::warning(
CODE_PREFIX,
CODE_MASK + 1,
format!("{operation} runs after an interaction (`Final.run()`)"),
span,
)
.with_note("Under the Checks-Effects-Interactions pattern, all effects (state writes) must precede any `.run()` calls in the same execution path.")
.with_help("Move this effect above the `.run()` call to avoid reentrancy issues.")
}
pub(crate) fn callee_has_effects_after_interaction(callee: impl Display, span: Span) -> Formatted {
Formatted::warning(
CODE_PREFIX,
CODE_MASK + 2,
format!("the call to `{callee}` runs after an interaction (`Final.run()`), and `{callee}` itself performs checks or effects"),
span,
)
.with_note("Under the Checks-Effects-Interactions pattern, any callee that performs checks or effects must run before any `.run()` calls in the same execution path.")
.with_help(format!("Move the call to `{callee}` above the `.run()` call to avoid reentrancy issues."))
}
pub(crate) fn cei_violation_in_loop(span: Span) -> Formatted {
Formatted::warning(
CODE_PREFIX,
CODE_MASK + 3,
"loop body contains both interactions (`Final.run()`) and state operations (checks or effects), violating the Checks-Effects-Interactions pattern",
span,
)
.with_help("Restructure the loop so a single iteration does not mix interactions with checks or effects. Split it into two passes if needed.")
}
pub(crate) fn tainted_value_in_finalize(variable: impl Display, external_call: impl Display, span: Span) -> Formatted {
Formatted::warning(
CODE_PREFIX,
CODE_MASK + 4,
format!("value `{variable}` used in the finalize block was derived from external call `{external_call}`, whose finalize may alter the state this value depends on"),
span,
)
.with_help(format!("The external program's finalize runs concurrently and may invalidate assumptions about `{variable}`. Re-read the value on-chain inside the finalize block."))
}
pub(crate) fn tainted_argument_to_external_call(
variable: impl Display,
callee: impl Display,
external_call: impl Display,
span: Span,
) -> Formatted {
Formatted::warning(
CODE_PREFIX,
CODE_MASK + 5,
format!("tainted value `{variable}` (derived from external call `{external_call}`) is passed as an argument to `{callee}`, whose finalize will use the potentially stale value"),
span,
)
.with_help(format!("The external program's finalize runs concurrently and may invalidate `{variable}`. Pass the value on-chain inside the finalize block instead."))
}