Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function override does not work with inheritance as expected #109

Open
gwalen opened this issue Feb 25, 2024 · 0 comments
Open

Function override does not work with inheritance as expected #109

gwalen opened this issue Feb 25, 2024 · 0 comments

Comments

@gwalen
Copy link

gwalen commented Feb 25, 2024

Stylus version: 0.4.2

Class structure:

We want to implement a classic MyToken contract that that inherits from Erc20 and change it's behavior by overriding the implementation of update(..) virtual method from Erc20.

Erc20 is implemented with OpenZeppelin code as reference (link here)

Solidity way:

abstract contract ERC20  { 
   //.....
   function _update(address from, address to, uint256 value) internal virtual {
       // function body
    }
   //other Erc20 functions
}

contract MyToken is ERC20, Pausable {
    constructor {...}

    function _update(address from, address to, uint256 value) internal virtual override {
       // new logic goes here
       // after new logic is executed we want to run base impl from ERC20
        super._update(from, to, value); 
    }
}

To do the same with Stylus following structure hierarchy was defined:

sol_storage! {
    pub struct Erc20<T> {
        // here goes the erc20 fields
    }
}

impl<T: Erc20Params> Erc20<T> {
    pub fn update(&mut self, from: Address, to: Address, value: U256) -> Result<(), Vec<u8>> {
    // method body
   }
}

#[external]
impl<T: Erc20Params> Erc20<T> {
    pub fn transfer(&mut self, to: Address, value: U256) -> Result<bool, Erc20Error> {
        let owner = msg::sender();
        self.transfer_internal(owner, to, value)?;
        Ok(true)
    }
  
  fn transfer_internal(&mut self, from: Address, to: Address, value: U256) -> Result<(), Erc20Error> {
        if from == Address::ZERO {
            return Err(Erc20Error::Erc20InvalidSpender(Erc20InvalidSpender {
                spender: Address::ZERO,
            }));    
        }
        if to == Address::ZERO {
            return Err(Erc20Error::Erc20InvalidReceiver(Erc20InvalidReceiver {
                receiver: Address::ZERO,
            }));
        }
        self.update(from, to, value)
    }

  // other methods of Erc20
}

-------------- MyToken impl
sol_storage! {
    #[entrypoint]  
    pub struct MyToken {
        #[borrow]
        Erc20<MyTokenParams> erc20;
    }
}
impl MyToken {
    pub fn update(&mut self, from: Address, to: Address, value: U256) -> Result<(), Vec<u8>> {
        // new logic comes here
        self.erc20.update(from, to, value)?;
        Ok(())
    }
}
#[external]
#[inherit(Erc20<MyTokenParams>)]
impl MyToken {
  // body if MyToken 
}

Issue

Expected behavior: when Erc20 methods call self.update(..) like in example above in transfer_internal(..) method, execution goes to overridden function defined in MyToken impl

Current behavior: calling self.update(..) inside transfer_internal(..) executes the update(..) from Erc20 impl

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant