-
Notifications
You must be signed in to change notification settings - Fork 8
/
INSTR.sol
80 lines (62 loc) · 3.2 KB
/
INSTR.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.15;
import "src/Kernel.sol";
error INSTR_InstructionsCannotBeEmpty();
error INSTR_InvalidChangeExecutorAction();
/// @notice Caches and executes batched instructions for protocol upgrades in the Kernel.
contract OlympusInstructions is Module {
event InstructionsStored(uint256 instructionsId);
uint256 public totalInstructions;
mapping(uint256 => Instruction[]) public storedInstructions;
/*//////////////////////////////////////////////////////////////
MODULE INTERFACE
//////////////////////////////////////////////////////////////*/
constructor(Kernel kernel_) Module(kernel_) {}
/// @inheritdoc Module
function KEYCODE() public pure override returns (Keycode) {
return toKeycode("INSTR");
}
/// @inheritdoc Module
function VERSION() public pure override returns (uint8 major, uint8 minor) {
return (1, 0);
}
/*//////////////////////////////////////////////////////////////
CORE LOGIC
//////////////////////////////////////////////////////////////*/
/// @notice View function for retrieving a list of Instructions in an outside contract.
function getInstructions(uint256 instructionsId_) public view returns (Instruction[] memory) {
return storedInstructions[instructionsId_];
}
/// @notice Store a list of Instructions to be executed in the future.
function store(Instruction[] calldata instructions_) external permissioned returns (uint256) {
uint256 length = instructions_.length;
uint256 instructionsId = ++totalInstructions;
Instruction[] storage instructions = storedInstructions[instructionsId];
if (length == 0) revert INSTR_InstructionsCannotBeEmpty();
for (uint256 i; i < length; ) {
Instruction calldata instruction = instructions_[i];
ensureContract(instruction.target);
// If the instruction deals with a module, make sure the module has a valid keycode (UPPERCASE A-Z ONLY)
if (
instruction.action == Actions.InstallModule ||
instruction.action == Actions.UpgradeModule
) {
Module module = Module(instruction.target);
ensureValidKeycode(module.KEYCODE());
} else if (instruction.action == Actions.ChangeExecutor && i != length - 1) {
// Throw an error if ChangeExecutor exists and is not the last Action in the instruction list.
// This exists because if ChangeExecutor is not the last item in the list of instructions,
// the Kernel will not recognize any of the following instructions as valid, since the policy
// executing the list of instructions no longer has permissions in the Kernel. To avoid this issue
// and prevent invalid proposals from being saved, we perform this check.
revert INSTR_InvalidChangeExecutorAction();
}
instructions.push(instructions_[i]);
unchecked {
++i;
}
}
emit InstructionsStored(instructionsId);
return instructionsId;
}
}