Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verify proxy/implementation on etherscan #541

Draft
wants to merge 10 commits into
base: develop
Choose a base branch
from
1 change: 1 addition & 0 deletions DEPLOYMENT_CHECKLIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ To deploy run `yarn deploy --network NETWORK` in `packages/contracts` and replac
- [ ] Go to the blockchain explorer and verify that each address is verified
- [ ] If it is not try to verfiy it with `npx hardhat verify --network NETWORK ADDRESS CONTRUCTOR-ARGS`. More infos on how to use this command can be found here: [https://hardhat.org/hardhat-runner/docs/guides/verifying](https://hardhat.org/hardhat-runner/docs/guides/verifying)
- [ ] If it is a proxy try to activate the blockchain explorer's proxy feature
- [ ] Try running `yarn linkProxies --network <network>` to automate this
- [ ] If the proxies are not verified with the `Similar Match Source Code` feature
- [ ] Verify one of the proxies
- [ ] Check if the other proxies are now verified with `Similar Match Source Code`
Expand Down
1 change: 1 addition & 0 deletions UPDATE_CHECKLIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ If the deployer **is** allowed to create a proposal
- [ ] Go to the blockchain explorer and verify that each address is verified
- [ ] If it is not try to verfiy it with `npx hardhat verify --network NETWORK ADDRESS CONTRUCTOR-ARGS`. More infos on how to use this command can be found here: [https://hardhat.org/hardhat-runner/docs/guides/verifying](https://hardhat.org/hardhat-runner/docs/guides/verifying)
- [ ] If it is a proxy try to activate the blockchain explorer's proxy feature
- [ ] Try running `yarn linkProxies --network <network>` to automate this
- [ ] If the proxies are not verified with the `Similar Match Source Code` feature
- [ ] Remove `import '@openzeppelin/hardhat-upgrades'` from `packages/contracts/hardhat.config.ts`
- [ ] Verify one of the proxies
Expand Down
14 changes: 5 additions & 9 deletions packages/contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,15 @@ Please do not use the issue tracker for security issues.

## Etherscan verification

To try out Etherscan verification, you first need to deploy a contract to an Ethereum testnet that's supported by Etherscan, such as [goerli](https://goerli.etherscan.io) or [sepolia](https://sepolia.etherscan.io).
Verification of contracts is currently handled by the etherscan verify plugin, invoked as a hardhat deploy stage. Contracts are bound to the HRE during deployment and then used as part of verification.

In this project, copy the `.env.example` file to a file named .env, and then edit it to fill in the details. Enter your Etherscan API key, your Goerli node URL (eg from Alchemy), and the private key of the account which will send the deployment transaction. With a valid .env file in place, first deploy your contract:
Make sure you have your Etherscan key setup in the HH config before running the deploy script.

```shell
hardhat run --network goerli scripts/sample-script.ts
```
### Proxy Verification

Then, copy the deployment address and paste it in to replace `DEPLOYED_CONTRACT_ADDRESS` in this command:
To avoid having to manually set 'Is this a Proxy?' in etherscan, you may call the Proxy Verification script, once your contracts have been verified. To do this run: `yarn verifyProxies --network <network>`.

```shell
npx hardhat verify --network goerli DEPLOYED_CONTRACT_ADDRESS "Hello, Hardhat!"
```
This can be run multiple times provided you haven't used the `--reset` flag to clear the deployment data. The etherscan API can be a little flaky at times so be patient with it and try multiple times if necessary.
Comment on lines +67 to +69
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would bet that this is because of rate limiting. Have you tried waiting 6s between the requests as we do it in our deploy script?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe it is: the error messaging indicates the contracts cannot be found sometimes, although this appears to be inconsistent. I think it may be due to delays in indexing the contracts on the explorers, and propagating the data.

Copy link
Contributor

@heueristik heueristik Mar 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had the same problem with Polygon. In this case, we added a one-time delay to the script.

// add a timeout for polygon because the call to `implementation()` can fail for newly deployed contracts in the first few seconds
if (network.name === 'polygon') {
console.log(`Waiting 30secs for ${network.name} to finish up...`);
await setTimeout(30000);
}

I think having a script that runs robustly and doesn't need to be executed multiple times, is important.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will take a look, if it doesn't work I will shelf the PR for now to avoid getting stuck on it.


## Testing with Previous Contract Versions

Expand Down
32 changes: 32 additions & 0 deletions packages/contracts/__req.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/sh

API_KEY="E7WHCR4BRTF2W4YPZQMFJZKBEHB6788QN3"

# Deploy and capture the output
cmd=$(yarn deploy --network optimismSepolia --tags VerifyProxies)
echo "Deployment command output:"
echo "$cmd"

# Extract GUIDs based on the new phrase
echo "Extracted GUIDs:"
guids=$(echo "$cmd" | grep -oP 'To check the request status, use \K\S+')
echo "$guids"

if [ -z "$guids" ]; then
echo "No GUIDs found. Exiting."
exit 1
fi

# Make API calls for each GUID
echo "API call results:"
echo "$guids" | while read -r guid; do
if [ -n "$guid" ]; then
url="https://api-sepolia-optimistic.etherscan.io/api?module=contract&action=checkproxyverification&guid=${guid}&apikey=$API_KEY"
echo "Calling: $url"
response=$(curl -s "$url")
echo "Response: $response"
echo # Print a newline for readability
else
echo "Empty GUID, skipping..."
fi
done
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
}
};
export default func;
func.tags = ['New', 'Verify'];
func.tags = ['New', 'Verify', 'BlockExplorerUploadContracts'];
func.runAtTheEnd = true;
func.skip = (hre: HardhatRuntimeEnvironment) =>
Promise.resolve(isLocal(hre.network));
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {isLocal} from '../../../utils/environment';
import {
collectProxyWithImplementation,
generateExplorerIsThisAProxyURL,
handleLinkProxyRequest,
} from '../../../utils/etherscan';
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';

/**
* This script can be run manually after the deployment of the contracts and contract verification,
* call `yarn linkProxies --network <network>` to run this script.
*
* It searches deployments for proxies and their implementations and links them on Etherscan.
* This avoids the need to call 'Is this a proxy?' for each contract using the UI.
* The script will request the linkage for all proxies and implementations and return a GUID to check the status
* of the request.
*
* The API is inconsistent when linking proxies, so we don't include this as part of the default deployment process.
*/
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
console.log('\nLinking Proxies on Etherscan');

const url = generateExplorerIsThisAProxyURL(hre);
const verifyData = collectProxyWithImplementation(
await hre.deployments.all()
);

console.log(
`Linking ${verifyData.length} proxies on Etherscan, please be patient.`
);

for (const {proxy, implementation} of verifyData) {
await handleLinkProxyRequest(url, proxy, implementation);
}
};
export default func;

func.tags = ['New', 'Verify', 'LinkProxies'];
func.dependencies = ['VerifyContracts'];
func.runAtTheEnd = true;

func.skip = (hre: HardhatRuntimeEnvironment) => {
const verifyProxies = process.env.LINK_PROXIES === 'true';
return Promise.resolve(isLocal(hre.network) || !verifyProxies);
};
21 changes: 11 additions & 10 deletions packages/contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"flatten": "hardhat flatten",
"analyze": "mythx analyze",
"deploy": "hardhat deploy",
"linkProxies": "LINK_PROXIES=true yarn deploy --tags LinkProxies",
"deploy:local": "yarn deploy --network localhost --reset",
"dev": "yarn hardhat node --hostname 0.0.0.0",
"prepublishOnly": "yarn build && yarn build:npm",
Expand All @@ -41,7 +42,7 @@
},
"homepage": "https://github.com/aragon/osx#readme",
"dependencies": {
"@aragon/osx-commons-contracts": "^1.4.0-alpha.2",
"@aragon/osx-commons-contracts": "1.4.0-alpha.2",
"@ensdomains/ens-contracts": "0.0.11",
"@openzeppelin/contracts": "4.9.5",
"@openzeppelin/contracts-upgradeable": "4.9.5"
Expand All @@ -52,15 +53,15 @@
"@aragon/osx-ethers-v1.2.0": "npm:@aragon/[email protected]",
"@aragon/osx-v1.0.1": "npm:@aragon/[email protected]",
"@aragon/osx-v1.3.0": "npm:@aragon/[email protected]",
"@defi-wonderland/smock": "^2.3.4",
"@nomicfoundation/hardhat-chai-matchers": "^1.0.5",
"@nomicfoundation/hardhat-network-helpers": "^1.0.8",
"@nomicfoundation/hardhat-verify": "^1.0.4",
"@nomiclabs/hardhat-ethers": "^2.2.1",
"@defi-wonderland/smock": "2.3.4",
"@nomicfoundation/hardhat-chai-matchers": "1.0.5",
"@nomicfoundation/hardhat-network-helpers": "1.0.8",
"@nomicfoundation/hardhat-verify": "1.0.4",
"@nomiclabs/hardhat-ethers": "2.2.1",
"@openzeppelin/hardhat-upgrades": "^1.23.1",
"@rollup/plugin-json": "^4.1.0",
"@typechain/ethers-v5": "^7.2.0",
"@typechain/hardhat": "^2.3.1",
"@typechain/ethers-v5": "7.2.0",
"@typechain/hardhat": "2.3.1",
"@types/chai": "^4.2.22",
"@types/mocha": "^9.0.0",
"@types/node": "^16.11.7",
Expand All @@ -77,7 +78,7 @@
"eslint-plugin-promise": "^5.1.1",
"ethereumjs-util": "^7.1.4",
"ethers": "^5.5.1",
"hardhat": "^2.12.7",
"hardhat": "2.12.7",
"hardhat-deploy": "^0.9.26",
"hardhat-gas-reporter": "^1.0.4",
"ipfs-http-client": "51.0.0",
Expand All @@ -88,7 +89,7 @@
"solidity-docgen": "^0.6.0-beta.35",
"tmp-promise": "^3.0.3",
"ts-node": "^8.1.0",
"typechain": "^5.2.0",
"typechain": "5.2.0",
"typescript": "^4.4.4"
}
}
6 changes: 2 additions & 4 deletions packages/contracts/src/test/ProtocolVersionMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,5 @@ pragma solidity ^0.8.8;
import {ProtocolVersion} from "@aragon/osx-commons-contracts/src/utils/versioning/ProtocolVersion.sol";

/// @title ProtocolVersionMock
// solhint-disable-next-line no-empty-blocks
contract ProtocolVersionMock is ProtocolVersion {

}
// solhint-disable no-empty-blocks
contract ProtocolVersionMock is ProtocolVersion {}
83 changes: 83 additions & 0 deletions packages/contracts/test/deploy/mocks/mock-deployments.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
"ManagementDAOProxy_Implementation": {
"address": "0x5FbDB2315678afecb367f032d93F642f64180aa3"
},
"ManagementDAOProxy_Proxy": {
"address": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512"
},
"ManagementDAOProxy": {
"address": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512"
},
"ENSRegistry": {
"address": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9"
},
"PublicResolver": {
"address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707"
},
"DAOENSSubdomainRegistrarProxy_Implementation": {
"address": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82"
},
"DAOENSSubdomainRegistrarProxy_Proxy": {
"address": "0x9A676e781A523b5d0C0e43731313A708CB607508"
},
"DAOENSSubdomainRegistrarProxy": {
"address": "0x9A676e781A523b5d0C0e43731313A708CB607508"
},
"PluginENSSubdomainRegistrarProxy_Implementation": {
"address": "0x0B306BF915C4d645ff596e518fAf3F9669b97016"
},
"PluginENSSubdomainRegistrarProxy_Proxy": {
"address": "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1"
},
"PluginENSSubdomainRegistrarProxy": {
"address": "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1"
},
"DAORegistryProxy_Implementation": {
"address": "0x68B1D87F95878fE05B998F19b66F4baba5De1aed"
},
"DAORegistryProxy_Proxy": {
"address": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c"
},
"DAORegistryProxy": {
"address": "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c"
},
"PluginRepoRegistryProxy_Implementation": {
"address": "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d"
},
"PluginRepoRegistryProxy_Proxy": {
"address": "0x59b670e9fA9D0A427751Af201D676719a970857b"
},
"PluginRepoRegistryProxy": {
"address": "0x59b670e9fA9D0A427751Af201D676719a970857b"
},
"PluginRepoFactory": {
"address": "0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1"
},
"PluginSetupProcessor": {
"address": "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44"
},
"DAOFactory": {
"address": "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f"
},
"AddresslistVotingSetup": {
"address": "0xc5a5C42992dECbae36851359345FE25997F5C42d"
},
"GovernanceERC20": {
"address": "0x67d269191c92Caf3cD7723F116c85e6E9bf55933"
},
"GovernanceWrappedERC20": {
"address": "0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E"
},
"TokenVotingSetup": {
"address": "0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690"
},
"AdminSetup": {
"address": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB"
},
"MultisigSetup": {
"address": "0x9E545E3C0baAB3E08CdfD552C960A1050f373042"
},
"PlaceholderSetup": {
"address": "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9"
}
}
Loading
Loading