diff --git a/contracts/v4-patch/GovernancePatchUpgrade.sol b/contracts/v4-patch/GovernancePatchUpgrade.sol index 36907cc..27dd8d6 100644 --- a/contracts/v4-patch/GovernancePatchUpgrade.sol +++ b/contracts/v4-patch/GovernancePatchUpgrade.sol @@ -16,6 +16,10 @@ contract GovernancePatchUpgrade is GovernanceStakingUpgrade { address userVaultAddress ) public GovernanceStakingUpgrade(stakingRewardsAddress, gasCompLogic, userVaultAddress) {} + function version() external pure virtual override returns (string memory) { + return "4.patch-exploit"; + } + // This should guarantee that the proposal extcodehashes are good function execute(uint256 proposalId) public payable virtual override(Governance) { require(msg.sender != address(this), "pseudo-external function"); diff --git a/contracts/v4-patch/PatchProposal.sol b/contracts/v4-patch/PatchProposal.sol index b4a1fc4..f260d7b 100644 --- a/contracts/v4-patch/PatchProposal.sol +++ b/contracts/v4-patch/PatchProposal.sol @@ -18,7 +18,7 @@ interface Proxy { // We will have to do this because of the contract size limit -contract ProposalContractsFactory { +contract PatchProposalContractsFactory { function createStakingRewards( address governance, address torn, @@ -48,10 +48,10 @@ contract PatchProposal { IERC20 public constant TORN = IERC20(0x77777FeDdddFfC19Ff86DB637967013e6C6A116C); - ProposalContractsFactory public immutable proposalContractsFactory; + PatchProposalContractsFactory public immutable patchProposalContractsFactory; - constructor(address _proposalContractsFactory) public { - proposalContractsFactory = ProposalContractsFactory(_proposalContractsFactory); + constructor(address _patchProposalContractsFactory) public { + patchProposalContractsFactory = PatchProposalContractsFactory(_patchProposalContractsFactory); } // Aight lets do this sirs @@ -71,11 +71,11 @@ contract PatchProposal { // And create a new staking contract TornadoStakingRewards newStaking = TornadoStakingRewards( - proposalContractsFactory.createStakingRewards(address(governance), address(TORN), registry) + patchProposalContractsFactory.createStakingRewards(address(governance), address(TORN), registry) ); // And a new registry implementation - address newRegistryImplementationAddress = proposalContractsFactory.createRegistryContract( + address newRegistryImplementationAddress = patchProposalContractsFactory.createRegistryContract( address(TORN), address(governance), ensAddress, diff --git a/deploy/deployPatch.js b/deploy/deployPatch.js new file mode 100644 index 0000000..4a71dd8 --- /dev/null +++ b/deploy/deployPatch.js @@ -0,0 +1,84 @@ +require('dotenv').config() + +const hre = require('hardhat') + +const { ethers } = hre + +const { createInterface } = require('readline') + +const prompter = createInterface({ input: process.stdin, output: process.stdout }) + +function _prompt(prompt, resolve) { + prompter.question(prompt, (answer) => { + if (answer == 'y') { + resolve(true) + } else if (answer == 'n') { + resolve(false) + } else _prompt('', resolve) + }) +} + +function prompt(prompt) { + return new Promise((resolve) => _prompt(prompt, resolve)) +} + +function deployedMessage(name, chainId, address) { + return `\n${name} deployed on ${idToNetwork(chainId)} @ ${address}\n` +} + +function verifiedMessage(name, address) { + return `\n${name} @ ${address} verified on Etherscan!\n` +} + +function timeout(seconds) { + return new Promise((resolve) => setTimeout(resolve, seconds * 1000)) +} + +const promptMessageBase = (middle) => `\n${middle}\n\nAre you sure you would like to continue? (y/n): ` + +async function deploy() { + const signer = await ethers.getSigner() + + const patchProposalContractsFactoryDeployer = ( + await ethers.getContractFactory('PatchProposalContractsFactory') + ).connect(signer) + + const patchProposalDeployer = (await ethers.getContractFactory('PatchProposal')).connect(signer) + + let patchProposal, patchProposalContractsFactory + + if (await prompt(promptMessageBase('Continuing to PatchProposalContractsFactory deployment.'))) { + patchProposalContractsFactory = await patchProposalContractsFactoryDeployer.deploy() + console.log(deployedMessage('PatchProposalContractsFactory', 1, patchProposalContractsFactory.address)) + } else { + return '\nDecided to stop at PatchProposalContractsFactory deployment.\n' + } + + if (await prompt(promptMessageBase('Continuing to PatchProposal deployment.'))) { + patchProposal = await patchProposalDeployer.deploy(patchProposalContractsFactory.address) + console.log(deployedMessage('PatchProposal', 1, patchProposal.address)) + } else { + return '\nDecided to stop at PatchProposal deployment.\n' + } + + if (await prompt(promptMessageBase('Continuing to contract verification.'))) { + await hre.run('verify:verify', { + address: patchProposalContractsFactory.address, + }) + + console.log(verifiedMessage('PatchProposalContractsFactory')) + console.log('\nWaiting 5 seconds.\n') + await timeout(5) + + await hre.run('verify:verify', { + address: patchProposal.address, + constructorArguments: [patchProposalContractsFactory.address], + }) + + console.log(verifiedMessage('PatchProposal')) + } else { + return '\nDecided to stop at contract verification.\n' + } +} + +deploy() diff --git a/test/patch/patch.test.js b/test/patch/patch.test.js index a0f5383..f2db310 100644 --- a/test/patch/patch.test.js +++ b/test/patch/patch.test.js @@ -134,7 +134,7 @@ describe('Gov Exploit Patch Upgrade Tests', () => { initialProposalDeployer = await ethers.getContractFactory('InitialProposal') maliciousProposalDeployer = await ethers.getContractFactory('MaliciousProposal') - proposalContractsDeployer = await ethers.getContractFactory('ProposalContractsFactory') + proposalContractsDeployer = await ethers.getContractFactory('PatchProposalContractsFactory') proposalDeployer = await ethers.getContractFactory('PatchProposal') // Metamorphic & Exploit