-
Notifications
You must be signed in to change notification settings - Fork 86
Expand file tree
/
Copy pathAllowlist.sol
More file actions
228 lines (197 loc) · 9.44 KB
/
Copy pathAllowlist.sol
File metadata and controls
228 lines (197 loc) · 9.44 KB
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
// SPDX-License-Identifier: GPL-3.0-only
//
// ▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄
// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
// ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓
// ▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓
// ▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
// ▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀
// ▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌
// ▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓
// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓
//
// Trust math, not hardware.
pragma solidity 0.8.17;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import "./WalletRegistry.sol";
/// @title Allowlist
/// @notice The allowlist contract replaces the Threshold TokenStaking contract
/// as an outcome of TIP-092 and TIP-100 governance decisions.
/// Staking tokens is no longer required to operate nodes. Beta stakers
/// are selected by the DAO and operate the network based on the
/// allowlist maintained by the DAO.
/// @dev The allowlist contract maintains the maximum possible compatibility
/// with the old TokenStaking contract interface, as utilized by the
/// WalletRegistry contract.
contract Allowlist is Ownable2StepUpgradeable {
struct StakingProviderInfo {
uint96 weight;
uint96 pendingNewWeight;
bool decreasePending;
}
/// @notice Mapping between the staking provider address and a struct
/// maintaining weight settings for that staking provider.
mapping(address => StakingProviderInfo) public stakingProviders;
WalletRegistry public walletRegistry;
event StakingProviderAdded(address indexed stakingProvider, uint96 weight);
event WeightDecreaseRequested(
address indexed stakingProvider,
uint96 oldWeight,
uint96 newWeight
);
event WeightDecreaseFinalized(
address indexed stakingProvider,
uint96 oldWeight,
uint96 newWeight
);
event MaliciousBehaviorIdentified(
address notifier,
address[] stakingProviders
);
error StakingProviderAlreadyAdded();
error StakingProviderUnknown();
error RequestedWeightNotBelowCurrentWeight();
error NotWalletRegistry();
error NoDecreasePending();
error ZeroAddress();
error ZeroWeight();
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(address _walletRegistry) external initializer {
if (_walletRegistry == address(0)) {
revert ZeroAddress();
}
__Ownable2Step_init();
walletRegistry = WalletRegistry(_walletRegistry);
}
/// @notice Allows the governance to add a new staking provider with the
/// provided weight. If the staking provider address already has
/// a non-zero weight, the function reverts.
/// @param stakingProvider The staking provider's address
/// @param weight The weight of the new staking provider
function addStakingProvider(address stakingProvider, uint96 weight)
external
onlyOwner
{
if (stakingProvider == address(0)) {
revert ZeroAddress();
}
if (weight == 0) {
revert ZeroWeight();
}
StakingProviderInfo storage info = stakingProviders[stakingProvider];
if (info.weight != 0) {
revert StakingProviderAlreadyAdded();
}
emit StakingProviderAdded(stakingProvider, weight);
info.weight = weight;
walletRegistry.authorizationIncreased(stakingProvider, 0, weight);
}
/// @notice Allows the governance to request weight decrease for the given
/// staking provider. The change does not take the effect immediately
/// as it has to be approved by the WalletRegistry contract based on
/// decrease delays required. Overwrites pending weight decrease
/// request for the given staking provider. Reverts if the staking
/// provider is now known or if the proposed new weight is higher
/// or equal the current weight.
///
/// BE EXTREMELY CAREFUL MAKING CHANGES TO THE BETA STAKER SET!
/// ENSURE WALLET LIVENESS IS NOT AT RISK AND FAILED HEARTBEATS
/// ARE NOT GOING TO TRIGGER CASCADING MOVING FUNDS OPERATIONS!
///
/// @param stakingProvider The staking provider's address
/// @param newWeight The new requested weight of this staking provider
function requestWeightDecrease(address stakingProvider, uint96 newWeight)
external
onlyOwner
{
StakingProviderInfo storage info = stakingProviders[stakingProvider];
uint96 currentWeight = info.weight;
if (currentWeight == 0) {
revert StakingProviderUnknown();
}
if (newWeight >= currentWeight) {
revert RequestedWeightNotBelowCurrentWeight();
}
emit WeightDecreaseRequested(stakingProvider, currentWeight, newWeight);
info.pendingNewWeight = newWeight;
info.decreasePending = true;
walletRegistry.authorizationDecreaseRequested(
stakingProvider,
currentWeight,
newWeight
);
}
/// @notice Called by WalletRegistry contract to approve the previously
/// requested weight decrease for the given staking provider.
/// @param stakingProvider The staking provider's address
/// @return The new weight of the staking provider
function approveAuthorizationDecrease(address stakingProvider)
external
returns (uint96)
{
if (msg.sender != address(walletRegistry)) {
revert NotWalletRegistry();
}
StakingProviderInfo storage info = stakingProviders[stakingProvider];
uint96 currentWeight = info.weight;
uint96 newWeight = info.pendingNewWeight;
if (currentWeight == 0) {
revert StakingProviderUnknown();
}
if (!info.decreasePending) {
revert NoDecreasePending();
}
emit WeightDecreaseFinalized(stakingProvider, currentWeight, newWeight);
info.weight = newWeight;
info.pendingNewWeight = 0;
info.decreasePending = false;
return newWeight;
}
/// @notice Returns the current weight of the staking provider.
/// @dev The function signature maintains compatibility with Threshold
/// TokenStaking contract to minimize the TIP-092 impact on the
/// WalletRegistry contract.
function authorizedStake(address stakingProvider, address)
external
view
returns (uint96)
{
return stakingProviders[stakingProvider].weight;
}
/// @notice No-op stake seize operation. After TIP-092 tokens are not staked
/// so there is nothing to seize from.
/// @dev The function signature maintains compatibility with Threshold
/// TokenStaking contract to minimize the TIP-092 impact on the
/// WalletRegistry contract.
function seize(
uint96,
uint256,
address notifier,
address[] memory _stakingProviders
) external {
emit MaliciousBehaviorIdentified(notifier, _stakingProviders);
}
/// @notice Returns the stake owner, beneficiary, and authorizer roles for
/// the given staking provider. After TIP-092 those roles are no
/// longer relevant as no tokens are staked. The owner is set to the
/// allowlist owner, the beneficiary is the staking provider itself
/// and the authorizer is the zero address.
/// @dev The function signature maintains compatibility with Threshold
/// TokenStaking contract to minimize the TIP-092 impact on the
/// WalletRegistry contract.
function rolesOf(address stakingProvider)
external
view
returns (
address stakeOwner,
address payable beneficiary,
address authorizer
)
{
return (owner(), payable(stakingProvider), address(0));
}
}