Skip to main content

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}