foundry_cheatcodes_spec/cheatcode.rs
1use super::Function;
2use alloy_sol_types::SolCall;
3use serde::{Deserialize, Serialize};
4
5/// Cheatcode definition trait. Implemented by all [`Vm`](crate::Vm) functions.
6pub trait CheatcodeDef: std::fmt::Debug + Clone + SolCall {
7 /// The static cheatcode definition.
8 const CHEATCODE: &'static Cheatcode<'static>;
9}
10
11/// Specification of a single cheatcode. Extends [`Function`] with additional metadata.
12#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
13#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
14#[serde(deny_unknown_fields, rename_all = "camelCase")]
15#[non_exhaustive]
16pub struct Cheatcode<'a> {
17 // Automatically-generated fields.
18 /// The Solidity function declaration.
19 #[serde(borrow)]
20 pub func: Function<'a>,
21
22 // Manually-specified fields.
23 /// The group that the cheatcode belongs to.
24 pub group: Group,
25 /// The current status of the cheatcode. E.g. whether it is stable or deprecated, etc.
26 pub status: Status<'a>,
27 /// Whether the cheatcode is safe to use inside of scripts. E.g. it does not change state in an
28 /// unexpected way.
29 pub safety: Safety,
30}
31
32/// The status of a cheatcode.
33#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
34#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
35#[serde(rename_all = "camelCase")]
36#[non_exhaustive]
37pub enum Status<'a> {
38 /// The cheatcode and its API is currently stable.
39 Stable,
40 /// The cheatcode has been deprecated, meaning it will be removed in a future release.
41 ///
42 /// Contains the optional reason for deprecation.
43 ///
44 /// `forge test` warns once per test suite that uses a deprecated cheatcode.
45 Deprecated(Option<&'a str>),
46 /// The cheatcode is only used internally for foundry testing and may be changed or removed at
47 /// any time.
48 ///
49 /// Internal cheatcodes are not included in forge-std's `Vm` interface. Foundry does not check
50 /// their use at runtime.
51 Internal,
52}
53
54/// Cheatcode groups.
55/// Initially derived and modified from inline comments in [`forge-std`'s `Vm.sol`][vmsol].
56///
57/// [vmsol]: https://github.com/foundry-rs/forge-std/blob/dcb0d52bc4399d37a6545848e3b8f9d03c77b98d/src/Vm.sol
58#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
59#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
60#[serde(rename_all = "camelCase")]
61#[non_exhaustive]
62pub enum Group {
63 /// Cheatcodes that read from, or write to the current EVM execution state.
64 ///
65 /// Examples: any of the `record` cheatcodes, `chainId`, `coinbase`.
66 ///
67 /// Safety: ambiguous, depends on whether the cheatcode is read-only or not.
68 Evm,
69 /// Cheatcodes that interact with how a test is run.
70 ///
71 /// Examples: `assume`, `skip`, `expectRevert`.
72 ///
73 /// Safety: ambiguous, depends on whether the cheatcode is read-only or not.
74 Testing,
75 /// Cheatcodes that interact with how a script is run.
76 ///
77 /// Examples: `broadcast`, `startBroadcast`, `stopBroadcast`.
78 ///
79 /// Safety: safe.
80 Scripting,
81 /// Cheatcodes that interact with the OS or filesystem.
82 ///
83 /// Examples: `ffi`, `projectRoot`, `writeFile`.
84 ///
85 /// Safety: safe.
86 Filesystem,
87 /// Cheatcodes that interact with the program's environment variables.
88 ///
89 /// Examples: `setEnv`, `envBool`, `envOr`.
90 ///
91 /// Safety: safe.
92 Environment,
93 /// Utility cheatcodes that deal with string parsing and manipulation.
94 ///
95 /// Examples: `toString`. `parseBytes`.
96 ///
97 /// Safety: safe.
98 String,
99 /// Utility cheatcodes that deal with parsing values from and converting values to JSON.
100 ///
101 /// Examples: `serializeJson`, `parseJsonUint`, `writeJson`.
102 ///
103 /// Safety: safe.
104 Json,
105 /// Utility cheatcodes that deal with parsing values from and converting values to TOML.
106 ///
107 /// Examples: `parseToml`, `writeToml`.
108 ///
109 /// Safety: safe.
110 Toml,
111 /// Cryptography-related cheatcodes.
112 ///
113 /// Examples: `sign*`.
114 ///
115 /// Safety: safe.
116 Crypto,
117 /// Generic, uncategorized utilities.
118 ///
119 /// Examples: `toString`, `parse*`, `serialize*`.
120 ///
121 /// Safety: safe.
122 Utilities,
123}
124
125impl Group {
126 /// Returns the safety of this cheatcode group.
127 ///
128 /// Some groups are inherently safe or unsafe, while others are ambiguous and will return
129 /// `None`.
130 pub const fn safety(self) -> Option<Safety> {
131 match self {
132 Self::Evm | Self::Testing => None,
133 Self::Scripting
134 | Self::Filesystem
135 | Self::Environment
136 | Self::String
137 | Self::Json
138 | Self::Toml
139 | Self::Crypto
140 | Self::Utilities => Some(Safety::Safe),
141 }
142 }
143
144 /// Returns this value as a string.
145 pub const fn as_str(self) -> &'static str {
146 match self {
147 Self::Evm => "evm",
148 Self::Testing => "testing",
149 Self::Scripting => "scripting",
150 Self::Filesystem => "filesystem",
151 Self::Environment => "environment",
152 Self::String => "string",
153 Self::Json => "json",
154 Self::Toml => "toml",
155 Self::Crypto => "crypto",
156 Self::Utilities => "utilities",
157 }
158 }
159}
160
161// TODO: Find a better name for this
162/// Cheatcode safety.
163#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
164#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
165#[serde(rename_all = "camelCase")]
166#[non_exhaustive]
167pub enum Safety {
168 /// The cheatcode is not safe to use in scripts.
169 Unsafe,
170 /// The cheatcode is safe to use in scripts.
171 #[default]
172 Safe,
173}
174
175impl Safety {
176 /// Returns this value as a string.
177 pub const fn as_str(self) -> &'static str {
178 match self {
179 Self::Safe => "safe",
180 Self::Unsafe => "unsafe",
181 }
182 }
183
184 /// Returns whether this value is safe.
185 pub const fn is_safe(self) -> bool {
186 matches!(self, Self::Safe)
187 }
188}