0

I am trying to implement and test an ERC20 token by inheriting from ERC20.sol from OpenZeppelin. I want most of the functions to be by default from OpenZeppelin but I also want to overrride some of them. For example, I have overriden increaseAllowance with the below code with the goal not to call approve in increaseAllowance to avoid front running.

function increaseAllowance(address spender, uint256 addedValue) public override returns (bool) {
    require(spender != address(0), "KToken: transfer to the zero address");
    
    _allowances[msg.sender][spender] += addedValue;

    emit Approval(msg.sender, spender, _allowances[msg.sender][spender]);
    return true;
}

When I test this function the _allowances state variable is not updated as expected. It keeps the value it had before and it is not increased by addedValue.

This is the test that I am running.

it("account1 should be able to increase allowance to account2", async () => {

  const kateToken = await deploy(accounts);
        
  // transfer 1000 tokens to account1 FROM owner     
  await kateToken.transfer(accounts[1], toWei('1000'), {from: accounts[0]});

  // approve 50 tokens FROM account1 TO account2
  await kateToken.approve(accounts[2], toWei('50'), {from: accounts[1]});

  let allowanceToAccountBEFORE = fromWei(await kateToken.allowance(accounts[1], accounts[2]));               

  // attempt to increase allowance to account2 by 150 tokens
  let increaseAllowanceProccess = await kateToken.increaseAllowance(accounts[2], toWei('150'), {from: accounts[1]});

  // get allowance of account2 converted from string to number so as to make calcs in asserts
  let allowanceToAccountAFTER = parseInt(fromWei(await kateToken.allowance(accounts[1], accounts[2])));        

  assert.equal(increaseAllowanceProccess.receipt.status, true, `proccess to increase allowance did not succeed`);
  assert.equal(allowanceToAccountBEFORE, allowanceToAccountAFTER-150, `allowance of account2 is not increased by 150 tokens`);

});

If I comment my code and increaseAllowance is called by OpenZeppelin's the test runs with success.

If not, allowance is not updated by 150 tokens, it remains 50 which was set by approve. But the strange thing is that I get the Approval Event (emited with only the addedValue), I can get the tx receipt with status true.

Do I have any logical or other issue that I can not get?

Is _allowances state variable from my contract different than _allowances state variable from OpenZeppelin's ERC20 Contract which I am inheriting from?

By the way, I have also implemented the same code by inheriting from IERC20 with no issues and succesful testing, and I can not understand why this does not work with ERC20.

Thank you in advance!

3
  • What OpenZeppelin version are you using? The override code modifies _allowances but shouldn't be possible in recent version because it is declared as private.
    – Ismael
    Commented Sep 29, 2021 at 16:05
  • @Ismael, am using the latest version of OpenZeppelin (pragma solidity ^0.8.0;). I can get _allowances from the public allowance function, if that helps.
    – katerith
    Commented Sep 29, 2021 at 16:43
  • The variable _allowances declared in your contract that will be different from the variable declared in OZ's contracts. To access the variable you have to use allowance to read it and _approve to modify ti.
    – Ismael
    Commented Sep 29, 2021 at 19:49

1 Answer 1

0

For example to override increaseAllowance you have to do something like this:

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";


contract Token2 is ERC20 {
    constructor() ERC20("Moe Szyslak", "MOE") {}

    function increaseAllowance(address spender, uint256 addedValue) public override returns (bool) {
        require(spender != address(0), "KToken: transfer to the zero address");

        uint256 allowed = allowance(msg.sender, spender);
        allowed += addedValue;

        _approve(msg.sender, spender, allowed);

        emit Approval(msg.sender, spender, allowed);

        return true;
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.