I apologize if this has been asked before, but I can't find what I'm looking for.
So, I want to build an ERC20 token that is Upgradeable. I started with the basic build the OZ Wizard creates:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20SnapshotUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
contract MyToken is Initializable, ERC20Upgradeable, ERC20SnapshotUpgradeable, OwnableUpgradeable, UUPSUpgradeable {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize() initializer public {
__ERC20_init("MyToken", "MTK");
__ERC20Snapshot_init();
__Ownable_init();
__UUPSUpgradeable_init();
_mint(msg.sender, 10000 * 10 ** decimals());
}
function snapshot() public onlyOwner {
_snapshot();
}
function _authorizeUpgrade(address newImplementation)
internal
onlyOwner
override
{}
// The following functions are overrides required by Solidity.
function _beforeTokenTransfer(address from, address to, uint256 amount)
internal
override(ERC20Upgradeable, ERC20SnapshotUpgradeable)
{
super._beforeTokenTransfer(from, to, amount);
}
}
I then wanted to modify the transfer function to add in some features like burning and auto liquidity, but when I add the transfer function from the original ERC20Upgradeable contract it throw the "Undeclared Identifier" error on all of the "_balances". I saw that it has to do with the mapping (which I don't understand because it should be pulling it from the ERC20Upgradeable import), so I throw it in there and the errors go away.
Now, when I compile this (on RemixIDE web) and deploy it to the London VM with a Proxy, it deploys successfully; however, when I try to transfer some of the tokens it throws:
The transaction has been reverted to the initial state.
Reason provided by the contract: "ERC20: transfer amount exceeds balance".
Debug the transaction to get more information.
I imagine this is due to the fact that it is trying to pull the balance from the mapping, but there wouldn't be anything there. This is just the start of my issues I've been running in to, but since I decided to try and build this contract from scratch this would be the starting place for my problems. I need help lol.
This is the deployed contract and as you can see I haven't even made any real changes:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20SnapshotUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
contract MyToken is Initializable, ERC20Upgradeable, ERC20SnapshotUpgradeable, OwnableUpgradeable, UUPSUpgradeable {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize() initializer public {
__ERC20_init("MyToken", "MTK");
__ERC20Snapshot_init();
__Ownable_init();
__UUPSUpgradeable_init();
_mint(msg.sender, 10000 * 10 ** decimals());
}
function snapshot() public onlyOwner {
_snapshot();
}
function _authorizeUpgrade(address newImplementation)
internal
onlyOwner
override
{}
// The following functions are overrides required by Solidity.
function _beforeTokenTransfer(address from, address to, uint256 amount)
internal
override(ERC20Upgradeable, ERC20SnapshotUpgradeable)
{
super._beforeTokenTransfer(from, to, amount);
}
/////////
mapping(address => uint256) private _balances;
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
function _transfer(
address from,
address to,
uint256 amount
) internal virtual override {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
}