Skip to content

Instantly share code, notes, and snippets.

@Amxx
Last active September 8, 2022 16:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Amxx/983acfa134f5b6d1120ae26ecab657b9 to your computer and use it in GitHub Desktop.
Save Amxx/983acfa134f5b6d1120ae26ecab657b9 to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/Address.sol";
contract UpgradeRegression is AccessControl {
bytes32 public constant EXECUTION_ROLE = keccak256("EXECUTION_ROLE");
bytes32 public constant REGRESSION_ROLE = keccak256("REGRESSION_ROLE");
mapping(bytes32 => uint64) internal _regressionDeadline;
constructor() {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
function perform(
address[] calldata executionTargets,
bytes[] calldata executionPayloads,
address[] calldata regressionTargets,
bytes[] calldata regressionPayloads,
address[] calldata regressionOperators,
bytes32 regressionSalt,
uint64 regressionDelay
)
public
onlyRole(EXECUTION_ROLE)
returns (bytes32 regressionID)
{
// Sanity
require(executionTargets.length == executionPayloads.length);
require(regressionTargets.length == regressionPayloads.length);
// Register regression
if (regressionTargets.length > 0) {
regressionID = hashRegression(regressionTargets, regressionPayloads, regressionSalt);
// Register delay
require(_regressionDeadline[regressionID] == 0);
_regressionDeadline[regressionID] = uint64(block.timestamp) + regressionDelay;
// Grant regression permission to operators
for (uint256 i = 0; i < regressionOperators.length; ++i) {
_grantRole(regressionID, regressionOperators[i]);
}
} else {
regressionID = bytes32(0);
}
// Execute
_execute(executionTargets, executionPayloads);
// TODO: emit event
}
function regression(
address[] calldata regressionTargets,
bytes[] calldata regressionPayloads,
bytes32 regressionSalt
)
public
{
bytes32 regressionID = hashRegression(regressionTargets, regressionPayloads, regressionSalt);
// Auth
require(hasRole(REGRESSION_ROLE, msg.sender) || hasRole(regressionID, msg.sender));
// Scheduled + timming + cleanup
uint64 deadline = _regressionDeadline[regressionID];
require(0 < deadline && block.timestamp < deadline);
delete _regressionDeadline[regressionID];
// Perform regression
_execute(regressionTargets, regressionPayloads);
}
function hashRegression(address[] calldata targets, bytes[] calldata payloads, bytes32 salt) public pure returns (bytes32) {
return keccak256(abi.encode(targets, payloads, salt));
}
function _execute(address[] calldata targets, bytes[] calldata payloads) private {
uint256 length = targets.length;
for (uint256 i = 0; i < length; ++i) {
Address.functionCall(targets[i], payloads[i]);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment