Skip to content

Commit

Permalink
fix(ct): make chugsplashregistry proxy's address deterministic
Browse files Browse the repository at this point in the history
  • Loading branch information
sam-goldman committed Nov 22, 2022
1 parent da5cb35 commit 16348b2
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 27 deletions.
7 changes: 7 additions & 0 deletions .changeset/fuzzy-chairs-lick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@chugsplash/contracts': patch
'@chugsplash/core': patch
'@chugsplash/executor': patch
---

Make the ChugSplashRegistry proxy's address deterministic
26 changes: 4 additions & 22 deletions packages/contracts/contracts/ChugSplashBootLoader.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,28 +53,23 @@ contract ChugSplashBootLoader is Initializable {
* @param _executorPaymentPercentage Amount that an executor will earn from completing a bundle,
* denominated as a percentage.
* @param _managerImplementation Address of the ChugSplashManager implementation contract.
* @param _registryProxy Address of the ChugSplashRegistry's proxy.
*/
function initialize(
address _owner,
uint256 _executorBondAmount,
uint256 _executionLockTime,
uint256 _ownerBondAmount,
uint256 _executorPaymentPercentage,
address _managerImplementation
address _managerImplementation,
address _registryProxy
) external initializer {
// Deploy the ProxyUpdater.
proxyUpdater = new ProxyUpdater{ salt: bytes32(0) }();

// Get the address of the ChugSplashRegistry's proxy that *will* be deployed.
address registryProxyAddress = Create2.compute(
address(this),
bytes32(0),
abi.encodePacked(type(Proxy).creationCode, abi.encode(address(this)))
);

// Deploy the root ChugSplashManager's proxy.
rootManagerProxy = new ChugSplashManagerProxy{ salt: bytes32(0) }(
ChugSplashRegistry(registryProxyAddress),
ChugSplashRegistry(_registryProxy),
address(this)
);
// Initialize the proxy. Note that we initialize it in a different call from the deployment
Expand All @@ -96,18 +91,5 @@ contract ChugSplashBootLoader is Initializable {
_executorPaymentPercentage,
_managerImplementation
);

// Deploy the ChugSplashRegistry's proxy.
registryProxy = new Proxy{ salt: bytes32(0) }(
// The owner must initially be this contract so that we can set the proxy's
// implementation contract.
address(this)
);

// Set the proxy's implementation contract.
registryProxy.upgradeTo(address(registryImplementation));

// Transfer ownership of the ChugSplashRegistry's proxy to the owner.
registryProxy.changeAdmin(_owner);
}
}
19 changes: 19 additions & 0 deletions packages/contracts/contracts/DeterministicProxyOwner.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { Proxy } from "./libraries/Proxy.sol";

/**
* @title DeterministicProxyOwner
*/
contract DeterministicProxyOwner is Initializable {
function initializeProxy(
address payable _proxy,
address _implementation,
address _newOwner
) external initializer {
Proxy(_proxy).upgradeTo(_implementation);
Proxy(_proxy).changeAdmin(_newOwner);
}
}
16 changes: 14 additions & 2 deletions packages/contracts/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
ChugSplashManagerProxyArtifact,
ChugSplashManagerABI,
ProxyABI,
DeterministicProxyOwnerArtifact,
} from './ifaces'

const owner = '0x1A3DAA6F487A480c1aD312b90FD0244871940b66'
Expand All @@ -22,6 +23,7 @@ const chugsplashManagerSourceName = ChugSplashManagerArtifact.sourceName
const proxyUpdaterSourceName = ProxyUpdaterArtifact.sourceName
const defaultAdapterSourceName = DefaultAdapterArtifact.sourceName
const chugsplashRegistyProxySourceName = ProxyArtifact.sourceName
const deterministicOwnerSourceName = DeterministicProxyOwnerArtifact.sourceName

const [chugsplashManagerConstructorFragment] = ChugSplashManagerABI.filter(
(fragment) => fragment.type === 'constructor'
Expand Down Expand Up @@ -51,15 +53,24 @@ export const PROXY_UPDATER_ADDRESS = ethers.utils.getCreate2Address(
ethers.utils.solidityKeccak256(['bytes'], [ProxyUpdaterArtifact.bytecode])
)

export const DETERMINISTIC_PROXY_OWNER_ADDRESS = ethers.utils.getCreate2Address(
DETERMINISTIC_DEPLOYMENT_PROXY_ADDRESS,
ethers.constants.HashZero,
ethers.utils.solidityKeccak256(
['bytes'],
[DeterministicProxyOwnerArtifact.bytecode]
)
)

const [registryProxyConstructorFragment] = ProxyABI.filter(
(fragment) => fragment.type === 'constructor'
)
const registryProxyConstructorArgTypes =
registryProxyConstructorFragment.inputs.map((input) => input.type)
const registryProxyConstructorArgValues = [CHUGSPLASH_BOOTLOADER_ADDRESS]
const registryProxyConstructorArgValues = [DETERMINISTIC_PROXY_OWNER_ADDRESS]

export const CHUGSPLASH_REGISTRY_PROXY_ADDRESS = ethers.utils.getCreate2Address(
CHUGSPLASH_BOOTLOADER_ADDRESS,
DETERMINISTIC_DEPLOYMENT_PROXY_ADDRESS,
ethers.constants.HashZero,
ethers.utils.solidityKeccak256(
['bytes', 'bytes'],
Expand Down Expand Up @@ -163,3 +174,4 @@ CHUGSPLASH_CONSTRUCTOR_ARGS[proxyUpdaterSourceName] = []
CHUGSPLASH_CONSTRUCTOR_ARGS[defaultAdapterSourceName] = []
CHUGSPLASH_CONSTRUCTOR_ARGS[chugsplashRegistyProxySourceName] =
registryProxyConstructorArgValues
CHUGSPLASH_CONSTRUCTOR_ARGS[deterministicOwnerSourceName] = []
4 changes: 3 additions & 1 deletion packages/contracts/src/ifaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ export const ChugSplashManagerArtifact = require('../artifacts/contracts/ChugSpl
export const ProxyUpdaterArtifact = require('../artifacts/contracts/ProxyUpdater.sol/ProxyUpdater.json')
export const DefaultAdapterArtifact = require('../artifacts/contracts/adapters/DefaultAdapter.sol/DefaultAdapter.json')
export const ProxyArtifact = require('../artifacts/contracts/libraries/Proxy.sol/Proxy.json')
export const DeterministicProxyOwnerArtifact = require('../artifacts/contracts/DeterministicProxyOwner.sol/DeterministicProxyOwner.json')

export const buildInfo = require('../artifacts/build-info/a59148ffea63beedd50ee5352d54a7bc.json')
export const buildInfo = require('../artifacts/build-info/3fa557b7889abe264f17b7551a4f2eed.json')

export const ChugSplashRegistryABI = ChugSplashRegistryArtifact.abi
export const ChugSplashBootLoaderABI = ChugSplashBootLoaderArtifact.abi
Expand All @@ -16,3 +17,4 @@ export const ChugSplashManagerABI = ChugSplashManagerArtifact.abi
export const ProxyUpdaterABI = ProxyUpdaterArtifact.abi
export const DefaultAdapterABI = DefaultAdapterArtifact.abi
export const ProxyABI = ProxyArtifact.abi
export const DeterministicProxyOwnerABI = DeterministicProxyOwnerArtifact.abi
72 changes: 70 additions & 2 deletions packages/core/src/languages/solidity/predeploys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,16 @@ import {
ChugSplashBootLoaderArtifact,
DEFAULT_ADAPTER_ADDRESS,
CHUGSPLASH_CONSTRUCTOR_ARGS,
CHUGSPLASH_REGISTRY_PROXY_ADDRESS,
ProxyArtifact,
ProxyABI,
DeterministicProxyOwnerABI,
DeterministicProxyOwnerArtifact,
DETERMINISTIC_PROXY_OWNER_ADDRESS,
CHUGSPLASH_REGISTRY_ADDRESS,
} from '@chugsplash/contracts'

import { getChugSplashRegistry } from '../../utils'
import { getChugSplashRegistry, getProxyOwner } from '../../utils'

export const deployChugSplashPredeploys = async (
provider: ethers.providers.JsonRpcProvider
Expand Down Expand Up @@ -63,7 +70,8 @@ export const deployChugSplashPredeploys = async (
EXECUTION_LOCK_TIME,
OWNER_BOND_AMOUNT,
EXECUTOR_PAYMENT_PERCENTAGE,
ChugSplashManager.address
ChugSplashManager.address,
CHUGSPLASH_REGISTRY_PROXY_ADDRESS
)
).wait()
} catch (err) {
Expand All @@ -76,6 +84,66 @@ export const deployChugSplashPredeploys = async (
}
}

// Deploy the ChugSplashRegistry's proxy.
const ChugSplashRegistryProxy = await doDeterministicDeploy(provider, {
signer: deployer,
contract: {
abi: ProxyABI,
bytecode: ProxyArtifact.bytecode,
},
salt: ethers.constants.HashZero,
args: CHUGSPLASH_CONSTRUCTOR_ARGS[ProxyArtifact.sourceName],
})

// Make sure the addresses match, just in case.
assert(
ChugSplashRegistryProxy.address === CHUGSPLASH_REGISTRY_PROXY_ADDRESS,
'ChugSplashRegistry proxy address mismatch'
)

// Deploy the DeterministicProxyOwner, which temporarily owns the ChugSplashRegistry proxy.
const DeterministicProxyOwner = await doDeterministicDeploy(provider, {
signer: deployer,
contract: {
abi: DeterministicProxyOwnerABI,
bytecode: DeterministicProxyOwnerArtifact.bytecode,
},
salt: ethers.constants.HashZero,
args: CHUGSPLASH_CONSTRUCTOR_ARGS[
DeterministicProxyOwnerArtifact.sourceName
],
})

// Make sure the addresses match, just in case.
assert(
DeterministicProxyOwner.address === DETERMINISTIC_PROXY_OWNER_ADDRESS,
'DeterministicProxyOwner address mismatch'
)

// Check if the ChugSplashRegistry proxy's owner is the DeterministicProxyOwner. This will only be true
// when the ChugSplashRegistry's proxy is initially deployed.
if (
(await getProxyOwner(ChugSplashRegistryProxy)) ===
DETERMINISTIC_PROXY_OWNER_ADDRESS
) {
// Initialize the ChugSplashRegistry's proxy through the DeterministicProxyOwner. This
// transaction sets the ChugSplasRegistry proxy's implementation and transfers ownership of the
// proxy to the specified owner.
await (
await DeterministicProxyOwner.initializeProxy(
ChugSplashRegistryProxy.address,
CHUGSPLASH_REGISTRY_ADDRESS,
owner
)
).wait()

// Make sure ownership of the ChugSplashRegistry's proxy has been transferred.
assert(
(await getProxyOwner(ChugSplashRegistryProxy)) === owner,
'ChugSplashRegistry proxy has incorrect owner'
)
}

// Deploy the DefaultAdapter.
const DefaultAdapter = await doDeterministicDeploy(provider, {
signer: deployer,
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,3 +225,9 @@ export const claimExecutorPayment = async (
await (await ChugSplashManager.claimExecutorPayment()).wait()
}
}

export const getProxyOwner = async (Proxy: Contract) => {
// Use the latest `AdminChanged` event on the Proxy to get the most recent owner.
const { args } = (await Proxy.queryFilter('AdminChanged')).at(-1)
return args.newAdmin
}
6 changes: 6 additions & 0 deletions packages/executor/src/utils/initialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
CHUGSPLASH_MANAGER_ADDRESS,
CHUGSPLASH_REGISTRY_ADDRESS,
DEFAULT_ADAPTER_ADDRESS,
DeterministicProxyOwnerArtifact,
DETERMINISTIC_PROXY_OWNER_ADDRESS,
buildInfo,
} from '@chugsplash/contracts'

Expand Down Expand Up @@ -56,6 +58,10 @@ export const initializeChugSplashPredeploys = async (
address: CHUGSPLASH_REGISTRY_ADDRESS,
},
{ artifact: DefaultAdapterArtifact, address: DEFAULT_ADAPTER_ADDRESS },
{
artifact: DeterministicProxyOwnerArtifact,
address: DETERMINISTIC_PROXY_OWNER_ADDRESS,
},
]

for (const { artifact, address } of contracts) {
Expand Down

0 comments on commit 16348b2

Please sign in to comment.