@@ -391,6 +391,14 @@ impl<T: Erc20Token> Erc20Contract<T> {
391391 amount : u128 ,
392392 ) -> PrecompileResult {
393393 handle. record_cost ( T :: GAS_COSTS . transfer ) ?;
394+
395+ // Ensure that the call is read-only and cannot modify state when
396+ // called using a static call.
397+ let read_only = handle. is_static ( ) ;
398+ if read_only {
399+ return Err ( Error :: Forbidden . encode ( ) ) ;
400+ }
401+
394402 let sender = handle. context ( ) . caller ;
395403 match T :: transfer ( & sender, & recipient, amount) {
396404 Ok ( done) => {
@@ -418,6 +426,14 @@ impl<T: Erc20Token> Erc20Contract<T> {
418426 amount : u128 ,
419427 ) -> PrecompileResult {
420428 handle. record_cost ( T :: GAS_COSTS . transfer_from ) ?;
429+
430+ // Ensure that the call is read-only and cannot modify state when
431+ // called using a static call.
432+ let read_only = handle. is_static ( ) ;
433+ if read_only {
434+ return Err ( Error :: Forbidden . encode ( ) ) ;
435+ }
436+
421437 let caller = handle. context ( ) . caller ;
422438 match T :: transfer_from ( & owner, & caller, & recipient, amount) {
423439 Ok ( done) => {
@@ -444,6 +460,14 @@ impl<T: Erc20Token> Erc20Contract<T> {
444460 amount : u128 ,
445461 ) -> PrecompileResult {
446462 handle. record_cost ( T :: GAS_COSTS . approve ) ?;
463+
464+ // Ensure that the call is read-only and cannot modify state when
465+ // called using a static call.
466+ let read_only = handle. is_static ( ) ;
467+ if read_only {
468+ return Err ( Error :: Forbidden . encode ( ) ) ;
469+ }
470+
447471 let owner = handle. context ( ) . caller ;
448472 match T :: approve ( & owner, & spender, amount) {
449473 Ok ( done) => {
@@ -482,6 +506,14 @@ impl<T: Erc20Token> Erc20Contract<T> {
482506 #[ evm_method( signature = "mint(address,uint256)" , convert) ]
483507 fn mint ( handle : & mut impl PrecompileHandle , to : H160 , amount : u128 ) -> PrecompileResult {
484508 handle. record_cost ( T :: GAS_COSTS . mint ) ?;
509+
510+ // Ensure that the call is read-only and cannot modify state when
511+ // called using a static call.
512+ let read_only = handle. is_static ( ) ;
513+ if read_only {
514+ return Err ( Error :: Forbidden . encode ( ) ) ;
515+ }
516+
485517 let caller = handle. context ( ) . caller ;
486518 match T :: mint ( & caller, & to, amount) {
487519 Ok ( _) => {
@@ -504,6 +536,14 @@ impl<T: Erc20Token> Erc20Contract<T> {
504536 #[ evm_method( signature = "burn(address,uint256)" , convert) ]
505537 fn burn ( handle : & mut impl PrecompileHandle , from : H160 , amount : u128 ) -> PrecompileResult {
506538 handle. record_cost ( T :: GAS_COSTS . burn ) ?;
539+
540+ // Ensure that the call is read-only and cannot modify state when
541+ // called using a static call.
542+ let read_only = handle. is_static ( ) ;
543+ if read_only {
544+ return Err ( Error :: Forbidden . encode ( ) ) ;
545+ }
546+
507547 let caller = handle. context ( ) . caller ;
508548 match T :: burn ( & caller, & from, amount) {
509549 Ok ( _) => {
0 commit comments