forked from Synthetixio/synthetix
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDelegateApprovals.sol
162 lines (131 loc) · 5.71 KB
/
DelegateApprovals.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
156
157
158
159
160
161
162
pragma solidity ^0.5.16;
// Inheritance
import "./Owned.sol";
import "./interfaces/IDelegateApprovals.sol";
// Internal references
import "./EternalStorage.sol";
// https://docs.synthetix.io/contracts/source/contracts/delegateapprovals
contract DelegateApprovals is Owned, IDelegateApprovals {
bytes32 public constant BURN_FOR_ADDRESS = "BurnForAddress";
bytes32 public constant ISSUE_FOR_ADDRESS = "IssueForAddress";
bytes32 public constant CLAIM_FOR_ADDRESS = "ClaimForAddress";
bytes32 public constant EXCHANGE_FOR_ADDRESS = "ExchangeForAddress";
bytes32 public constant APPROVE_ALL = "ApproveAll";
bytes32[5] private _delegatableFunctions = [
APPROVE_ALL,
BURN_FOR_ADDRESS,
ISSUE_FOR_ADDRESS,
CLAIM_FOR_ADDRESS,
EXCHANGE_FOR_ADDRESS
];
/* ========== STATE VARIABLES ========== */
EternalStorage public eternalStorage;
constructor(address _owner, EternalStorage _eternalStorage) public Owned(_owner) {
eternalStorage = _eternalStorage;
}
/* ========== VIEWS ========== */
// Move it to setter and associatedState
// util to get key based on action name + address of authoriser + address for delegate
function _getKey(
bytes32 _action,
address _authoriser,
address _delegate
) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(_action, _authoriser, _delegate));
}
// hash of actionName + address of authoriser + address for the delegate
function canBurnFor(address authoriser, address delegate) external view returns (bool) {
return _checkApproval(BURN_FOR_ADDRESS, authoriser, delegate);
}
function canIssueFor(address authoriser, address delegate) external view returns (bool) {
return _checkApproval(ISSUE_FOR_ADDRESS, authoriser, delegate);
}
function canClaimFor(address authoriser, address delegate) external view returns (bool) {
return _checkApproval(CLAIM_FOR_ADDRESS, authoriser, delegate);
}
function canExchangeFor(address authoriser, address delegate) external view returns (bool) {
return _checkApproval(EXCHANGE_FOR_ADDRESS, authoriser, delegate);
}
function approvedAll(address authoriser, address delegate) public view returns (bool) {
return eternalStorage.getBooleanValue(_getKey(APPROVE_ALL, authoriser, delegate));
}
// internal function to check approval based on action
// if approved for all actions then will return true
// before checking specific approvals
function _checkApproval(
bytes32 action,
address authoriser,
address delegate
) internal view returns (bool) {
if (approvedAll(authoriser, delegate)) return true;
return eternalStorage.getBooleanValue(_getKey(action, authoriser, delegate));
}
/* ========== SETTERS ========== */
// Approve All
function approveAllDelegatePowers(address delegate) external {
_setApproval(APPROVE_ALL, msg.sender, delegate);
}
// Removes all delegate approvals
function removeAllDelegatePowers(address delegate) external {
for (uint i = 0; i < _delegatableFunctions.length; i++) {
_withdrawApproval(_delegatableFunctions[i], msg.sender, delegate);
}
}
// Burn on behalf
function approveBurnOnBehalf(address delegate) external {
_setApproval(BURN_FOR_ADDRESS, msg.sender, delegate);
}
function removeBurnOnBehalf(address delegate) external {
_withdrawApproval(BURN_FOR_ADDRESS, msg.sender, delegate);
}
// Issue on behalf
function approveIssueOnBehalf(address delegate) external {
_setApproval(ISSUE_FOR_ADDRESS, msg.sender, delegate);
}
function removeIssueOnBehalf(address delegate) external {
_withdrawApproval(ISSUE_FOR_ADDRESS, msg.sender, delegate);
}
// Claim on behalf
function approveClaimOnBehalf(address delegate) external {
_setApproval(CLAIM_FOR_ADDRESS, msg.sender, delegate);
}
function removeClaimOnBehalf(address delegate) external {
_withdrawApproval(CLAIM_FOR_ADDRESS, msg.sender, delegate);
}
// Exchange on behalf
function approveExchangeOnBehalf(address delegate) external {
_setApproval(EXCHANGE_FOR_ADDRESS, msg.sender, delegate);
}
function removeExchangeOnBehalf(address delegate) external {
_withdrawApproval(EXCHANGE_FOR_ADDRESS, msg.sender, delegate);
}
function _setApproval(
bytes32 action,
address authoriser,
address delegate
) internal {
require(delegate != address(0), "Can't delegate to address(0)");
eternalStorage.setBooleanValue(_getKey(action, authoriser, delegate), true);
emit Approval(authoriser, delegate, action);
}
function _withdrawApproval(
bytes32 action,
address authoriser,
address delegate
) internal {
// Check approval is set otherwise skip deleting approval
if (eternalStorage.getBooleanValue(_getKey(action, authoriser, delegate))) {
eternalStorage.deleteBooleanValue(_getKey(action, authoriser, delegate));
emit WithdrawApproval(authoriser, delegate, action);
}
}
function setEternalStorage(EternalStorage _eternalStorage) external onlyOwner {
require(address(_eternalStorage) != address(0), "Can't set eternalStorage to address(0)");
eternalStorage = _eternalStorage;
emit EternalStorageUpdated(address(eternalStorage));
}
/* ========== EVENTS ========== */
event Approval(address indexed authoriser, address delegate, bytes32 action);
event WithdrawApproval(address indexed authoriser, address delegate, bytes32 action);
event EternalStorageUpdated(address newEternalStorage);
}