Skip to content

Commit

Permalink
feat: add meta upgrades to root chugsplashmanager
Browse files Browse the repository at this point in the history
  • Loading branch information
sam-goldman committed Feb 22, 2023
1 parent 10494fd commit 35c7a63
Show file tree
Hide file tree
Showing 34 changed files with 771 additions and 796 deletions.
7 changes: 7 additions & 0 deletions .changeset/slow-scissors-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@chugsplash/contracts': patch
'@chugsplash/plugins': patch
'@chugsplash/core': patch
---

Add meta upgrades for root ChugSplashManager
7 changes: 4 additions & 3 deletions packages/contracts/contracts/ChugSplashBootLoader.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ contract ChugSplashBootLoader is Initializable {
_managerImplementation,
abi.encodeCall(ChugSplashManager.initialize, ("Root Manager", _owner))
);
// Transfer ownership of the ChugSplashManagerProxy to the specified owner.
rootManagerProxy.changeAdmin(_owner);
// Change the admin of the root ChugSplashManagerProxy to itself, since it will be upgrading
// itself during meta-upgradeability (i.e. ChugSplash upgrading itself).
rootManagerProxy.changeAdmin(address(rootManagerProxy));

// Deploy and initialize the ChugSplashRegistry's implementation contract.
registryImplementation = new ChugSplashRegistry{ salt: _salt }(
Expand All @@ -77,6 +78,6 @@ contract ChugSplashBootLoader is Initializable {
_managerImplementation
);

registryImplementation.initialize(_owner, new address[](0));
registryImplementation.initialize(_owner, address(rootManagerProxy), new address[](0));
}
}
15 changes: 3 additions & 12 deletions packages/contracts/contracts/ChugSplashManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,6 @@ contract ChugSplashManager is OwnableUpgradeable, ReentrancyGuardUpgradeable {

/**
* @param _registry Address of the ChugSplashRegistry.
* @param _name Name of the project this contract is managing.
* @param _owner Address of the project owner.
* @param _executionLockTime Amount of time for an executor to completely execute a
* bundle after claiming it.
* @param _ownerBondAmount Amount that must be deposited in this contract in order to
Expand All @@ -320,8 +318,6 @@ contract ChugSplashManager is OwnableUpgradeable, ReentrancyGuardUpgradeable {
*/
constructor(
ChugSplashRegistry _registry,
string memory _name,
address _owner,
uint256 _executionLockTime,
uint256 _ownerBondAmount,
uint256 _executorPaymentPercentage
Expand All @@ -330,8 +326,6 @@ contract ChugSplashManager is OwnableUpgradeable, ReentrancyGuardUpgradeable {
executionLockTime = _executionLockTime;
ownerBondAmount = _ownerBondAmount;
executorPaymentPercentage = _executorPaymentPercentage;

initialize(_name, _owner);
}

/**
Expand Down Expand Up @@ -512,7 +506,6 @@ contract ChugSplashManager is OwnableUpgradeable, ReentrancyGuardUpgradeable {
uint256 initialGasLeft = gasleft();

ChugSplashBundleState storage bundle = _bundles[activeBundleId];

require(
bundle.executions[_actionIndex] == false,
"ChugSplashManager: action has already been executed"
Expand All @@ -532,10 +525,8 @@ contract ChugSplashManager is OwnableUpgradeable, ReentrancyGuardUpgradeable {
// Get the proxy type and adapter for this reference name.
bytes32 proxyType = proxyTypes[_action.referenceName];
address adapter = registry.adapters(proxyType);
address updater = registry.updaters(proxyType);

require(adapter != address(0), "ChugSplashManager: proxy type has no adapter");
require(updater != address(0), "ChugSplashManager: proxy type has no updater");

// Get the proxy to use for this reference name. The proxy can either be the default proxy
// used by ChugSplash or a non-standard proxy that has previously been set by the project
Expand Down Expand Up @@ -576,14 +567,14 @@ contract ChugSplashManager is OwnableUpgradeable, ReentrancyGuardUpgradeable {
proxy = proxies[_action.referenceName];
}

// Set the proxy's implementation to be the Updater. Updaters ensure that only the
// Set the proxy's implementation to be a ProxyUpdater. Updaters ensure that only the
// ChugSplashManager can interact with a proxy that is in the process of being updated. Note
// that we use the Updater contract to provide a generic interface for updating a variety of
// proxy types.
(bool success, ) = adapter.delegatecall(
abi.encodeCall(IProxyAdapter.initiateExecution, (proxy, updater))
abi.encodeCall(IProxyAdapter.initiateExecution, (proxy))
);
require(success, "ChugSplashManager: delegatecall to set storage failed");
require(success, "ChugSplashManager: failed to set implementation to an updater");

// Mark the action as executed and update the total number of executed actions.
bundle.actionsExecuted++;
Expand Down
33 changes: 16 additions & 17 deletions packages/contracts/contracts/ChugSplashRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,6 @@ contract ChugSplashRegistry is Initializable, OwnableUpgradeable, IChugSplashReg
*/
mapping(bytes32 => address) public adapters;

/**
* @notice Mapping of proxy types to updaters.
*/
mapping(bytes32 => address) public updaters;

/**
* @notice Addresses that can execute bundles.
*/
Expand Down Expand Up @@ -160,13 +155,23 @@ contract ChugSplashRegistry is Initializable, OwnableUpgradeable, IChugSplashReg
}

/**
* @param _owner Initial owner of this contract.
* @param _executors Array of executors to add.
* @param _owner Initial owner of this contract.
* @param _rootManagerProxy Address of the root ChugSplashManagerProxy.
* @param _executors Array of executors to add.
*/
function initialize(address _owner, address[] memory _executors) public initializer {
function initialize(
address _owner,
address _rootManagerProxy,
address[] memory _executors
) public initializer {
__Ownable_init();
_transferOwnership(_owner);

// Add the root ChugSplashManager to projects and managers mappings. Will be removed once
// ChugSplash is non-upgradeable.
projects["ChugSplash"] = ChugSplashManager(payable(_rootManagerProxy));
managers[ChugSplashManager(payable(_rootManagerProxy))] = true;

for (uint i = 0; i < _executors.length; i++) {
executors[_executors[i]] = true;
}
Expand Down Expand Up @@ -237,24 +242,18 @@ contract ChugSplashRegistry is Initializable, OwnableUpgradeable, IChugSplashReg
}

/**
* @notice Adds a new proxy type with a corresponding adapter and updater, which
* can be used to upgrade a custom proxy.
* @notice Adds a new proxy type with a corresponding adapter.
*
* @param _proxyType Hash representing the proxy type
* @param _adapter Address of the adapter for this proxy type.
* @param _updater Address of the updater for this proxy type.
*/
function addProxyType(bytes32 _proxyType, address _adapter, address _updater) external {
function addProxyType(bytes32 _proxyType, address _adapter) external {
require(
adapters[_proxyType] == address(0),
"ChugSplashRegistry: proxy type has an existing adapter"
);
require(
updaters[_proxyType] == address(0),
"ChugSplashRegistry: proxy type has an existing updater"
);

adapters[_proxyType] = _adapter;
updaters[_proxyType] = _updater;

emit ProxyTypeAdded(_proxyType, _adapter);
}
Expand Down
14 changes: 9 additions & 5 deletions packages/contracts/contracts/adapters/DefaultAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@ import { Proxy } from "../libraries/Proxy.sol";

/**
* @title DefaultAdapter
* @notice Adapter for an OpenZeppelin Transparent Upgradeable proxy. This is the adapter used by
* default proxies in the ChugSplash system. To learn more about the transparent proxy
* pattern, see: https://docs.openzeppelin.com/contracts/4.x/api/proxy#transparent_proxy
* @notice Adapter for the default EIP-1967 proxy used by ChugSplash.
*/
contract DefaultAdapter is IProxyAdapter {
address public immutable proxyUpdater;

constructor(address _proxyUpdater) {
proxyUpdater = _proxyUpdater;
}

/**
* @inheritdoc IProxyAdapter
*/
function initiateExecution(address payable _proxy, address _implementation) external {
Proxy(_proxy).upgradeTo(_implementation);
function initiateExecution(address payable _proxy) external {
Proxy(_proxy).upgradeTo(proxyUpdater);
}

/**
Expand Down
15 changes: 9 additions & 6 deletions packages/contracts/contracts/adapters/OZTransparentAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ import { Proxy } from "../libraries/Proxy.sol";
* pattern, see: https://docs.openzeppelin.com/contracts/4.x/api/proxy#transparent_proxy
*/
contract OZTransparentAdapter is IProxyAdapter {
address public immutable proxyUpdater;

constructor(address _proxyUpdater) {
proxyUpdater = _proxyUpdater;
}

/**
* @inheritdoc IProxyAdapter
*/
function initiateExecution(address payable _proxy, address _implementation) external {
Proxy(_proxy).upgradeTo(_implementation);
function initiateExecution(address payable _proxy) external {
Proxy(_proxy).upgradeTo(proxyUpdater);
}

/**
Expand All @@ -41,10 +47,7 @@ contract OZTransparentAdapter is IProxyAdapter {
(bool success, ) = _proxy.call(
abi.encodeCall(
Proxy.upgradeToAndCall,
(
Proxy(_proxy).implementation(),
abi.encodeCall(IProxyUpdater.setStorage, (_key, _offset, _segment))
)
(proxyUpdater, abi.encodeCall(IProxyUpdater.setStorage, (_key, _offset, _segment)))
)
);
require(success, "OZTransparentAdapter: call to set storage failed");
Expand Down
10 changes: 8 additions & 2 deletions packages/contracts/contracts/adapters/OZUUPSAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ import { Proxy } from "../libraries/Proxy.sol";
* https://docs.openzeppelin.com/contracts/4.x/api/proxy#transparent-vs-uups
*/
contract OZUUPSAdapter is IProxyAdapter {
address public immutable proxyUpdater;

constructor(address _proxyUpdater) {
proxyUpdater = _proxyUpdater;
}

/**
* @inheritdoc IProxyAdapter
*/
function initiateExecution(address payable _proxy, address _implementation) external {
OZUUPSUpdater(_proxy).upgradeTo(_implementation);
function initiateExecution(address payable _proxy) external {
OZUUPSUpdater(_proxy).upgradeTo(proxyUpdater);
OZUUPSUpdater(_proxy).initiate();
}

Expand Down
51 changes: 51 additions & 0 deletions packages/contracts/contracts/adapters/ProxyAdapter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import { IProxyAdapter } from "../interfaces/IProxyAdapter.sol";
import { IProxyUpdater } from "../interfaces/IProxyUpdater.sol";
import { Proxy } from "../libraries/Proxy.sol";

/**
* @title DefaultAdapter
* @notice Adapter for the default EIP-1967 proxy used by ChugSplash.
*/
contract DefaultAdapter is IProxyAdapter {
address public immutable proxyUpdater;

constructor(address _proxyUpdater) {
proxyUpdater = _proxyUpdater;
}

/**
* @inheritdoc IProxyAdapter
*/
function initiateExecution(address payable _proxy) external {
Proxy(_proxy).upgradeTo(proxyUpdater);
}

/**
* @inheritdoc IProxyAdapter
*/
function completeExecution(address payable _proxy, address _implementation) external {
Proxy(_proxy).upgradeTo(_implementation);
}

/**
* @inheritdoc IProxyAdapter
*/
function setStorage(
address payable _proxy,
bytes32 _key,
uint8 _offset,
bytes memory _segment
) external {
IProxyUpdater(_proxy).setStorage(_key, _offset, _segment);
}

/**
* @inheritdoc IProxyAdapter
*/
function changeProxyAdmin(address payable _proxy, address _newAdmin) external {
Proxy(_proxy).changeAdmin(_newAdmin);
}
}
7 changes: 3 additions & 4 deletions packages/contracts/contracts/interfaces/IProxyAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ pragma solidity ^0.8.9;
*/
interface IProxyAdapter {
/**
* @notice Upgrade the implementation of the proxy.
* @notice Update the proxy to be in a state where it can be upgraded by ChugSplash.
*
* @param _proxy Address of the proxy.
* @param _implementation Address of the updater implementation.
* @param _proxy Address of the proxy.
*/
function initiateExecution(address payable _proxy, address _implementation) external;
function initiateExecution(address payable _proxy) external;

/**
* @notice Upgrade the implementation of the proxy.
Expand Down
5 changes: 5 additions & 0 deletions packages/contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ const config: HardhatUserConfig = {
enabled: true,
runs: 200,
},
outputSelection: {
'*': {
'*': ['storageLayout'],
},
},
},
},
}
Expand Down
Loading

0 comments on commit 35c7a63

Please sign in to comment.