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}