-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathRos-Contract.sol
298 lines (245 loc) · 11.3 KB
/
Ros-Contract.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
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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
pragma solidity ^0.5.17;
interface IERC20 {
function balanceOf(address owner) external view returns (uint);
function transfer(address _to, uint256 _value) external returns (bool);
function transferFrom(address _from, address _to, uint256 _value) external returns (bool);
function approve(address _spender, uint256 _value) external returns (bool);
}
contract Rose {
using SafeMath for uint;
/// @notice EIP-20 token name for this token
string public constant name = "Rose";
/// @notice EIP-20 token symbol for this token
string public constant symbol = "Ros";
/// @notice EIP-20 token decimals for this token
uint8 public constant decimals = 18;
/// @notice Total number of tokens in circulation
uint public constant totalSupply = 20_000_000e18; // 20 million ros
/// @notice Allowance amounts on behalf of others
mapping(address => mapping(address => uint)) internal allowances;
/// @notice Official record of token balances for each account
mapping(address => uint) internal balances;
/// @notice A record of each accounts delegate
mapping(address => address) public delegates;
function setCheckpoint(uint fromBlock64, uint votes192) internal pure returns (uint){
fromBlock64 |= votes192 << 64;
return fromBlock64;
}
function getCheckpoint(uint _checkpoint) internal pure returns (uint fromBlock, uint votes){
fromBlock=uint(uint64(_checkpoint));
votes=uint(uint192(_checkpoint>>64));
}
function getCheckpoint(address _account,uint _index) external view returns (uint fromBlock, uint votes){
uint data=checkpoints[_account][_index];
(fromBlock,votes)=getCheckpoint(data);
}
/// @notice A record of votes checkpoints for each account, by index
mapping(address => mapping(uint => uint)) public checkpoints;
/// @notice The number of checkpoints for each account
mapping(address => uint) public numCheckpoints;
/// @notice An event thats emitted when an account changes its delegate
event DelegateChanged(address delegator, address fromDelegate, address toDelegate);
/// @notice An event thats emitted when a delegate account's vote balance changes
event DelegateVotesChanged(address delegate, uint previousBalance, uint newBalance);
/// @notice The standard EIP-20 transfer event
event Transfer(address indexed from, address indexed to, uint256 amount);
/// @notice The standard EIP-20 approval event
event Approval(address indexed owner, address indexed spender, uint256 amount);
constructor(address account) public {
balances[account] = totalSupply;
emit Transfer(address(0), account, totalSupply);
}
function allowance(address account, address spender) external view returns (uint) {
return allowances[account][spender];
}
function approve(address spender, uint rawAmount) external returns (bool) {
require(spender != address(0), "ERC20: approve to the zero address");
allowances[msg.sender][spender] = rawAmount;
emit Approval(msg.sender, spender, rawAmount);
return true;
}
/**
* @notice Get the number of tokens held by the `account`
* @param account The address of the account to get the balance of
* @return The number of tokens held
*/
function balanceOf(address account) external view returns (uint) {
return balances[account];
}
/**
* @notice Transfer `amount` tokens from `msg.sender` to `dst`
* @param dst The address of the destination account
* @param rawAmount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transfer(address dst, uint rawAmount) external returns (bool) {
_transferTokens(msg.sender, dst, rawAmount);
return true;
}
/**
* @notice Transfer `amount` tokens from `src` to `dst`
* @param src The address of the source account
* @param dst The address of the destination account
* @param rawAmount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transferFrom(address src, address dst, uint rawAmount) external returns (bool) {
address spender = msg.sender;
uint spenderAllowance = allowances[src][spender];
if (spender != src && spenderAllowance != uint(- 1)) {
uint newAllowance = spenderAllowance.sub(rawAmount, "Rose::transferFrom: transfer amount exceeds spender allowance");
allowances[src][spender] = newAllowance;
emit Approval(src, spender, newAllowance);
}
_transferTokens(src, dst, rawAmount);
return true;
}
/**
* @notice Delegate votes from `msg.sender` to `delegatee`
* @param delegatee The address to delegate votes to
*/
function delegate(address delegatee) public {
return _delegate(msg.sender, delegatee);
}
function _delegate(address delegator, address delegatee) internal {
address currentDelegate = delegates[delegator];
uint delegatorBalance = balances[delegator];
delegates[delegator] = delegatee;
emit DelegateChanged(delegator, currentDelegate, delegatee);
_moveDelegates(currentDelegate, delegatee, delegatorBalance);
}
/**
* @notice Gets the current votes balance for `account`
* @param account The address to get votes balance
* @return The number of current votes for `account`
*/
function getCurrentVotes(address account) external view returns (uint) {
uint nCheckpoints = numCheckpoints[account];
(,uint votes)=getCheckpoint(checkpoints[account][nCheckpoints - 1]);
return nCheckpoints > 0 ? votes : 0;
}
/**
* @notice Determine the prior number of votes for an account as of a block number
* @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
* @param account The address of the account to check
* @param blockNumber The block number to get the vote balance at
* @return The number of votes the account had as of the given block
*/
function getPriorVotes(address account, uint blockNumber) public view returns (uint) {
require(blockNumber < block.number, "Rose::getPriorVotes: not yet determined");
uint nCheckpoints = numCheckpoints[account];
if (nCheckpoints == 0) {
return 0;
}
(uint dataFromBlock1,uint dataVotes1)=getCheckpoint(checkpoints[account][nCheckpoints - 1]);
// First check most recent balance
if (dataFromBlock1 <= blockNumber) {
return dataVotes1;
}
(uint fromBlock0,)=getCheckpoint(checkpoints[account][0]);
// Next check implicit zero balance
if (fromBlock0 > blockNumber) {
return 0;
}
uint lower = 0;
uint upper = nCheckpoints - 1;
while (upper > lower) {
uint center = upper - (upper - lower) / 2;
// ceil, avoiding overflow
uint cp = checkpoints[account][center];
(uint cpFromBlock,uint cpVotes)=getCheckpoint(cp);
if (cpFromBlock == blockNumber) {
return cpVotes;
} else if (cpFromBlock < blockNumber) {
lower = center;
} else {
upper = center - 1;
}
}
(,uint reVotes)=getCheckpoint(checkpoints[account][lower]);
return reVotes;
}
function _transferTokens(address src, address dst, uint amount) internal {
require(src != address(0), "Rose::_transferTokens: cannot transfer from the zero address");
require(dst != address(0), "Rose::_transferTokens: cannot transfer to the zero address");
balances[src] = balances[src].sub(amount, "Rose::_transferTokens: transfer amount exceeds balance");
balances[dst] = balances[dst].add(amount, "Rose::_transferTokens: transfer amount overflows");
emit Transfer(src, dst, amount);
_moveDelegates(delegates[src], delegates[dst], amount);
}
function _moveDelegates(address srcRep, address dstRep, uint amount) internal {
if (srcRep != dstRep && amount > 0) {
if (srcRep != address(0)) {
uint srcRepNum = numCheckpoints[srcRep];
(,uint srcVotes)=getCheckpoint(checkpoints[srcRep][srcRepNum - 1]);
uint srcRepOld = srcRepNum > 0 ? srcVotes : 0;
uint srcRepNew = srcRepOld.sub(amount, "Rose::_moveVotes: vote amount underflows");
_writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
}
if (dstRep != address(0)) {
uint dstRepNum = numCheckpoints[dstRep];
(,uint dstVotes)=getCheckpoint(checkpoints[dstRep][dstRepNum - 1]);
uint dstRepOld = dstRepNum > 0 ? dstVotes : 0;
uint dstRepNew = dstRepOld.add(amount, "Rose::_moveVotes: vote amount overflows");
_writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
}
}
}
function _writeCheckpoint(address delegatee, uint256 nCheckpoints, uint256 oldVotes, uint256 newVotes) internal {
uint blockNumber = block.number;
(uint fromBlock,)=getCheckpoint(checkpoints[delegatee][nCheckpoints - 1]);
if (nCheckpoints > 0 && fromBlock == blockNumber) {
checkpoints[delegatee][nCheckpoints - 1] = setCheckpoint(fromBlock,newVotes);
} else {
checkpoints[delegatee][nCheckpoints] = setCheckpoint(blockNumber, newVotes);
numCheckpoints[delegatee] = nCheckpoints + 1;
}
emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
}
}
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, errorMessage);
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction underflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, errorMessage);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
}