/
Permissions.sol
153 lines (129 loc) · 4.73 KB
/
Permissions.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
pragma solidity >=0.6.6;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
/// @title Permissions
/// @author 0xScotch <scotch@malt.money>
/// @notice Inherited by almost all Malt contracts to provide access control
contract Permissions is AccessControl {
using SafeMath for uint256;
using SafeERC20 for ERC20;
// Timelock has absolute power across the system
bytes32 public constant TIMELOCK_ROLE = keccak256("TIMELOCK_ROLE");
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
bytes32 public constant GOVERNOR_ROLE = keccak256("GOVERNOR_ROLE");
// Can mint/burn Malt
bytes32 public constant MONETARY_BURNER_ROLE = keccak256("MONETARY_BURNER_ROLE");
bytes32 public constant MONETARY_MINTER_ROLE = keccak256("MONETARY_MINTER_ROLE");
// Contract types
bytes32 public constant STABILIZER_NODE_ROLE = keccak256("STABILIZER_NODE_ROLE");
bytes32 public constant LIQUIDITY_MINE_ROLE = keccak256("LIQUIDITY_MINE_ROLE");
bytes32 public constant AUCTION_ROLE = keccak256("AUCTION_ROLE");
bytes32 public constant REWARD_THROTTLE_ROLE = keccak256("REWARD_THROTTLE_ROLE");
address internal globalAdmin;
mapping(address => uint256) public lastBlock; // protect against reentrancy
function _adminSetup(address _timelock) internal {
_roleSetup(TIMELOCK_ROLE, _timelock);
_roleSetup(ADMIN_ROLE, _timelock);
_roleSetup(GOVERNOR_ROLE, _timelock);
_roleSetup(MONETARY_BURNER_ROLE, _timelock);
_roleSetup(MONETARY_MINTER_ROLE, _timelock);
_roleSetup(STABILIZER_NODE_ROLE, _timelock);
_roleSetup(LIQUIDITY_MINE_ROLE, _timelock);
_roleSetup(AUCTION_ROLE, _timelock);
_roleSetup(REWARD_THROTTLE_ROLE, _timelock);
globalAdmin = _timelock;
}
function assignRole(bytes32 role, address _assignee)
external
onlyRole(TIMELOCK_ROLE, "Only timelock can assign roles")
{
_setupRole(role, _assignee);
}
function removeRole(bytes32 role, address _entity)
external
onlyRole(TIMELOCK_ROLE, "Only timelock can revoke roles")
{
revokeRole(role, _entity);
}
function reassignGlobalAdmin(address _admin)
external
onlyRole(TIMELOCK_ROLE, "Only timelock can assign roles")
{
_swapRole(_admin, globalAdmin, TIMELOCK_ROLE);
_swapRole(_admin, globalAdmin, ADMIN_ROLE);
_swapRole(_admin, globalAdmin, GOVERNOR_ROLE);
_swapRole(_admin, globalAdmin, MONETARY_BURNER_ROLE);
_swapRole(_admin, globalAdmin, MONETARY_MINTER_ROLE);
_swapRole(_admin, globalAdmin, STABILIZER_NODE_ROLE);
_swapRole(_admin, globalAdmin, LIQUIDITY_MINE_ROLE);
_swapRole(_admin, globalAdmin, AUCTION_ROLE);
_swapRole(_admin, globalAdmin, REWARD_THROTTLE_ROLE);
globalAdmin = _admin;
}
function emergencyWithdrawGAS(address payable destination)
external
onlyRole(TIMELOCK_ROLE, "Only timelock can assign roles")
{
// Transfers the entire balance of the Gas token to destination
destination.call{value: address(this).balance}('');
}
function emergencyWithdraw(address _token, address destination)
external
onlyRole(TIMELOCK_ROLE, "Must have timelock role")
{
// Transfers the entire balance of an ERC20 token at _token to destination
ERC20 token = ERC20(_token);
token.safeTransfer(destination, token.balanceOf(address(this)));
}
function partialWithdrawGAS(address payable destination, uint256 amount)
external
onlyRole(TIMELOCK_ROLE, "Must have timelock role")
{
destination.call{value: amount}('');
}
function partialWithdraw(address _token, address destination, uint256 amount)
external
onlyRole(TIMELOCK_ROLE, "Only timelock can assign roles")
{
ERC20 token = ERC20(_token);
token.safeTransfer(destination, amount);
}
/*
* INTERNAL METHODS
*/
function _swapRole(address newAccount, address oldAccount, bytes32 role) internal {
revokeRole(role, oldAccount);
_setupRole(role, newAccount);
}
function _roleSetup(bytes32 role, address account) internal {
_setupRole(role, account);
_setRoleAdmin(role, ADMIN_ROLE);
}
function _onlyRole(bytes32 role, string memory reason) internal view {
require(
hasRole(
role,
_msgSender()
),
reason
);
}
function _notSameBlock() internal {
require(
block.number > lastBlock[_msgSender()],
"Can't carry out actions in the same block"
);
lastBlock[_msgSender()] = block.number;
}
// Using internal function calls here reduces compiled bytecode size
modifier onlyRole(bytes32 role, string memory reason) {
_onlyRole(role, reason);
_;
}
modifier notSameBlock() {
_notSameBlock();
_;
}
}