signet_evm/sys/
mod.rs

1mod driver;
2
3mod logs;
4pub use logs::{
5    MintNative as MintNativeSysLog, MintToken as MintTokenSysLog, Transact as TransactSysLog,
6};
7
8mod native;
9pub use native::MintNative;
10
11mod token;
12pub use token::MintToken;
13
14mod transact;
15pub use transact::TransactSysTx;
16
17use alloy::{
18    consensus::ReceiptEnvelope,
19    primitives::{Address, Bytes, Log, TxKind, U256},
20};
21use core::fmt;
22use signet_types::primitives::TransactionSigned;
23use trevm::{
24    helpers::Ctx,
25    revm::{context::result::EVMError, Database, DatabaseCommit, Inspector},
26    Trevm, Tx,
27};
28
29/// [`SysBase`] is the root trait for all system actions and transactions. It
30/// provides the basic functionality that the [`SignetDriver`] needs to process
31/// system actions and transactions.
32///
33/// The [`fmt::Display`] impl is used for tracing, and should be a short
34///
35pub trait SysBase: fmt::Debug + Clone {
36    /// Get the name of the system action or transaction. This is used for
37    /// tracing, and should be short, descriptive, and unique for each
38    /// system action or transaction type.
39    fn name() -> &'static str;
40
41    /// Get a short description of the system action or transaction. This
42    /// should be a concise, human-readable string that describes the
43    /// system action or transaction.
44    ///
45    /// E.g.
46    /// - "Mint 100 USD to 0xabcd..."
47    /// - "Transact 0.5 ETH from 0xabcd... to 0xef01... with input data
48    ///   0x1234..."
49    fn description(&self) -> String;
50
51    /// Check if the system action has a nonce. This is typically used to
52    /// determine if the nonce should be populated by the Evm during
53    /// transaction processing.
54    fn has_nonce(&self) -> bool;
55
56    /// Populate the nonce for the transaction. This is typically used to
57    /// ensure that the transaction is unique. It will be called by the Evm
58    /// during transaction processing to set the nonce for the transaction.
59    fn populate_nonce(&mut self, nonce: u64);
60
61    /// Set the nonce for the transaction. This is a convenience method that
62    /// calls [`Self::populate_nonce`] with the given nonce.
63    fn with_nonce(mut self, nonce: u64) -> Self
64    where
65        Self: Sized,
66    {
67        self.populate_nonce(nonce);
68        self
69    }
70
71    /// Convert the system action into a transaction that can be appended to a
72    /// block by the [`SignetDriver`].
73    fn produce_transaction(&self) -> TransactionSigned;
74
75    /// Produce a log for the system action. This will be appended to the end
76    /// of the receipt, and
77    fn produce_log(&self) -> Log;
78
79    /// Get the address that the Signet EVM considers to be the sender of the
80    /// system action. This is typically the [`MINTER_ADDRESS`] for token or
81    /// native asset mints, and the host-chain user address for transact events.
82    ///
83    /// [`MINTER_ADDRESS`]: signet_types::constants::MINTER_ADDRESS
84    fn evm_sender(&self) -> Address;
85}
86
87/// System actions are operations that apply changes to the EVM state without
88/// going through the transaction processing pipeline. They are not run as
89/// transactions, and do not have gas limits or revert semantics. They are
90/// typically used for operations that need to be applied directly to the state,
91/// such as modifying balances.
92pub trait SysAction: SysBase {
93    /// Apply the system action to the EVM state.
94    fn apply<Db, Insp, State>(
95        &self,
96        evm: &mut Trevm<Db, Insp, State>,
97    ) -> Result<(), EVMError<Db::Error>>
98    where
99        Db: Database + DatabaseCommit,
100        Insp: Inspector<Ctx<Db>>;
101
102    /// Produce a receipt for the system action. This receipt will be
103    /// accumulated in the block object during EVM execution.
104    fn produce_receipt(&self, cumulative_gas_used: u64) -> ReceiptEnvelope;
105}
106
107/// System transactions run on the EVM as a transaction, but do not pay gas and
108/// cannot produce Orders. They are run as transactions, but are not subject to
109/// the same rules and constraints as regular transactions. They CAN revert,
110/// and CAN halt. They are typically used for operations that need to be run as
111/// transactions, but should not pay gas. E.g. minting tokens or performing
112/// system-level operations that do not require gas payment.
113pub trait UnmeteredSysTx: SysBase + SysTx {}
114
115/// A transaction that is run on the EVM, and may or may not pay gas.
116///
117/// See [`MeteredSysTx`] and [`UnmeteredSysTx`] for more specific
118/// transaction types.
119pub trait SysTx: SysBase + Tx {
120    /// Get the callee address for the transaction.
121    fn callee(&self) -> TxKind;
122
123    /// Get the input data for the transaction. This is the calldata that is
124    /// passed to the callee when the transaction is executed.
125    fn input(&self) -> Bytes;
126
127    /// Get the value of the transaction. This is the amount of native
128    /// asset that is being transferred to the callee when the transaction is
129    /// executed.
130    fn value(&self) -> U256;
131}
132/// System transactions run on the EVM as a transaction, and are subject to the
133/// same rules and constraints as regular transactions. They may run arbitrary
134/// execution, have gas limits, and can revert if they fail. They must satisfy
135/// the system market constraints on Orders.
136///
137/// They are distinct from [`UnmeteredSysTx`], which are run as transactions,
138/// but do not pay gas and cannot produce Orders.
139///
140/// They are distinct from [`SysAction`], which are not run as transactions,
141/// but rather apply changes to the state directly without going through the
142/// transaction processing pipeline.
143pub trait MeteredSysTx: SysBase + SysTx {
144    /// Get the gas limit for the transaction. This is the maximum amount of
145    /// gas that the transaction is allowed to consume.
146    ///
147    /// Metered system transactions ALWAYS consume all gas.
148    fn gas_limit(&self) -> u128;
149
150    /// Get the max fee per gas for the transaction. This is the maximum
151    /// amount of gas that the transaction is willing to pay for each unit of
152    /// gas consumed.
153    ///
154    /// Metered system transactions ALWAYS consume all gas and NEVER pay a tip.
155    fn max_fee_per_gas(&self) -> u128;
156
157    /// Get the precise total fee for the transaction. This is the product of
158    /// [`MeteredSysTx::gas_limit`] and [`MeteredSysTx::max_fee_per_gas`]. This
159    /// is distinct from the actual fee paid, which may be less than this. The
160    /// actual fee paid is the product of [`MeteredSysTx::gas_limit`] and the
161    /// current block's basefee.
162    ///
163    /// Metered system transactions ALWAYS consume all gas and NEVER pay a tip,
164    /// so the maximum fee they will pay is known up front.
165    fn max_fee(&self) -> U256 {
166        U256::from(self.gas_limit()) * U256::from(self.max_fee_per_gas())
167    }
168}