Hi, I'm trying to create an upgradeable factory contract that can create proxies of ERC20 tokens.
I have the Factory contract that is:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";
import "./TokenProxyR.sol";
import "./TokenR.sol";
contract TokenFactoryR is Initializable, OwnableUpgradeable {
using CountersUpgradeable for CountersUpgradeable.Counter;
mapping(uint256 => address) private addressesProxies;
CountersUpgradeable.Counter private counter;
string private version;
function initialize(string memory _version) public initializer {
_transferOwnership(tx.origin);
version = _version;
}
function versionContract() public view returns (string memory) {
return version;
}
function createProxyContract(string memory _name, string memory _symbol) public onlyOwner {
TokenR token = new TokenR();
TokenProxyR newProxy = new TokenProxyR(address(token), abi.encodeWithSelector(TokenR(address(0)).initialize.selector, _name, _symbol));
uint256 currentCounter = counter.current();
addressesProxies[currentCounter] = address(newProxy);
counter.increment();
}
function getProxyAddress(uint256 id) public view returns(address) {
return addressesProxies[id];
}
function getCurrentCounter() public view returns(uint256) {
return counter.current();
}
}
This factory creates Proxies:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/proxy/Proxy.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
contract TokenProxyR is ERC1967Proxy {
uint32 private version;
constructor(address _logic, bytes memory _data) ERC1967Proxy(_logic, _data) {}
function versionProxy() public view returns(uint32) {
return version;
}
function upgradeTo(address implementation) public {
super._upgradeTo(implementation);
}
}
This proxy creates forwards the functions calls to this contract here:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
contract TokenR is
Initializable,
ERC20Upgradeable,
ERC20BurnableUpgradeable,
PausableUpgradeable,
OwnableUpgradeable
{
//This function gets called by the TokenFactory contract
function initialize(string memory _name, string memory _symbol)
external
initializer
{
__ERC20_init(_name, _symbol);
__ERC20Burnable_init();
__Pausable_init();
__Ownable_init();
}
}
Is this correct?
I have tested throughly and all the tests pass successfully.
But I was thinking: is this practice correct?
So can an upgradeable contract (Factory) create Proxies in this way (these contracts don't use the "initialize" function but a ERC1967 constructor)?
Thanks a bunch.