1- use crate :: config:: MintConfig ;
1+ use crate :: {
2+ config:: MintConfig ,
3+ mint_precompile:: { parse_operation, Operation } ,
4+ } ;
25use alloy_primitives:: { Address , U256 } ;
36use revm:: {
47 context_interface:: { ContextTr , JournalTr } ,
@@ -13,6 +16,7 @@ pub struct MintInspector {
1316 per_call_cap : U256 ,
1417 per_block_cap : Option < U256 > ,
1518 minted_this_block : U256 ,
19+ burned_this_block : U256 ,
1620}
1721
1822impl MintInspector {
@@ -23,10 +27,12 @@ impl MintInspector {
2327 per_call_cap : config. per_call_cap ,
2428 per_block_cap : config. per_block_cap ,
2529 minted_this_block : U256 :: ZERO ,
30+ burned_this_block : U256 :: ZERO ,
2631 }
2732 }
2833
29- const MINT_CALLDATA_LEN : usize = 20 + 32 ;
34+ const MINT_CALLDATA_LEN : usize = 4 + 20 + 32 ; // selector + address + amount
35+ const BURN_CALLDATA_LEN : usize = 4 + 32 ; // selector + amount
3036
3137 fn revert_outcome ( message : & str , inputs : & CallInputs ) -> CallOutcome {
3238 CallOutcome :: new (
@@ -58,18 +64,42 @@ where
5864 }
5965
6066 let calldata = inputs. input . bytes ( context) ;
61- if calldata. len ( ) != Self :: MINT_CALLDATA_LEN {
62- return Some ( Self :: revert_outcome ( "invalid input length" , inputs) ) ;
63- }
64-
65- let amount = U256 :: from_be_slice ( & calldata[ 20 ..Self :: MINT_CALLDATA_LEN ] ) ;
66- if amount > self . per_call_cap {
67- return Some ( Self :: revert_outcome ( "over per-call cap" , inputs) ) ;
68- }
6967
70- if let Some ( cap) = self . per_block_cap {
71- if self . minted_this_block + amount > cap {
72- return Some ( Self :: revert_outcome ( "over per-block cap" , inputs) ) ;
68+ // Parse operation type
69+ let operation = match parse_operation ( & calldata) {
70+ Ok ( op) => op,
71+ Err ( _) => return Some ( Self :: revert_outcome ( "invalid operation" , inputs) ) ,
72+ } ;
73+
74+ // Validate length based on operation
75+ match operation {
76+ Operation :: Mint => {
77+ if calldata. len ( ) != Self :: MINT_CALLDATA_LEN {
78+ return Some ( Self :: revert_outcome ( "invalid mint input length" , inputs) ) ;
79+ }
80+ let amount = U256 :: from_be_slice ( & calldata[ 24 ..Self :: MINT_CALLDATA_LEN ] ) ;
81+ if amount > self . per_call_cap {
82+ return Some ( Self :: revert_outcome ( "over per-call cap" , inputs) ) ;
83+ }
84+ if let Some ( cap) = self . per_block_cap {
85+ if self . minted_this_block + amount > cap {
86+ return Some ( Self :: revert_outcome ( "over per-block cap" , inputs) ) ;
87+ }
88+ }
89+ }
90+ Operation :: Burn => {
91+ if calldata. len ( ) != Self :: BURN_CALLDATA_LEN {
92+ return Some ( Self :: revert_outcome ( "invalid burn input length" , inputs) ) ;
93+ }
94+ let amount = U256 :: from_be_slice ( & calldata[ 4 ..Self :: BURN_CALLDATA_LEN ] ) ;
95+ if amount > self . per_call_cap {
96+ return Some ( Self :: revert_outcome ( "over per-call cap" , inputs) ) ;
97+ }
98+ if let Some ( cap) = self . per_block_cap {
99+ if self . burned_this_block + amount > cap {
100+ return Some ( Self :: revert_outcome ( "over per-block cap" , inputs) ) ;
101+ }
102+ }
73103 }
74104 }
75105
@@ -82,24 +112,63 @@ where
82112 }
83113
84114 let calldata = inputs. input . bytes ( context) ;
85- if calldata. len ( ) != Self :: MINT_CALLDATA_LEN {
86- outcome. result = Self :: revert_result ( "invalid input length" ) ;
87- return ;
88- }
89-
90- let to = Address :: from_slice ( & calldata[ ..20 ] ) ;
91- let amount = U256 :: from_be_slice ( & calldata[ 20 ..Self :: MINT_CALLDATA_LEN ] ) ;
92115
93- match context. journal_mut ( ) . load_account ( to) {
94- Ok ( mut account_load) => {
95- account_load. info . balance += amount;
96- }
116+ // Parse operation type
117+ let operation = match parse_operation ( & calldata) {
118+ Ok ( op) => op,
97119 Err ( _) => {
98- outcome. result = Self :: revert_result ( "account load failed " ) ;
120+ outcome. result = Self :: revert_result ( "invalid operation " ) ;
99121 return ;
100122 }
123+ } ;
124+
125+ match operation {
126+ Operation :: Mint => {
127+ if calldata. len ( ) != Self :: MINT_CALLDATA_LEN {
128+ outcome. result = Self :: revert_result ( "invalid mint input length" ) ;
129+ return ;
130+ }
131+
132+ let to = Address :: from_slice ( & calldata[ 4 ..24 ] ) ;
133+ let amount = U256 :: from_be_slice ( & calldata[ 24 ..Self :: MINT_CALLDATA_LEN ] ) ;
134+
135+ match context. journal_mut ( ) . load_account ( to) {
136+ Ok ( mut account_load) => {
137+ account_load. info . balance += amount;
138+ }
139+ Err ( _) => {
140+ outcome. result = Self :: revert_result ( "account load failed" ) ;
141+ return ;
142+ }
143+ }
144+
145+ self . minted_this_block += amount;
146+ }
147+ Operation :: Burn => {
148+ if calldata. len ( ) != Self :: BURN_CALLDATA_LEN {
149+ outcome. result = Self :: revert_result ( "invalid burn input length" ) ;
150+ return ;
151+ }
152+
153+ let amount = U256 :: from_be_slice ( & calldata[ 4 ..Self :: BURN_CALLDATA_LEN ] ) ;
154+
155+ // Burn from caller's balance
156+ match context. journal_mut ( ) . load_account ( inputs. caller ) {
157+ Ok ( mut account_load) => {
158+ if account_load. info . balance < amount {
159+ outcome. result = Self :: revert_result ( "insufficient balance" ) ;
160+ return ;
161+ }
162+ account_load. info . balance -= amount;
163+ }
164+ Err ( _) => {
165+ outcome. result = Self :: revert_result ( "account load failed" ) ;
166+ return ;
167+ }
168+ }
169+
170+ self . burned_this_block += amount;
171+ }
101172 }
102-
103- self . minted_this_block += amount;
104173 }
105174}
0 commit comments