1-
21use crate :: mint_precompile:: NATIVE_MINT_PRECOMPILE_ADDRESS ;
32use alloy_primitives:: { Address , U256 } ;
3+ use bytes:: Bytes ;
44use revm:: db:: Database ;
5- use revm:: precompile:: Precompile ;
6- use revm:: primitives:: { ExecutionResult , Output , TransactTo } ;
7- use revm:: { Evm , Inspector } ;
5+ use revm:: primitives:: {
6+ AccountInfo , CallInputs , CallOutcome , ExecutionResult , Output , TransactTo , B160 ,
7+ } ;
8+ use revm:: { DatabaseCommit , Evm , Inspector , JournaledState } ;
89use std:: collections:: HashSet ;
910
1011/// An inspector that gates calls to the native mint precompile.
1112///
1213/// This inspector enforces an allowlist and various limits on the minting of the native token.
1314/// It also performs the state mutation (crediting the balance) when the precompile call is
1415/// successful.
16+ #[ derive( Clone , Debug ) ]
1517pub struct MintInspector {
1618 /// The address of the native mint precompile.
1719 precompile : Address ,
1820 /// A static list of addresses that are allowed to call the precompile.
1921 allow : HashSet < Address > ,
20- /// An optional on-chain registry for validating callers.
21- registry : Option < Address > ,
2222 /// The maximum amount that can be minted in a single call.
2323 per_call_cap : U256 ,
2424 /// The maximum amount that can be minted in a single block.
@@ -28,21 +28,68 @@ pub struct MintInspector {
2828}
2929
3030impl < DB : Database > Inspector < DB > for MintInspector {
31- /// Called before the execution of a transaction.
32- fn transact_inspect (
31+ fn call (
3332 & mut self ,
3433 context : & mut revm:: InnerEvmContext < DB > ,
35- transact_to : TransactTo ,
36- caller : Address ,
37- value : U256 ,
38- ) -> Option < Vec < u8 > > {
39- // Reset the per-block mint counter at the beginning of each transaction.
40- self . minted_this_block = U256 :: ZERO ;
34+ inputs : & mut CallInputs ,
35+ ) -> Option < CallOutcome > {
36+ // Intercept calls to the native mint precompile.
37+ if inputs. contract != self . precompile {
38+ return None ;
39+ }
40+
41+ // Check if the caller is authorized.
42+ if !self . allow . contains ( & inputs. caller ) {
43+ // Return a revert outcome if the caller is not authorized.
44+ let outcome = CallOutcome :: new ( ) . with_revert ( Bytes :: from_static ( b"unauthorized" ) ) ;
45+ return Some ( outcome) ;
46+ }
47+
48+ // Decode the amount from the input.
49+ let amount = U256 :: from_be_slice ( & inputs. input [ 20 ..52 ] ) ;
50+
51+ // Check if the amount exceeds the per-call cap.
52+ if amount > self . per_call_cap {
53+ let outcome = CallOutcome :: new ( ) . with_revert ( Bytes :: from_static ( b"over per-call cap" ) ) ;
54+ return Some ( outcome) ;
55+ }
56+
57+ // Check if the amount exceeds the per-block cap.
58+ if let Some ( per_block_cap) = self . per_block_cap {
59+ if self . minted_this_block + amount > per_block_cap {
60+ let outcome =
61+ CallOutcome :: new ( ) . with_revert ( Bytes :: from_static ( b"over per-block cap" ) ) ;
62+ return Some ( outcome) ;
63+ }
64+ }
65+
4166 None
4267 }
4368
44- /// Called after the execution of a transaction.
45- fn transact_end ( & mut self , context : & mut revm:: InnerEvmContext < DB > , result : ExecutionResult ) {
46- // No-op
69+ fn call_end (
70+ & mut self ,
71+ context : & mut revm:: InnerEvmContext < DB > ,
72+ inputs : & CallInputs ,
73+ outcome : CallOutcome ,
74+ ) -> CallOutcome {
75+ // Only handle successful calls to the native mint precompile.
76+ if inputs. contract != self . precompile || outcome. is_revert ( ) {
77+ return outcome;
78+ }
79+
80+ // Decode the recipient and amount from the input.
81+ let to = Address :: from_slice ( & inputs. input [ 0 ..20 ] ) ;
82+ let amount = U256 :: from_be_slice ( & inputs. input [ 20 ..52 ] ) ;
83+
84+ // Credit the recipient's balance.
85+ // This is the core state mutation logic.
86+ let ( account, _) = context. journaled_state . load_account ( to, context. db ) . unwrap ( ) ;
87+ account. info . balance += amount;
88+ self . minted_this_block += amount;
89+
90+ // Mark the account as touched so the state change is persisted.
91+ context. journaled_state . touch ( & to) ;
92+
93+ outcome
4794 }
48- }
95+ }
0 commit comments