Hi, first time posting here, hopefully I'm doing this correctly.
I'm trying to deploy a UUPSUgradeable contract. I was able to deploy it locally on Ganache and then on the ropsten testnet, but I am running into an issue with verifying the implementation contract on ropsten etherscan.
TTP8.sol is my implementation contract (see below)
I've also included the content of 2_deploy_contracts.js below.
I deployed the following 3 contracts:
TestTP8 - 0x42d613469421a1D33fCc8e6D5D9F230aF97E57e9
ProxyAdmin - 0x459D8AD49E61e314469B039bf67b1308a3362a30
TransparentUpgradeableProxy - 0x401C312d588d879F58BC12B55Ff293D6b2F7eaE0 --> I also have a side question about this one. From all the forum help I reviewed, I keep seeing that this proxy should be called 'AdminUpgradeabilityProxy' and the fact that I generated the code using the OpenZeppelin Wizard by selecting UUPSUpgradeable instead of Transparent makes me wonder why I see get a TransparentUpgradeableProxy. Would you be able to help me understand this point to see if I did anything wrong?
Now, with regards to my verify issue:
I tried it with 1) truffle-verify-plugin and 2) truffle-flattener. I've been using truffle-verify-plugin successfully on ropsten for other test contracts I deployed that are not upgradeable. But I get this output when I try it on my TTP8 upgradeable implementation contract:
C:\Solidity\ttp8>truffle run verify testtp8 --network ropsten
Verifying testtp8
Fail - Unable to verify
Failed to verify 1 contract(s): testtp8
I found in a different forum question that someone has used the truffle-flattener successfully instead, so I tried it as well and unfortunately, could not get it to work. I got this error:
C:\Solidity\ttp8>truffle-flattener .\contracts\ttp8.sol
(node:13420) Warning: Accessing non-existent property 'INVALID_ALT_NUMBER' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
(node:13420) Warning: Accessing non-existent property 'INVALID_ALT_NUMBER' of module exports inside circular dependency
Error: Could not parse C:\Solidity\ttp8\node_modules\@openzeppelin\contracts-upgradeable\token\ERC20\ERC20Upgradeable.sol for extracting its imports: ParserError: missing ';' at '{' (164:18)
at getDependencies (C:\Users\name\AppData\Roaming\npm\node_modules\truffle-flattener\index.js:44:11)
at dependenciesDfs (C:\Users\name\AppData\Roaming\npm\node_modules\truffle-flattener\index.js:64:24)
at async dependenciesDfs (C:\Users\name\AppData\Roaming\npm\node_modules\truffle-flattener\index.js:73:7)
at async getSortedFilePaths (C:\Users\name\AppData\Roaming\npm\node_modules\truffle-flattener\index.js:83:5)
at async flatten (C:\Users\name\AppData\Roaming\npm\node_modules\truffle-flattener\index.js:180:23)
at async main (C:\Users\name\AppData\Roaming\npm\node_modules\truffle-flattener\index.js:237:3)
I've tried to use the multi file verify option on ropsten etherscan by uploading all the respective .sol files that I see in my build folder, but that did not work as well (I was not able to find any good instructions on how to use the multifile verify option on etherscan in general, is there any good resources on this that anyone can share?). I got these errors (this is just the start of it, the list of errors goes on and on in a similar format):
ParserError: Source "utils/ContextUpgradeable.sol" not found: File import callback not supported
--> AccessControlUpgradeable.sol:6:1:
|
6 | import "../utils/ContextUpgradeable.sol"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ParserError: Source "utils/StringsUpgradeable.sol" not found: File import callback not supported
--> AccessControlUpgradeable.sol:7:1:
|
7 | import "../utils/StringsUpgradeable.sol"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ParserError: Source "utils/introspection/ERC165Upgradeable.sol" not found: File import callback not supported
--> AccessControlUpgradeable.sol:8:1:
|
8 | import "../utils/introspection/ERC165Upgradeable.sol"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ParserError: Source "proxy/utils/Initializable.sol" not found: File import callback not supported
--> AccessControlUpgradeable.sol:9:1:
|
Thanks a lot for your help!
Code to reproduce
TTP8.sol -->
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
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/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
contract TestTP8 is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, PausableUpgradeable, AccessControlUpgradeable, UUPSUpgradeable {
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
function initialize() initializer public {
__ERC20_init("TestTP8", "TTP8");
__ERC20Burnable_init();
__Pausable_init();
__AccessControl_init();
__UUPSUpgradeable_init();
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(PAUSER_ROLE, msg.sender);
_mint(msg.sender, 25000 * 10 ** decimals());
_setupRole(MINTER_ROLE, msg.sender);
_setupRole(UPGRADER_ROLE, msg.sender);
}
function pause() public onlyRole(PAUSER_ROLE) {
_pause();
}
function unpause() public onlyRole(PAUSER_ROLE) {
_unpause();
}
function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
_mint(to, amount);
}
function _beforeTokenTransfer(address from, address to, uint256 amount)
internal
whenNotPaused
override
{
super._beforeTokenTransfer(from, to, amount);
}
function _authorizeUpgrade(address newImplementation)
internal
onlyRole(UPGRADER_ROLE)
override
{}
//Extra code added from this point on
function burnFrom(address account, uint256 amount) public virtual override {
require(
hasRole(DEFAULT_ADMIN_ROLE, _msgSender()),
"ModifiedAccessControl: Only DEFAULT_ADMIN_ROLE may use burnFrom"
);
super.burnFrom(account, amount);
}
function burn(uint256 amount) public virtual override {
require(
hasRole(DEFAULT_ADMIN_ROLE, _msgSender()),
"ModifiedAccessControl: Only DEFAULT_ADMIN_ROLE may use burn"
);
super.burn(amount);
}
function multiTransfer(address[] calldata dests, uint256[] calldata values) external returns (uint256) {
uint256 i = 0;
while (i < dests.length) {
transfer(dests[i], values[i]);
i += 1;
}
return(i);
}
}
2_deploy_contracts.js -->
const TestTP8 = artifacts.require('TestTP8');
const { deployProxy } = require('@openzeppelin/truffle-upgrades');
module.exports = async function (deployer) {
await deployProxy(TestTP8, [], { deployer, initializer: 'initialize' });
};
Environment
Truffle v5.4.6 (core: 5.4.6)
Solidity - 0.8.4 (solc-js)
Node v14.17.5
Web3.js v1.5.1