diff --git a/.changeset/mean-dragons-drive.md b/.changeset/mean-dragons-drive.md new file mode 100644 index 000000000..be6a11dc8 --- /dev/null +++ b/.changeset/mean-dragons-drive.md @@ -0,0 +1,5 @@ +--- +'@chugsplash/contracts': minor +--- + +Adds executor selection to Manager diff --git a/package.json b/package.json index c57bcac66..7ff9f1c7f 100644 --- a/package.json +++ b/package.json @@ -20,13 +20,11 @@ "lint:fix": "yarn workspaces run lint:fix" }, "devDependencies": { - "@changesets/cli": "^2.16.0", - "@types/node": "^18.0.0", - "ts-node": "^10.8.1", - "typescript": "^4.7.4", "@babel/eslint-parser": "^7.18.2", + "@changesets/cli": "^2.16.0", "@types/chai": "^4.2.18", "@types/mocha": "^8.2.2", + "@types/node": "^18.0.0", "@typescript-eslint/eslint-plugin": "^5.26.0", "@typescript-eslint/parser": "^4.26.0", "chai": "^4.2.0", @@ -45,6 +43,8 @@ "mocha": "^8.4.0", "nyc": "^15.1.0", "prettier": "^2.3.1", - "prettier-plugin-solidity": "^1.0.0-beta.13" + "prettier-plugin-solidity": "^1.0.0-beta.13", + "ts-node": "^10.8.1", + "typescript": "^4.7.4" } } diff --git a/packages/contracts/contracts/ChugSplashManager.sol b/packages/contracts/contracts/ChugSplashManager.sol index 484ed761f..a8b54aefc 100644 --- a/packages/contracts/contracts/ChugSplashManager.sol +++ b/packages/contracts/contracts/ChugSplashManager.sol @@ -8,6 +8,7 @@ import { ProxyAdmin } from "./ProxyAdmin.sol"; import { ProxyUpdater } from "./ProxyUpdater.sol"; import { Create2 } from "./libraries/Create2.sol"; import { MerkleTree } from "./libraries/MerkleTree.sol"; +import { IExecutorSelectionStrategy } from "./IExecutorSelectionStrategy.sol"; /** * @title ChugSplashManager @@ -137,6 +138,11 @@ contract ChugSplashManager is Owned { */ bytes32 public activeBundleId; + /** + * @notice The address of the Executor Selection Strategy for this project. + */ + IExecutorSelectionStrategy public executorSelectionStrategy; + /** * @notice Mapping of bundle IDs to bundle state. */ @@ -273,6 +279,12 @@ contract ChugSplashManager is Owned { "ChugSplashManager: action has already been executed" ); + address executor = getSelectedExecutor(activeBundleId); + require( + executor == msg.sender, + "ChugSplashManager: caller is not approved executor for active bundle ID" + ); + require( MerkleTree.verify( activeBundleId, @@ -364,6 +376,32 @@ contract ChugSplashManager is Owned { emit ProxySetToTarget(_name, _proxy, _proxyType, _name); } + /** + * @notice Allows the project owner to set an Executor Selection Strategy, which determines the + * strategy used to select executors for this project. Only callable when there is no + * active bundle. + */ + function setExecutorSelectionStategy(IExecutorSelectionStrategy _executorSelectionStrategy) + external + onlyOwner + { + require( + activeBundleId == bytes32(0), + "ChugSplashManager: a bundle has been approved and not yet completed" + ); + executorSelectionStrategy = _executorSelectionStrategy; + } + + /** + * @notice Get the address of the executor selected by the Executor Selection Strategy to + * execute a given bundle ID. + * + * @param _bundleId Bundle ID. + */ + function getSelectedExecutor(bytes32 _bundleId) public view returns (address) { + return executorSelectionStrategy.getSelectedExecutor(address(this), _bundleId); + } + /** * @notice Computes the address of an ERC-1967 proxy that would be created by this contract * given the target's name. This proxy is the default proxy used by ChugSplash. Uses diff --git a/packages/contracts/contracts/IExecutorSelectionStrategy.sol b/packages/contracts/contracts/IExecutorSelectionStrategy.sol new file mode 100644 index 000000000..595f098db --- /dev/null +++ b/packages/contracts/contracts/IExecutorSelectionStrategy.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +/** + * @notice Interface for the Executor Selection Strategy (ESS). + */ +interface IExecutorSelectionStrategy { + /** + * @notice Queries the selected executor for a given project/bundle. + * + * @param _project Address of the ChugSplashManager that mananges the project. + * @param _bundleId ID of the bundle currently being executed. + * + * @return Address of the selected executor. + */ + function getSelectedExecutor(address _project, bytes32 _bundleId) + external + view + returns (address); +}