Skip to content

Commit 62f6a28

Browse files
authored
Merge pull request #2463 from oasisprotocol/peternose/bugfix/erc20-read-only
runtime-sdk/modules/evm/src/precompile/erc20: Support read-only mode
2 parents 6999422 + adf766b commit 62f6a28

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

  • runtime-sdk/modules/evm/src/precompile

runtime-sdk/modules/evm/src/precompile/erc20.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)