-
Notifications
You must be signed in to change notification settings - Fork 6
/
Candidate.sol
203 lines (172 loc) · 6.58 KB
/
Candidate.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
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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/access/Ownable.sol";
import { IDAOCommittee } from "./interfaces/IDAOCommittee.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ICandidate } from "./interfaces/ICandidate.sol";
import { Layer2I } from "./interfaces/Layer2I.sol";
import { Layer2RegistryI } from "./interfaces/Layer2RegistryI.sol";
import "../../proxy/ProxyStorage.sol";
import { AccessibleCommon } from "./common/AccessibleCommon.sol";
import "./CandidateStorage.sol";
interface ICoinage {
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}
interface IOperator {
function setWithdrawalDelay(uint256 withdrawalDelay_) external;
}
interface IISeigManager {
function updateSeigniorage() external returns (bool);
function coinages(address layer2) external view returns (address);
}
/// @title Managing a candidate
/// @notice Either a user or layer2 contract can be a candidate
contract Candidate is ProxyStorage, AccessibleCommon, CandidateStorage, Layer2I {
event TransferCoinage(address from, address to, uint256 amount);
modifier onlyCandidate() {
if (isLayer2Candidate) {
Layer2I layer2 = Layer2I(candidate);
require(layer2.operator() == msg.sender, "Candidate: sender is not the operator of this contract");
} else {
require(candidate == msg.sender, "Candidate: sender is not the candidate of this contract");
}
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return _supportedInterfaces[interfaceId] || super.supportsInterface(interfaceId) ;
}
// function _registerInterface(bytes4 interfaceId) internal virtual {
// require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
// _supportedInterfaces[interfaceId] = true;
// }
function initialize(
address _candidate,
bool _isLayer2Candidate,
string memory _memo,
address _committee,
address _seigManager
) external {
require(
_candidate != address(0)
|| _committee != address(0)
|| _seigManager != address(0),
"Candidate: input is zero"
);
candidate = _candidate;
isLayer2Candidate = _isLayer2Candidate;
committee = _committee;
seigManager = _seigManager;
memo = _memo;
}
function setSeigManager(address _seigManager) external onlyOwner {
require(_seigManager != address(0), "Candidate: input is zero");
seigManager = _seigManager;
}
/// @notice Set DAOCommitteeProxy contract address
/// @param _committee New DAOCommitteeProxy contract address
function setCommittee(address _committee) external onlyOwner {
require(_committee != address(0), "Candidate: input is zero");
committee = _committee;
}
/// @notice Set memo
/// @param _memo New memo on this candidate
function setMemo(string calldata _memo) external onlyOwner {
memo = _memo;
}
/// @notice Set DAOCommitteeProxy contract address
/// @notice Call updateSeigniorage on SeigManager
/// @return Whether or not the execution succeeded
function updateSeigniorage() external returns (bool) {
require(seigManager != address(0), "Candidate: SeigManager is zero");
require(IISeigManager(seigManager).updateSeigniorage(), "fail updateSeigniorage");
return true;
}
/// @notice Try to be a member
/// @param _memberIndex The index of changing member slot
/// @return Whether or not the execution succeeded
function changeMember(uint256 _memberIndex)
external
onlyCandidate
returns (bool)
{
return IDAOCommittee(committee).changeMember(_memberIndex);
}
/// @notice Retire a member
/// @return Whether or not the execution succeeded
function retireMember() external onlyCandidate returns (bool) {
return IDAOCommittee(committee).retireMember();
}
/// @notice Vote on an agenda
/// @param _agendaID The agenda ID
/// @param _vote voting type
/// @param _comment voting comment
function castVote(
uint256 _agendaID,
uint256 _vote,
string calldata _comment
)
external
onlyCandidate
{
IDAOCommittee(committee).castVote(_agendaID, _vote, _comment);
}
function claimActivityReward()
external
onlyCandidate
{
address receiver;
if (isLayer2Candidate) {
Layer2I layer2 = Layer2I(candidate);
receiver = layer2.operator();
} else {
receiver = candidate;
}
IDAOCommittee(committee).claimActivityReward(receiver);
}
/// @notice Checks whether this contract is a candidate contract
/// @return Whether or not this contract is a candidate contract
function isCandidateContract() external pure returns (bool) {
return true;
}
function isCandidateFwContract() external pure returns (bool) {
return true;
}
function operator() external view override returns (address) { return candidate; }
function isLayer2() external pure override returns (bool) { return true; }
function currentFork() external pure override returns (uint256) { return 1; }
function lastEpoch(uint256 /*forkNumber*/) external pure override returns (uint256) { return 1; }
function changeOperator(address _operator) external override { }
/// @notice Retrieves the total staked balance on this candidate
/// @return totalsupply Total staked amount on this candidate
function totalStaked()
external
view
returns (uint256 totalsupply)
{
IERC20 coinage = _getCoinageToken();
return coinage.totalSupply();
}
/// @notice Retrieves the staked balance of the account on this candidate
/// @param _account Address being retrieved
/// @return amount The staked balance of the account on this candidate
function stakedOf(
address _account
)
external
view
returns (uint256 amount)
{
IERC20 coinage = _getCoinageToken();
return coinage.balanceOf(_account);
}
function _getCoinageToken() internal view returns (IERC20) {
address c;
if (isLayer2Candidate) {
c = candidate;
} else {
c = address(this);
}
require(c != address(0), "Candidate: coinage is zero");
return IERC20(IISeigManager(seigManager).coinages(c));
}
}