manual deployment, optimization, formatting, need to update deploy script

Signed-off-by: AlienTornadosaurusHex <>
This commit is contained in:
AlienTornadosaurusHex 2023-05-24 23:59:14 +00:00
parent 75cf27d7d4
commit f14e8d988b
9 changed files with 147 additions and 103 deletions

View File

@ -5,6 +5,11 @@ artifacts
build
dist
README.md
contracts/v2-vault-and-gas/libraries/EtherSend.sol
coverage
coverage.json
coverage.json
diffs
contracts/v2-vault-and-gas
contracts/v3-relayer-registry
contracts/v4-patch/TornadoStakingRewards.sol
contracts/v4-patch/TornadoStakingRewards.sol

View File

@ -8,8 +8,7 @@
{
"files": "*.sol",
"options": {
"singleQuote": false,
"printWidth": 130
"singleQuote": false
}
}
]

View File

@ -2,4 +2,10 @@ module.exports = {
governance: '0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce',
TORN: '0x77777FeDdddFfC19Ff86DB637967013e6C6A116C',
tornWhale: '0xF977814e90dA44bFA03b6295A0616a897441aceC',
ens: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
feeManager: '0x5f6c97C6AD7bdd0AE7E0Dd4ca33A4ED3fDabD4D7',
staking: '0x2FC93484614a34f26F7970CBB94615bA109BB4bf',
registry: '0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2',
compensations: '0xFA4C1f3f7D5dd7c12a9Adb82Cd7dDA542E3d59ef',
vault: '0x2F50508a8a3D323B91336FA3eA6ae50E55f32185',
}

View File

@ -38,7 +38,10 @@ contract GovernancePatchUpgrade is GovernanceStakingUpgrade {
proposalCodehash := extcodehash(target)
}
require(proposalCodehash == proposalCodehashes[proposalId], "Governance::propose: metamorphic contracts not allowed");
require(
proposalCodehash == proposalCodehashes[proposalId],
"Governance::propose: metamorphic contracts not allowed"
);
super.execute(proposalId);
}

View File

@ -3,10 +3,8 @@
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
import { LoopbackProxy } from "../v1/LoopbackProxy.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { GovernancePatchUpgrade } from "./GovernancePatchUpgrade.sol";
import { TornadoStakingRewards } from "./TornadoStakingRewards.sol";
@ -16,96 +14,56 @@ interface Proxy {
function upgradeTo(address newImplementation) external;
}
/**
* @notice Contract which should help the proposal deploy the necessary contracts.
*/
contract PatchProposalContractsFactory {
/**
* @notice Create a new TornadoStakingRewards contract.
* @param governance The address of Tornado Cash Goveranance.
* @param torn The torn token address.
* @param registry The address of the relayer registry.
* @return The address of the new staking contract.
*/
function createStakingRewards(
address governance,
address torn,
address registry
) external returns (address) {
return address(new TornadoStakingRewards(governance, torn, registry));
}
/**
* @notice Create a new RelayerRegistry contract.
* @param torn The torn token address.
* @param governance The address of Tornado Cash Goveranance.
* @param ens The ens registrar address.
* @param staking The TornadoStakingRewards contract address.
* @return The address of the new registry contract.
*/
function createRegistryContract(
address torn,
address governance,
address ens,
address staking,
address feeManager
) external returns (address) {
return address(new RelayerRegistry(torn, governance, ens, staking, feeManager));
}
}
/**
* @notice Proposal which should patch governance against the metamorphic contract replacement vulnerability.
*/
contract PatchProposal {
using SafeMath for uint256;
using Address for address;
// Address of the staking proxy
address public constant stakingProxyAddress = 0x2FC93484614a34f26F7970CBB94615bA109BB4bf;
address public constant feeManagerAddress = 0x5f6c97C6AD7bdd0AE7E0Dd4ca33A4ED3fDabD4D7;
address public constant ensAddress = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e;
address public immutable registry = 0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2;
// Address of the registry proxy
address public constant registryProxyAddress = 0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2;
// Address of the gas compensation vault
address public constant gasCompensationVaultAddress = 0xFA4C1f3f7D5dd7c12a9Adb82Cd7dDA542E3d59ef;
// Address of the user vault (not replaced)
address public constant userVaultAddress = 0x2F50508a8a3D323B91336FA3eA6ae50E55f32185;
// Address of the governance proxy
address payable public constant governanceProxyAddress = 0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce;
// Torn token
IERC20 public constant TORN = IERC20(0x77777FeDdddFfC19Ff86DB637967013e6C6A116C);
PatchProposalContractsFactory public immutable patchProposalContractsFactory;
// These are the contracts we deployed
address public immutable deployedStakingContractAddress;
address public immutable deployedRelayerRegistryImplementationAddress;
constructor(address _patchProposalContractsFactory) public {
patchProposalContractsFactory = PatchProposalContractsFactory(_patchProposalContractsFactory);
constructor(address _deployedStakingContractAddress, address _deployedRelayerRegistryImplementationAddress)
public
{
deployedStakingContractAddress = _deployedStakingContractAddress;
deployedRelayerRegistryImplementationAddress = _deployedRelayerRegistryImplementationAddress;
}
/// @notice Function to execute the proposal.
function executeProposal() external {
// address(this) has to be governance
address payable governance = payable(address(this));
// Get the two contracts gov depends on
address gasComp = address(GovernancePatchUpgrade(governance).gasCompensationVault());
address vault = address(GovernancePatchUpgrade(governance).userVault());
// Get the old staking contract
TornadoStakingRewards oldStaking = TornadoStakingRewards(address(GovernancePatchUpgrade(governance).Staking()));
TornadoStakingRewards oldStaking = TornadoStakingRewards(stakingProxyAddress);
// Get the small amount of TORN left
oldStaking.withdrawTorn(TORN.balanceOf(address(oldStaking)));
// And create a new staking contract
TornadoStakingRewards newStaking = TornadoStakingRewards(
patchProposalContractsFactory.createStakingRewards(address(governance), address(TORN), registry)
);
// And a new registry implementation
address newRegistryImplementationAddress = patchProposalContractsFactory.createRegistryContract(
address(TORN),
address(governance),
ensAddress,
address(newStaking),
feeManagerAddress
);
TornadoStakingRewards newStaking = TornadoStakingRewards(deployedStakingContractAddress);
// Upgrade the registry proxy
Proxy(registry).upgradeTo(newRegistryImplementationAddress);
Proxy(registryProxyAddress).upgradeTo(deployedRelayerRegistryImplementationAddress);
// Now upgrade the governance to the latest stuff
LoopbackProxy(payable(governance)).upgradeTo(address(new GovernancePatchUpgrade(address(newStaking), gasComp, vault)));
LoopbackProxy(governanceProxyAddress).upgradeTo(
address(new GovernancePatchUpgrade(address(newStaking), gasCompensationVaultAddress, userVaultAddress))
);
}
}

View File

@ -127,16 +127,22 @@ contract MetamorphicContractFactory {
*/
constructor(bytes memory transientContractInitializationCode) public {
// assign the initialization code for the metamorphic contract.
_metamorphicContractInitializationCode = (hex"5860208158601c335a63aaf10f428752fa158151803b80938091923cf3");
_metamorphicContractInitializationCode = (
hex"5860208158601c335a63aaf10f428752fa158151803b80938091923cf3"
);
// calculate and assign keccak256 hash of metamorphic initialization code.
_metamorphicContractInitializationCodeHash = keccak256(abi.encodePacked(_metamorphicContractInitializationCode));
_metamorphicContractInitializationCodeHash = keccak256(
abi.encodePacked(_metamorphicContractInitializationCode)
);
// store the initialization code for the transient contract.
_transientContractInitializationCode = transientContractInitializationCode;
// calculate and assign keccak256 hash of transient initialization code.
_transientContractInitializationCodeHash = keccak256(abi.encodePacked(_transientContractInitializationCode));
_transientContractInitializationCodeHash = keccak256(
abi.encodePacked(_transientContractInitializationCode)
);
}
/* solhint-disable function-max-lines */
@ -214,7 +220,10 @@ contract MetamorphicContractFactory {
} /* solhint-enable no-inline-assembly */
// ensure that the contracts were successfully deployed.
require(deployedMetamorphicContract == metamorphicContractAddress, "Failed to deploy the new metamorphic contract.");
require(
deployedMetamorphicContract == metamorphicContractAddress,
"Failed to deploy the new metamorphic contract."
);
// initialize the new metamorphic contract if any data or value is provided.
if (data.length > 0 || msg.value > 0) {
@ -281,7 +290,10 @@ contract MetamorphicContractFactory {
} /* solhint-enable no-inline-assembly */
// ensure that the contracts were successfully deployed.
require(deployedMetamorphicContract == metamorphicContractAddress, "Failed to deploy the new metamorphic contract.");
require(
deployedMetamorphicContract == metamorphicContractAddress,
"Failed to deploy the new metamorphic contract."
);
// initialize the new metamorphic contract if any data or value is provided.
if (data.length > 0 || msg.value > 0) {
@ -412,7 +424,11 @@ contract MetamorphicContractFactory {
* @param salt bytes32 The nonce passed into CREATE2 by metamorphic contract.
* @return Address of the corresponding metamorphic contract.
*/
function findMetamorphicContractAddress(bytes32 salt) external view returns (address metamorphicContractAddress) {
function findMetamorphicContractAddress(bytes32 salt)
external
view
returns (address metamorphicContractAddress)
{
// determine the address where the metamorphic contract will be deployed.
metamorphicContractAddress = _getMetamorphicContractAddress(salt);
}
@ -424,7 +440,11 @@ contract MetamorphicContractFactory {
* transient contract.
* @return Address of the corresponding transient contract.
*/
function findTransientContractAddress(bytes32 salt) external view returns (address transientContractAddress) {
function findTransientContractAddress(bytes32 salt)
external
view
returns (address transientContractAddress)
{
// determine the address where the transient contract will be deployed.
transientContractAddress = _getTransientContractAddress(salt);
}
@ -442,14 +462,20 @@ contract MetamorphicContractFactory {
returns (address metamorphicContractAddress)
{
// determine the address of the metamorphic contract.
metamorphicContractAddress = _getMetamorphicContractAddressWithConstructor(_getTransientContractAddress(salt));
metamorphicContractAddress = _getMetamorphicContractAddressWithConstructor(
_getTransientContractAddress(salt)
);
}
/**
* @dev View function for retrieving the initialization code of metamorphic
* contracts for purposes of verification.
*/
function getMetamorphicContractInitializationCode() external view returns (bytes memory metamorphicContractInitializationCode) {
function getMetamorphicContractInitializationCode()
external
view
returns (bytes memory metamorphicContractInitializationCode)
{
return _metamorphicContractInitializationCode;
}
@ -469,7 +495,11 @@ contract MetamorphicContractFactory {
* @dev View function for retrieving the initialization code of transient
* contracts for purposes of verification.
*/
function getTransientContractInitializationCode() external view returns (bytes memory transientContractInitializationCode) {
function getTransientContractInitializationCode()
external
view
returns (bytes memory transientContractInitializationCode)
{
return _transientContractInitializationCode;
}
@ -477,7 +507,11 @@ contract MetamorphicContractFactory {
* @dev View function for retrieving the keccak256 hash of the initialization
* code of transient contracts for purposes of verification.
*/
function getTransientContractInitializationCodeHash() external view returns (bytes32 transientContractInitializationCodeHash) {
function getTransientContractInitializationCodeHash()
external
view
returns (bytes32 transientContractInitializationCodeHash)
{
return _transientContractInitializationCodeHash;
}
@ -532,7 +566,11 @@ contract MetamorphicContractFactory {
* that has been deployed via a transient contract given the address of the
* transient contract.
*/
function _getMetamorphicContractAddressWithConstructor(address transientContractAddress) internal pure returns (address) {
function _getMetamorphicContractAddressWithConstructor(address transientContractAddress)
internal
pure
returns (address)
{
// determine the address of the metamorphic contract.
return
address(
@ -560,7 +598,10 @@ contract MetamorphicContractFactory {
modifier containsCaller(bytes32 salt) {
// prevent contract submissions from being stolen from tx.pool by requiring
// that the first 20 bytes of the submitted salt match msg.sender.
require(address(bytes20(salt)) == msg.sender, "Invalid salt - first 20 bytes of the salt must match calling address.");
require(
address(bytes20(salt)) == msg.sender,
"Invalid salt - first 20 bytes of the salt must match calling address."
);
_;
}
}

View File

@ -16,25 +16,36 @@ const config = require('./config')
module.exports = {
solidity: {
compilers: [
{
version: '0.6.12',
settings: {
optimizer: {
enabled: true,
runs: 1000,
},
},
},
{
version: '0.5.6',
settings: {
optimizer: {
enabled: true,
runs: 1000,
runs: 1_000,
},
},
},
{
version: '0.6.12',
settings: {
optimizer: {
enabled: true,
runs: 1_000_000,
},
},
},
],
overrides: {
'contracts/v4-patch/PatchProposal.sol': {
version: '0.6.12',
settings: {
optimizer: {
enabled: true,
runs: 1,
},
},
},
},
},
networks: {
hardhat: {

View File

@ -17,6 +17,7 @@
"test:f": "yarn prettier:fix && yarn test",
"clean": "yarn prettier:fix && yarn lint",
"compile": "yarn prettier:fix && yarn hardhat compile",
"_compile": "yarn hardhat compile",
"coverage": "yarn hardhat coverage",
"layout": "yarn hardhat check"
},

View File

@ -54,11 +54,16 @@ describe('Gov Exploit Patch Upgrade Tests', () => {
let proposalContractsDeployer
let proposalDeployer
let registryDeployer
let stakingDeployer
let proposerBalanceInitial
let torn
let governance
let metamorphicFactory
let registryImplementation
let staking
let exploit = {
hacker: undefined,
@ -134,7 +139,10 @@ describe('Gov Exploit Patch Upgrade Tests', () => {
initialProposalDeployer = await ethers.getContractFactory('InitialProposal')
maliciousProposalDeployer = await ethers.getContractFactory('MaliciousProposal')
proposalContractsDeployer = await ethers.getContractFactory('PatchProposalContractsFactory')
stakingDeployer = await ethers.getContractFactory('TornadoStakingRewards')
registryDeployer = await ethers.getContractFactory('RelayerRegistry')
proposalDeployer = await ethers.getContractFactory('PatchProposal')
// Metamorphic & Exploit
@ -146,6 +154,16 @@ describe('Gov Exploit Patch Upgrade Tests', () => {
initialProposalImpl = await initialProposalDeployer.deploy()
maliciousProposalImpl = await maliciousProposalDeployer.deploy()
staking = await stakingDeployer.deploy(config.governance, config.TORN, config.registry)
registryImplementation = await registryDeployer.deploy(
config.TORN,
config.governance,
config.ens,
config.staking,
config.feeManager,
)
exploit.address = await metamorphicFactory.findMetamorphicContractAddress(exploit.salt)
// Snapshot
@ -159,16 +177,16 @@ describe('Gov Exploit Patch Upgrade Tests', () => {
snapshotId = await takeSnapshot()
})
it('Should be able to execute the proposal', async () => {
it.only('Should be able to execute the proposal', async () => {
// Load these storage variables for comparison
const oldVaultAddr = await governance.userVault()
const oldGasCompAddr = await governance.gasCompensationVault()
const oldStaking = await governance.Staking()
// Start proposing
// Deploy the proposal
const proposal = await proposalDeployer.deploy((await proposalContractsDeployer.deploy()).address)
const proposal = await proposalDeployer.deploy(staking.address, registryImplementation.address)
// Propose
@ -194,7 +212,9 @@ describe('Gov Exploit Patch Upgrade Tests', () => {
await ethers.provider.send('evm_mine', [])
await governance.execute(proposalId)
const response = await governance.execute(proposalId)
console.log(await response.wait())
const newVaultAddr = await governance.userVault()
const newGasCompAddr = await governance.gasCompensationVault()