Is the contract ERC20Upgradeable.sol also upgradable

Hi
I have a question to the upgradable Plugin.
I walked trough the Box contract example and i see there is a BoxV2.sol that upgrades the original Box.sol contract.

Lets say i customized the _transfer function in ERC20Upgradeable.sol with custom transaction Fees.
The ERC20Upgradeable.sol is imported on my main contract (lets call it also box.sol as
import “@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol”;

If i now create a 2nd. “BoxV2.sol” contract and change the import path to a new created ERC20UpgradeableV2.sol and then run the migration script.

I get this errors.

DeclarationError: Identifier already declared.
→ /home/ubuntu/contracts/box/contracts/box-V1.2.sol:5:1:
|
5 | import “@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol”;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Note: The previous declaration is here:
@openzeppelin/contracts-upgradeable/token/ERC20/ERC20UpgradeableV2.sol:34:1:

My question is, is it possible to upgrade the _transfer function located in the ERC20Upgradeable.sol?
For example if i want to change the fee or fee receiver i have static coded into the _transfer function?

Example _transfer function:

 function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");
		
	address FeeReceiverAdr = 0xE037D395bB24C69bD0347F4e1652199BF61a41d1;
        address payable FeeReceiver = payable(FeeReceiverAdr); // Correct since Solidity >= 0.6.0
		
        _beforeTokenTransfer(sender, recipient, amount);
		
	uint bpsfee = 1618;
	uint bps = 100000;
		
        uint fee = amount/bps*bpsfee;
        uint taxedValue = amount-fee;
        
        uint256 senderBalance = _balances[sender];
	require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");    
      
        _balances[sender] = senderBalance - amount;
	_balances[recipient] += taxedValue;
	_balances[FeeReceiver] +=  fee;
		
        emit Transfer(sender, recipient, taxedValue);
        emit Transfer(sender, FeeReceiver, fee);
    }

Figure out which identifier was defined twice and rename one of the two.

But you should avoid copying and modifying the ERC20Upgradeable contract. You should override either _transfer or _beforeTokenTransfer using inheritance.

Hi Frangio
Thank you for your feedback. Now it is compiling.
Just to be sure if i have done it the right way and to post the solution here :slight_smile:

I had to declare _balance in my box contract
And I added the _transfer function to my box contract and removed the view (only internal override)

mapping (address => uint256) private _balances;

 function _transfer(address sender, address recipient, uint256 amount) internal override {
......
}

Is this the correct way to have it upgradeable?
Cheers

I’m not sure I understand what you mean by having it upgradeable.

Your contract will be upgradeable if you deploy it with a proxy, for example by using the deployProxy function in our Upgrades Plugins for Hardhat and Truffle.