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