Skip to content

Commit

Permalink
Merge pull request sphinx-labs#479 from chugsplash/pate/chu-49-add-su…
Browse files Browse the repository at this point in the history
…pport-for-uups-proxies

feat(ct): add support for uups proxies
  • Loading branch information
RPate97 authored Feb 9, 2023
2 parents 8b64e6c + fa3f420 commit cab3f56
Show file tree
Hide file tree
Showing 44 changed files with 1,249 additions and 369 deletions.
8 changes: 8 additions & 0 deletions .changeset/short-coins-crash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@chugsplash/contracts': minor
'@chugsplash/executor': minor
'@chugsplash/plugins': minor
'@chugsplash/core': minor
---

Add support for UUPS proxies
20 changes: 0 additions & 20 deletions packages/contracts/contracts/ChugSplashBootLoader.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ pragma solidity ^0.8.9;
import { ChugSplashRegistry } from "./ChugSplashRegistry.sol";
import { ChugSplashManager } from "./ChugSplashManager.sol";
import { ChugSplashManagerProxy } from "./ChugSplashManagerProxy.sol";
import { ProxyUpdater } from "./ProxyUpdater.sol";
import { Reverter } from "./Reverter.sol";
import { Create2 } from "./libraries/Create2.sol";
import { Proxy } from "./libraries/Proxy.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
Expand All @@ -20,16 +18,6 @@ contract ChugSplashBootLoader is Initializable {
address public constant DETERMINISTIC_DEPLOYMENT_PROXY_ADDRESS =
0x4e59b44847b379578588920cA78FbF26c0B4956C;

/**
* @notice The ProxyUpdater.
*/
ProxyUpdater public proxyUpdater;

/**
* @notice The Reverter.
*/
Reverter public reverter;

/**
* @notice Address of the ChugSplashRegistry implementation contract.
*/
Expand Down Expand Up @@ -66,12 +54,6 @@ contract ChugSplashBootLoader is Initializable {
address _registryProxy,
bytes32 _salt
) external initializer {
// Deploy the ProxyUpdater.
proxyUpdater = new ProxyUpdater{ salt: _salt }();

// Deploy the Reverter.
reverter = new Reverter{ salt: _salt }();

// Deploy the root ChugSplashManager's proxy.
rootManagerProxy = new ChugSplashManagerProxy{ salt: _salt }(
ChugSplashRegistry(_registryProxy),
Expand All @@ -89,8 +71,6 @@ contract ChugSplashBootLoader is Initializable {

// Deploy and initialize the ChugSplashRegistry's implementation contract.
registryImplementation = new ChugSplashRegistry{ salt: _salt }(
address(proxyUpdater),
address(reverter),
_ownerBondAmount,
_executionLockTime,
_executorPaymentPercentage,
Expand Down
109 changes: 19 additions & 90 deletions packages/contracts/contracts/ChugSplashManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import {
} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { Proxy } from "./libraries/Proxy.sol";
import { ChugSplashRegistry } from "./ChugSplashRegistry.sol";
import { IProxyAdapter } from "./IProxyAdapter.sol";
import { ProxyUpdater } from "./ProxyUpdater.sol";
import { IProxyAdapter } from "./interfaces/IProxyAdapter.sol";
import { IProxyUpdater } from "./interfaces/IProxyUpdater.sol";
import { Create2 } from "./libraries/Create2.sol";
import { MerkleTree } from "./libraries/MerkleTree.sol";
import {
Expand Down Expand Up @@ -194,11 +194,6 @@ contract ChugSplashManager is OwnableUpgradeable, ReentrancyGuardUpgradeable {
*/
ChugSplashRegistry public immutable registry;

/**
* @notice Address of the ProxyUpdater.
*/
address public immutable proxyUpdater;

/**
* @notice Amount that must be deposited in this contract in order to execute a bundle. The
* project owner can withdraw this amount whenever a bundle is not active. This bond
Expand Down Expand Up @@ -287,7 +282,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 _proxyUpdater Address of the ProxyUpdater.
* @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 @@ -299,13 +293,11 @@ contract ChugSplashManager is OwnableUpgradeable, ReentrancyGuardUpgradeable {
ChugSplashRegistry _registry,
string memory _name,
address _owner,
address _proxyUpdater,
uint256 _executionLockTime,
uint256 _ownerBondAmount,
uint256 _executorPaymentPercentage
) {
registry = _registry;
proxyUpdater = _proxyUpdater;
executionLockTime = _executionLockTime;
ownerBondAmount = _ownerBondAmount;
executorPaymentPercentage = _executorPaymentPercentage;
Expand Down Expand Up @@ -509,8 +501,10 @@ 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 @@ -551,14 +545,14 @@ contract ChugSplashManager is OwnableUpgradeable, ReentrancyGuardUpgradeable {
proxy = proxies[_action.referenceName];
}

if (_getProxyImplementation(proxy, adapter) != registry.reverter()) {
// Set the proxy's implementation to be the Reverter. This ensures that end-users can't
// accidentally interact with a proxy that is in the process of being upgraded. Note
// that we use a Reverter contract instead of address(0) to support OpenZeppelin's
// `TransparentUpgradeableProxy`, whose `upgradeTo` call reverts if the implementation
// is not a contract.
_upgradeProxyTo(proxy, adapter, registry.reverter());
}
// Set the proxy's implementation to be the Updater. 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))
);
require(success, "ChugSplashManager: delegatecall to set storage failed");

// Mark the action as executed and update the total number of executed actions.
bundle.actionsExecuted++;
Expand Down Expand Up @@ -674,7 +668,10 @@ contract ChugSplashManager is OwnableUpgradeable, ReentrancyGuardUpgradeable {
}

// Upgrade the proxy's implementation contract.
_upgradeProxyTo(proxy, adapter, implementation);
(bool success, ) = adapter.delegatecall(
abi.encodeCall(IProxyAdapter.completeExecution, (proxy, implementation))
);
require(success, "ChugSplashManager: delegatecall to complete execution failed");

emit ChugSplashActionExecuted(activeBundleId, proxy, msg.sender, actionIndex);
registry.announceWithData("ChugSplashActionExecuted", abi.encodePacked(proxy));
Expand Down Expand Up @@ -935,79 +932,11 @@ contract ChugSplashManager is OwnableUpgradeable, ReentrancyGuardUpgradeable {
bytes32 _key,
bytes32 _value
) internal {
// Delegatecall the adapter to upgrade the proxy's implementation to be the ProxyUpdater,
// and call `setStorage` on the proxy.
_upgradeProxyToAndCall(
_proxy,
_adapter,
proxyUpdater,
abi.encodeCall(ProxyUpdater.setStorage, (_key, _value))
);

// Delegatecall the adapter to set the proxy's implementation back to the Reverter.
_upgradeProxyTo(_proxy, _adapter, registry.reverter());
}

/**
* @notice Delegatecalls an adapter to get the address of the proxy's implementation contract.
*
* @param _proxy Address of the proxy.
* @param _adapter Address of the adapter to use for the proxy.
*/
function _getProxyImplementation(
address payable _proxy,
address _adapter
) internal returns (address) {
(bool success, bytes memory implementationBytes) = _adapter.delegatecall(
abi.encodeCall(IProxyAdapter.getProxyImplementation, (_proxy))
);
require(success, "ChugSplashManager: delegatecall to get proxy implementation failed");

// Convert the implementation's type from bytes to address.
address implementation;
assembly {
implementation := mload(add(implementationBytes, 32))
}
return implementation;
}

/**
* @notice Delegatecalls an adapter to upgrade a proxy's implementation contract.
*
* @param _proxy Address of the proxy to upgrade.
* @param _adapter Address of the adapter to use for the proxy.
* @param _implementation Address to set as the proxy's new implementation contract.
*/
function _upgradeProxyTo(
address payable _proxy,
address _adapter,
address _implementation
) internal {
(bool success, ) = _adapter.delegatecall(
abi.encodeCall(IProxyAdapter.upgradeProxyTo, (_proxy, _implementation))
);
require(success, "ChugSplashManager: delegatecall to upgrade proxy failed");
}

/**
* @notice Upgrade a proxy's implementation contract and delegatecall the proxy with encoded
* function data via an adapter.
*
* @param _proxy Address of the proxy to upgrade.
* @param _adapter Address of the adapter to use for the proxy.
* @param _implementation Address to set as the proxy's new implementation contract.
* @param _data Calldata to delegatecall the new implementation with.
*/
function _upgradeProxyToAndCall(
address payable _proxy,
address _adapter,
address _implementation,
bytes memory _data
) internal {
// Delegatecall the adapter to call `setStorage` on the proxy.
(bool success, ) = _adapter.delegatecall(
abi.encodeCall(IProxyAdapter.upgradeProxyToAndCall, (_proxy, _implementation, _data))
abi.encodeCall(IProxyAdapter.setStorage, (_proxy, _key, _value))
);
require(success, "ChugSplashManager: delegatecall to upgrade proxy with data failed");
require(success, "ChugSplashManager: delegatecall to set storage failed");
}

/**
Expand Down
31 changes: 13 additions & 18 deletions packages/contracts/contracts/ChugSplashRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -108,19 +108,14 @@ contract ChugSplashRegistry is Initializable, OwnableUpgradeable, IChugSplashReg
mapping(bytes32 => address) public adapters;

/**
* @notice Addresses that can execute bundles.
*/
mapping(address => bool) public executors;

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

/**
* @notice Address of the Reverter.
* @notice Addresses that can execute bundles.
*/
address public immutable reverter;
mapping(address => bool) public executors;

/**
* @notice Amount that must be deposited in the ChugSplashManager in order to execute a bundle.
Expand All @@ -144,8 +139,6 @@ contract ChugSplashRegistry is Initializable, OwnableUpgradeable, IChugSplashReg
address public immutable managerImplementation;

/**
* @param _proxyUpdater Address of the ProxyUpdater.
* @param _reverter Address of the Reverter.
* @param _ownerBondAmount Amount that must be deposited in the ChugSplashManager in
* order to execute a bundle.
* @param _executionLockTime Amount of time for an executor to completely execute a
Expand All @@ -155,15 +148,11 @@ contract ChugSplashRegistry is Initializable, OwnableUpgradeable, IChugSplashReg
* @param _managerImplementation Address of the ChugSplashManager implementation contract.
*/
constructor(
address _proxyUpdater,
address _reverter,
uint256 _ownerBondAmount,
uint256 _executionLockTime,
uint256 _executorPaymentPercentage,
address _managerImplementation
) {
proxyUpdater = _proxyUpdater;
reverter = _reverter;
ownerBondAmount = _ownerBondAmount;
executionLockTime = _executionLockTime;
executorPaymentPercentage = _executorPaymentPercentage;
Expand Down Expand Up @@ -248,18 +237,24 @@ contract ChugSplashRegistry is Initializable, OwnableUpgradeable, IChugSplashReg
}

/**
* @notice Adds a new proxy type with a corresponding adapter, which can be used to upgrade a
* custom proxy.
* @notice Adds a new proxy type with a corresponding adapter and updater, which
* can be used to upgrade a custom proxy.
*
* @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) external {
function addProxyType(bytes32 _proxyType, address _adapter, address _updater) 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
43 changes: 0 additions & 43 deletions packages/contracts/contracts/IProxyAdapter.sol

This file was deleted.

24 changes: 0 additions & 24 deletions packages/contracts/contracts/ProxyUpdater.sol

This file was deleted.

12 changes: 0 additions & 12 deletions packages/contracts/contracts/Reverter.sol

This file was deleted.

Loading

0 comments on commit cab3f56

Please sign in to comment.