-
Notifications
You must be signed in to change notification settings - Fork 2
/
Preparable.sol
155 lines (138 loc) · 4.94 KB
/
Preparable.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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.10;
import "../../interfaces/IPreparable.sol";
import "../../libraries/Errors.sol";
/**
* @notice Implements the base logic for a two-phase commit
* @dev This does not implements any access-control so publicly exposed
* callers should make sure to have the proper checks in place
*/
contract Preparable is IPreparable {
uint256 private constant _MIN_DELAY = 3 days;
mapping(bytes32 => address) public pendingAddresses;
mapping(bytes32 => uint256) public pendingUInts256;
mapping(bytes32 => address) public currentAddresses;
mapping(bytes32 => uint256) public currentUInts256;
/**
* @dev Deadlines shares the same namespace regardless of the type
* of the pending variable so this needs to be enforced in the caller
*/
mapping(bytes32 => uint256) public deadlines;
function _prepareDeadline(bytes32 key, uint256 delay) internal {
require(deadlines[key] == 0, Error.DEADLINE_NOT_ZERO);
require(delay >= _MIN_DELAY, Error.DELAY_TOO_SHORT);
deadlines[key] = block.timestamp + delay;
}
/**
* @notice Prepares an uint256 that should be committed to the contract
* after `_MIN_DELAY` elapsed
* @param value The value to prepare
* @return `true` if success.
*/
function _prepare(
bytes32 key,
uint256 value,
uint256 delay
) internal returns (bool) {
_prepareDeadline(key, delay);
pendingUInts256[key] = value;
emit ConfigPreparedNumber(key, value, delay);
return true;
}
/**
* @notice Same as `_prepare(bytes32,uint256,uint256)` but uses a default delay
*/
function _prepare(bytes32 key, uint256 value) internal returns (bool) {
return _prepare(key, value, _MIN_DELAY);
}
/**
* @notice Prepares an address that should be committed to the contract
* after `_MIN_DELAY` elapsed
* @param value The value to prepare
* @return `true` if success.
*/
function _prepare(
bytes32 key,
address value,
uint256 delay
) internal returns (bool) {
_prepareDeadline(key, delay);
pendingAddresses[key] = value;
emit ConfigPreparedAddress(key, value, delay);
return true;
}
/**
* @notice Same as `_prepare(bytes32,address,uint256)` but uses a default delay
*/
function _prepare(bytes32 key, address value) internal returns (bool) {
return _prepare(key, value, _MIN_DELAY);
}
/**
* @notice Reset a uint256 key
* @return `true` if success.
*/
function _resetUInt256Config(bytes32 key) internal returns (bool) {
require(deadlines[key] != 0, Error.NOTHING_PENDING);
deadlines[key] = 0;
pendingUInts256[key] = 0;
emit ConfigReset(key);
return true;
}
/**
* @notice Reset an address key
* @return `true` if success.
*/
function _resetAddressConfig(bytes32 key) internal returns (bool) {
require(deadlines[key] != 0, Error.NOTHING_PENDING);
deadlines[key] = 0;
pendingAddresses[key] = address(0);
emit ConfigReset(key);
return true;
}
/**
* @dev Checks the deadline of the key and reset it
*/
function _executeDeadline(bytes32 key) internal {
uint256 deadline = deadlines[key];
require(block.timestamp >= deadline, Error.DEADLINE_NOT_REACHED);
require(deadline != 0, Error.DEADLINE_NOT_SET);
deadlines[key] = 0;
}
/**
* @notice Execute uint256 config update (with time delay enforced).
* @dev Needs to be called after the update was prepared. Fails if called before time delay is met.
* @return New value.
*/
function _executeUInt256(bytes32 key) internal returns (uint256) {
_executeDeadline(key);
uint256 newValue = pendingUInts256[key];
_setConfig(key, newValue);
return newValue;
}
/**
* @notice Execute address config update (with time delay enforced).
* @dev Needs to be called after the update was prepared. Fails if called before time delay is met.
* @return New value.
*/
function _executeAddress(bytes32 key) internal returns (address) {
_executeDeadline(key);
address newValue = pendingAddresses[key];
_setConfig(key, newValue);
return newValue;
}
function _setConfig(bytes32 key, address value) internal returns (address) {
emit ConfigUpdatedAddress(key, currentAddresses[key], value);
currentAddresses[key] = value;
pendingAddresses[key] = address(0);
deadlines[key] = 0;
return value;
}
function _setConfig(bytes32 key, uint256 value) internal returns (uint256) {
uint256 oldValue = currentUInts256[key];
currentUInts256[key] = value;
pendingUInts256[key] = 0;
deadlines[key] = 0;
emit ConfigUpdatedNumber(key, oldValue, value);
return value;
}
}