2017-07-05 10:28:15 +00:00
|
|
|
|
pragma solidity ^0.4.11;
|
|
|
|
|
|
|
|
|
|
import "./announcementTypes.sol";
|
|
|
|
|
import "./module.sol";
|
|
|
|
|
import "./moduleHandler.sol";
|
|
|
|
|
import "./safeMath.sol";
|
|
|
|
|
|
|
|
|
|
contract schellingVars {
|
|
|
|
|
/*
|
|
|
|
|
Common enumerations and structures of the Schelling and Database contract.
|
|
|
|
|
*/
|
|
|
|
|
enum voterStatus {
|
|
|
|
|
base,
|
|
|
|
|
afterPrepareVote,
|
|
|
|
|
afterSendVoteOk,
|
|
|
|
|
afterSendVoteBad
|
|
|
|
|
}
|
|
|
|
|
struct _rounds {
|
|
|
|
|
uint256 totalAboveWeight;
|
|
|
|
|
uint256 totalBelowWeight;
|
|
|
|
|
uint256 reward;
|
|
|
|
|
uint256 blockHeight;
|
|
|
|
|
bool voted;
|
|
|
|
|
}
|
|
|
|
|
struct _voter {
|
|
|
|
|
uint256 roundID;
|
|
|
|
|
bytes32 hash;
|
|
|
|
|
voterStatus status;
|
|
|
|
|
bool voteResult;
|
|
|
|
|
uint256 rewards;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
contract schellingDB is safeMath, schellingVars {
|
|
|
|
|
/*
|
|
|
|
|
Schelling database contract.
|
|
|
|
|
*/
|
|
|
|
|
address private owner;
|
|
|
|
|
function replaceOwner(address newOwner) external returns(bool) {
|
2018-06-12 09:05:49 +00:00
|
|
|
|
require( owner == address(0x00) || msg.sender == owner );
|
2017-07-05 10:28:15 +00:00
|
|
|
|
owner = newOwner;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
modifier isOwner { require( msg.sender == owner ); _; }
|
|
|
|
|
/*
|
|
|
|
|
Constructor
|
|
|
|
|
*/
|
2018-07-04 17:20:51 +00:00
|
|
|
|
constructor() public {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
rounds.length = 2;
|
|
|
|
|
rounds[0].blockHeight = block.number;
|
|
|
|
|
currentSchellingRound = 1;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
Funds
|
|
|
|
|
*/
|
|
|
|
|
mapping(address => uint256) private funds;
|
2018-07-04 17:20:51 +00:00
|
|
|
|
function getFunds(address _owner) public view returns(bool, uint256) {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
return (true, funds[_owner]);
|
|
|
|
|
}
|
|
|
|
|
function setFunds(address _owner, uint256 _amount) isOwner external returns(bool) {
|
|
|
|
|
funds[_owner] = _amount;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
Rounds
|
|
|
|
|
*/
|
|
|
|
|
_rounds[] private rounds;
|
2018-07-04 17:20:51 +00:00
|
|
|
|
function getRound(uint256 _id) public view returns(bool, uint256, uint256, uint256, uint256, bool) {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
if ( rounds.length <= _id ) { return (false, 0, 0, 0, 0, false); }
|
|
|
|
|
else { return (true, rounds[_id].totalAboveWeight, rounds[_id].totalBelowWeight, rounds[_id].reward, rounds[_id].blockHeight, rounds[_id].voted); }
|
|
|
|
|
}
|
|
|
|
|
function pushRound(uint256 _totalAboveWeight, uint256 _totalBelowWeight, uint256 _reward, uint256 _blockHeight, bool _voted) isOwner external returns(bool, uint256) {
|
|
|
|
|
return (true, rounds.push(_rounds(_totalAboveWeight, _totalBelowWeight, _reward, _blockHeight, _voted)));
|
|
|
|
|
}
|
|
|
|
|
function setRound(uint256 _id, uint256 _totalAboveWeight, uint256 _totalBelowWeight, uint256 _reward, uint256 _blockHeight, bool _voted) isOwner external returns(bool) {
|
|
|
|
|
rounds[_id] = _rounds(_totalAboveWeight, _totalBelowWeight, _reward, _blockHeight, _voted);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-07-04 17:20:51 +00:00
|
|
|
|
function getCurrentRound() public view returns(bool, uint256) {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
return (true, rounds.length-1);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
Voter
|
|
|
|
|
*/
|
|
|
|
|
mapping(address => _voter) private voter;
|
2018-07-04 17:20:51 +00:00
|
|
|
|
function getVoter(address _owner) public view returns(bool success, uint256 roundID,
|
2017-07-05 10:28:15 +00:00
|
|
|
|
bytes32 hash, voterStatus status, bool voteResult, uint256 rewards) {
|
|
|
|
|
roundID = voter[_owner].roundID;
|
|
|
|
|
hash = voter[_owner].hash;
|
|
|
|
|
status = voter[_owner].status;
|
|
|
|
|
voteResult = voter[_owner].voteResult;
|
|
|
|
|
rewards = voter[_owner].rewards;
|
|
|
|
|
success = true;
|
|
|
|
|
}
|
|
|
|
|
function setVoter(address _owner, uint256 _roundID, bytes32 _hash, voterStatus _status, bool _voteResult, uint256 _rewards) isOwner external returns(bool) {
|
|
|
|
|
voter[_owner] = _voter(
|
|
|
|
|
_roundID,
|
|
|
|
|
_hash,
|
|
|
|
|
_status,
|
|
|
|
|
_voteResult,
|
|
|
|
|
_rewards
|
|
|
|
|
);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
Schelling Token emission
|
|
|
|
|
*/
|
|
|
|
|
mapping(uint256 => uint256) private schellingExpansion;
|
2018-07-04 17:20:51 +00:00
|
|
|
|
function getSchellingExpansion(uint256 _id) public view returns(bool, uint256) {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
return (true, schellingExpansion[_id]);
|
|
|
|
|
}
|
|
|
|
|
function setSchellingExpansion(uint256 _id, uint256 _expansion) isOwner external returns(bool) {
|
|
|
|
|
schellingExpansion[_id] = _expansion;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
Current Schelling Round
|
|
|
|
|
*/
|
|
|
|
|
uint256 private currentSchellingRound;
|
|
|
|
|
function setCurrentSchellingRound(uint256 _id) isOwner external returns(bool) {
|
|
|
|
|
currentSchellingRound = _id;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-07-04 17:20:51 +00:00
|
|
|
|
function getCurrentSchellingRound() public view returns(bool, uint256) {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
return (true, currentSchellingRound);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
contract schelling is module, announcementTypes, schellingVars {
|
|
|
|
|
/*
|
|
|
|
|
Schelling contract
|
|
|
|
|
*/
|
|
|
|
|
/*
|
|
|
|
|
module callbacks
|
|
|
|
|
*/
|
2018-09-12 14:21:43 +00:00
|
|
|
|
function replaceModule(address payable addr) external returns (bool) {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
require( super.isModuleHandler(msg.sender) );
|
|
|
|
|
require( db.replaceOwner(addr) );
|
|
|
|
|
super._replaceModule(addr);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-09-12 14:21:43 +00:00
|
|
|
|
function transferEvent(address payable from, address payable to, uint256 value) external returns (bool) {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
/*
|
2018-08-01 19:57:12 +00:00
|
|
|
|
Transaction completed. This function can be called only by the ModuleHandler.
|
2017-07-05 10:28:15 +00:00
|
|
|
|
If this contract is the receiver, the amount will be added to the prize pool of the current round.
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
@from From who
|
|
|
|
|
@to To who
|
|
|
|
|
@value Amount
|
2018-07-10 07:18:19 +00:00
|
|
|
|
@bool Was the transaction successful?
|
2017-07-05 10:28:15 +00:00
|
|
|
|
*/
|
|
|
|
|
require( super.isModuleHandler(msg.sender) );
|
|
|
|
|
if ( to == address(this) ) {
|
2018-06-21 11:58:38 +00:00
|
|
|
|
uint256 currentRound = getCurrentRound();
|
|
|
|
|
schellingVars._rounds memory round = getRound(currentRound);
|
2017-07-05 10:28:15 +00:00
|
|
|
|
round.reward += value;
|
|
|
|
|
setRound(currentRound, round);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
modifier isReady {
|
2018-06-21 11:58:38 +00:00
|
|
|
|
(bool _success, bool _active) = super.isActive();
|
2018-08-01 19:57:12 +00:00
|
|
|
|
require( _success && _active );
|
2017-07-05 10:28:15 +00:00
|
|
|
|
_;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
Schelling database functions.
|
|
|
|
|
*/
|
|
|
|
|
function getFunds(address addr) internal returns (uint256) {
|
2018-06-21 11:58:38 +00:00
|
|
|
|
(bool a, uint256 b) = db.getFunds(addr);
|
2017-07-05 10:28:15 +00:00
|
|
|
|
require( a );
|
|
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
function setFunds(address addr, uint256 amount) internal {
|
|
|
|
|
require( db.setFunds(addr, amount) );
|
|
|
|
|
}
|
2018-07-14 21:42:01 +00:00
|
|
|
|
function setVoter(address owner, _voter memory voter) internal {
|
2018-08-01 19:57:12 +00:00
|
|
|
|
require( db.setVoter(owner,
|
2017-07-05 10:28:15 +00:00
|
|
|
|
voter.roundID,
|
|
|
|
|
voter.hash,
|
|
|
|
|
voter.status,
|
|
|
|
|
voter.voteResult,
|
|
|
|
|
voter.rewards
|
|
|
|
|
) );
|
2018-07-14 21:42:01 +00:00
|
|
|
|
}
|
|
|
|
|
function getVoter(address addr) internal view returns (_voter memory) {
|
2018-06-21 11:58:38 +00:00
|
|
|
|
(bool a, uint256 b, bytes32 c, schellingVars.voterStatus d, bool e, uint256 f) = db.getVoter(addr);
|
2017-07-05 10:28:15 +00:00
|
|
|
|
require( a );
|
|
|
|
|
return _voter(b, c, d, e, f);
|
|
|
|
|
}
|
2018-07-14 21:42:01 +00:00
|
|
|
|
function setRound(uint256 id, _rounds memory round) internal {
|
2018-08-01 19:57:12 +00:00
|
|
|
|
require( db.setRound(id,
|
2017-07-05 10:28:15 +00:00
|
|
|
|
round.totalAboveWeight,
|
|
|
|
|
round.totalBelowWeight,
|
|
|
|
|
round.reward,
|
|
|
|
|
round.blockHeight,
|
|
|
|
|
round.voted
|
|
|
|
|
) );
|
|
|
|
|
}
|
2018-07-14 21:42:01 +00:00
|
|
|
|
function pushRound(_rounds memory round) internal returns (uint256) {
|
|
|
|
|
(bool a, uint256 b) = db.pushRound(
|
2017-07-05 10:28:15 +00:00
|
|
|
|
round.totalAboveWeight,
|
|
|
|
|
round.totalBelowWeight,
|
|
|
|
|
round.reward,
|
|
|
|
|
round.blockHeight,
|
|
|
|
|
round.voted
|
|
|
|
|
);
|
|
|
|
|
require( a );
|
|
|
|
|
return b;
|
|
|
|
|
}
|
2018-07-14 21:42:01 +00:00
|
|
|
|
function getRound(uint256 id) internal returns (_rounds memory) {
|
2018-06-21 11:58:38 +00:00
|
|
|
|
(bool a, uint256 b, uint256 c, uint256 d, uint256 e, bool f) = db.getRound(id);
|
2017-07-05 10:28:15 +00:00
|
|
|
|
require( a );
|
|
|
|
|
return _rounds(b, c, d, e, f);
|
|
|
|
|
}
|
|
|
|
|
function getCurrentRound() internal returns (uint256) {
|
2018-06-21 11:58:38 +00:00
|
|
|
|
(bool a, uint256 b) = db.getCurrentRound();
|
2017-07-05 10:28:15 +00:00
|
|
|
|
require( a );
|
|
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
function setCurrentSchellingRound(uint256 id) internal {
|
|
|
|
|
require( db.setCurrentSchellingRound(id) );
|
|
|
|
|
}
|
2018-07-02 09:14:28 +00:00
|
|
|
|
function getCurrentSchellingRound() internal view returns(uint256) {
|
2018-06-21 11:58:38 +00:00
|
|
|
|
(bool a, uint256 b) = db.getCurrentSchellingRound();
|
2017-07-05 10:28:15 +00:00
|
|
|
|
require( a );
|
|
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
function setSchellingExpansion(uint256 id, uint256 amount) internal {
|
|
|
|
|
require( db.setSchellingExpansion(id, amount) );
|
|
|
|
|
}
|
2018-07-02 09:14:28 +00:00
|
|
|
|
function getSchellingExpansion(uint256 id) internal view returns(uint256) {
|
2018-06-21 11:58:38 +00:00
|
|
|
|
(bool a, uint256 b) = db.getSchellingExpansion(id);
|
2017-07-05 10:28:15 +00:00
|
|
|
|
require( a );
|
|
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
Schelling module
|
|
|
|
|
*/
|
|
|
|
|
uint256 private roundBlockDelay = 720;
|
|
|
|
|
uint8 private interestCheckRounds = 7;
|
|
|
|
|
uint8 private interestCheckAboves = 4;
|
|
|
|
|
uint256 private interestRate = 300;
|
|
|
|
|
uint256 private interestRateM = 1e3;
|
|
|
|
|
|
|
|
|
|
bytes1 public aboveChar = 0x31;
|
|
|
|
|
bytes1 public belowChar = 0x30;
|
|
|
|
|
schellingDB private db;
|
2018-07-04 17:20:51 +00:00
|
|
|
|
|
2018-09-12 14:21:43 +00:00
|
|
|
|
constructor(address payable _moduleHandler, address _db, bool _forReplace) public {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
/*
|
|
|
|
|
Installation function.
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
@_moduleHandler Address of ModuleHandler.
|
|
|
|
|
@_db Address of the database.
|
|
|
|
|
@_forReplace This address will be replaced with the old one or not.
|
|
|
|
|
@_icoExpansionAddress This address can turn schelling runds during ICO.
|
|
|
|
|
*/
|
|
|
|
|
db = schellingDB(_db);
|
|
|
|
|
super.registerModuleHandler(_moduleHandler);
|
|
|
|
|
if ( ! _forReplace ) {
|
2018-07-12 18:07:16 +00:00
|
|
|
|
require( db.replaceOwner(address(this)) );
|
2017-07-05 10:28:15 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
function configure(announcementType a, uint256 b) external returns(bool) {
|
|
|
|
|
/*
|
|
|
|
|
Can be called only by the ModuleHandler.
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
@a Sort of configuration
|
|
|
|
|
@b Value
|
|
|
|
|
*/
|
|
|
|
|
require( super.isModuleHandler(msg.sender) );
|
|
|
|
|
if ( a == announcementType.schellingRoundBlockDelay ) { roundBlockDelay = b; }
|
|
|
|
|
else if ( a == announcementType.schellingCheckRounds ) { interestCheckRounds = uint8(b); }
|
|
|
|
|
else if ( a == announcementType.schellingCheckAboves ) { interestCheckAboves = uint8(b); }
|
|
|
|
|
else if ( a == announcementType.schellingRate ) { interestRate = b; }
|
|
|
|
|
else { return false; }
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
function prepareVote(bytes32 votehash, uint256 roundID) isReady noContract external {
|
|
|
|
|
/*
|
|
|
|
|
Initializing manual vote.
|
2018-08-01 19:57:12 +00:00
|
|
|
|
Only the hash of vote will be sent. (Envelope sending).
|
|
|
|
|
The address must be in default state, that is there are no vote in progress.
|
2017-07-05 10:28:15 +00:00
|
|
|
|
Votes can be sent only on the actually Schelling round.
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
@votehash Hash of the vote
|
|
|
|
|
@roundID Number of Schelling round
|
|
|
|
|
*/
|
|
|
|
|
nextRound();
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2018-06-21 11:58:38 +00:00
|
|
|
|
uint256 currentRound = getCurrentRound();
|
|
|
|
|
schellingVars._rounds memory round = getRound(currentRound);
|
2017-07-05 10:28:15 +00:00
|
|
|
|
_voter memory voter;
|
|
|
|
|
uint256 funds;
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
require( roundID == currentRound );
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
voter = getVoter(msg.sender);
|
|
|
|
|
funds = getFunds(msg.sender);
|
|
|
|
|
|
|
|
|
|
require( funds > 0 );
|
|
|
|
|
require( voter.status == voterStatus.base );
|
|
|
|
|
voter.roundID = currentRound;
|
|
|
|
|
voter.hash = votehash;
|
|
|
|
|
voter.status = voterStatus.afterPrepareVote;
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
setVoter(msg.sender, voter);
|
|
|
|
|
round.voted = true;
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
setRound(currentRound, round);
|
|
|
|
|
}
|
2018-08-07 20:12:52 +00:00
|
|
|
|
function sendVote(string calldata vote) isReady noContract external {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
/*
|
|
|
|
|
Check vote (Envelope opening)
|
|
|
|
|
Only the sent “envelopes” can be opened.
|
|
|
|
|
Envelope opening only in the next Schelling round.
|
|
|
|
|
If the vote invalid, the deposit will be lost.
|
|
|
|
|
If the “envelope” was opened later than 1,5 Schelling round, the vote is automatically invalid, and deposit can be lost.
|
|
|
|
|
Lost deposits will be 100% burned.
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
@vote Hash of the content of the vote.
|
|
|
|
|
*/
|
|
|
|
|
nextRound();
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2018-06-21 11:58:38 +00:00
|
|
|
|
uint256 currentRound = getCurrentRound();
|
2017-07-05 10:28:15 +00:00
|
|
|
|
_rounds memory round;
|
|
|
|
|
_voter memory voter;
|
|
|
|
|
uint256 funds;
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
bool lostEverything;
|
|
|
|
|
voter = getVoter(msg.sender);
|
|
|
|
|
round = getRound(voter.roundID);
|
|
|
|
|
funds = getFunds(msg.sender);
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
require( voter.status == voterStatus.afterPrepareVote );
|
|
|
|
|
require( voter.roundID < currentRound );
|
2018-06-14 10:28:33 +00:00
|
|
|
|
if ( keccak256(bytes(vote)) == voter.hash ) {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
delete voter.hash;
|
|
|
|
|
if (round.blockHeight+roundBlockDelay/2 >= block.number) {
|
|
|
|
|
if ( bytes(vote)[0] == aboveChar ) {
|
|
|
|
|
voter.status = voterStatus.afterSendVoteOk;
|
|
|
|
|
round.totalAboveWeight += funds;
|
|
|
|
|
voter.voteResult = true;
|
|
|
|
|
} else if ( bytes(vote)[0] == belowChar ) {
|
|
|
|
|
voter.status = voterStatus.afterSendVoteOk;
|
|
|
|
|
round.totalBelowWeight += funds;
|
|
|
|
|
} else { lostEverything = true; }
|
|
|
|
|
} else {
|
|
|
|
|
voter.status = voterStatus.afterSendVoteBad;
|
|
|
|
|
}
|
|
|
|
|
} else { lostEverything = true; }
|
|
|
|
|
if ( lostEverything ) {
|
|
|
|
|
require( moduleHandler(moduleHandlerAddress).burn(address(this), funds) );
|
|
|
|
|
delete funds;
|
|
|
|
|
delete voter.status;
|
|
|
|
|
}
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
setVoter(msg.sender, voter);
|
|
|
|
|
setRound(voter.roundID, round);
|
|
|
|
|
setFunds(msg.sender, funds);
|
|
|
|
|
}
|
|
|
|
|
function checkVote() isReady noContract external {
|
|
|
|
|
/*
|
|
|
|
|
Checking votes.
|
|
|
|
|
Vote checking only after the envelope opening Schelling round.
|
|
|
|
|
Deposit will be lost, if the vote wrong, or invalid.
|
|
|
|
|
The right votes take share of deposits.
|
|
|
|
|
*/
|
|
|
|
|
nextRound();
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2018-06-21 11:58:38 +00:00
|
|
|
|
uint256 currentRound = getCurrentRound();
|
2017-07-05 10:28:15 +00:00
|
|
|
|
_rounds memory round;
|
|
|
|
|
_voter memory voter;
|
|
|
|
|
uint256 funds;
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
voter = getVoter(msg.sender);
|
|
|
|
|
round = getRound(voter.roundID);
|
|
|
|
|
funds = getFunds(msg.sender);
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
|
|
|
|
require( voter.status == voterStatus.afterSendVoteOk ||
|
2017-07-05 10:28:15 +00:00
|
|
|
|
voter.status == voterStatus.afterSendVoteBad );
|
|
|
|
|
if ( round.blockHeight+roundBlockDelay/2 <= block.number ) {
|
|
|
|
|
if ( isWinner(round, voter.voteResult) && voter.status == voterStatus.afterSendVoteOk ) {
|
|
|
|
|
voter.rewards += funds * round.reward / getRoundWeight(round.totalAboveWeight, round.totalBelowWeight);
|
|
|
|
|
} else {
|
|
|
|
|
require( moduleHandler(moduleHandlerAddress).burn(address(this), funds) );
|
|
|
|
|
delete funds;
|
|
|
|
|
}
|
|
|
|
|
delete voter.status;
|
|
|
|
|
delete voter.roundID;
|
2018-07-11 23:49:00 +00:00
|
|
|
|
} else { revert(); }
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
setVoter(msg.sender, voter);
|
|
|
|
|
setFunds(msg.sender, funds);
|
|
|
|
|
}
|
|
|
|
|
function getRewards(address beneficiary) isReady noContract external {
|
|
|
|
|
/*
|
|
|
|
|
Redeem of prize.
|
|
|
|
|
The prizes will be collected here, and with this function can be transferred to the account of the user.
|
|
|
|
|
Optionally there can be an address of a beneficiary added, which address the prize will be sent to. Without beneficiary, the owner is the default address.
|
|
|
|
|
Prize will be sent from the Schelling address without any transaction fee.
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
@beneficiary Address of the beneficiary
|
|
|
|
|
*/
|
2018-06-21 11:58:38 +00:00
|
|
|
|
schellingVars._voter memory voter = getVoter(msg.sender);
|
|
|
|
|
uint256 funds = getFunds(msg.sender);
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
address _beneficiary = msg.sender;
|
2018-06-12 09:05:49 +00:00
|
|
|
|
if (beneficiary != address(0x00)) { _beneficiary = beneficiary; }
|
2017-07-05 10:28:15 +00:00
|
|
|
|
uint256 reward;
|
|
|
|
|
require( voter.rewards > 0 );
|
|
|
|
|
require( voter.status == voterStatus.base );
|
|
|
|
|
reward = voter.rewards;
|
|
|
|
|
delete voter.rewards;
|
|
|
|
|
require( moduleHandler(moduleHandlerAddress).transfer(address(this), _beneficiary, reward, false) );
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
setVoter(msg.sender, voter);
|
|
|
|
|
}
|
2018-07-02 09:14:28 +00:00
|
|
|
|
function checkReward() public view returns (uint256 reward) {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
/*
|
|
|
|
|
Withdraw of the amount of the prize (it’s only information).
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
@reward Prize
|
|
|
|
|
*/
|
2018-06-21 11:58:38 +00:00
|
|
|
|
schellingVars._voter memory voter = getVoter(msg.sender);
|
2017-07-05 10:28:15 +00:00
|
|
|
|
return voter.rewards;
|
|
|
|
|
}
|
|
|
|
|
function nextRound() internal returns (bool) {
|
|
|
|
|
/*
|
|
|
|
|
Inside function, checks the time of the Schelling round and if its needed, creates a new Schelling round.
|
|
|
|
|
*/
|
2018-06-21 11:58:38 +00:00
|
|
|
|
uint256 currentRound = getCurrentRound();
|
|
|
|
|
_rounds memory round = getRound(currentRound);
|
2017-07-05 10:28:15 +00:00
|
|
|
|
_rounds memory newRound;
|
|
|
|
|
_rounds memory prevRound;
|
2018-06-21 11:58:38 +00:00
|
|
|
|
uint256 currentSchellingRound = getCurrentSchellingRound();
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
if ( round.blockHeight+roundBlockDelay > block.number) { return false; }
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
newRound.blockHeight = block.number;
|
|
|
|
|
if ( ! round.voted ) {
|
|
|
|
|
newRound.reward = round.reward;
|
|
|
|
|
}
|
2018-07-10 07:18:19 +00:00
|
|
|
|
uint256 above;
|
2017-07-05 10:28:15 +00:00
|
|
|
|
for ( uint256 a=currentRound ; a>=currentRound-interestCheckRounds ; a-- ) {
|
|
|
|
|
if (a == 0) { break; }
|
|
|
|
|
prevRound = getRound(a);
|
2018-07-10 07:18:19 +00:00
|
|
|
|
if ( prevRound.totalAboveWeight > prevRound.totalBelowWeight ) { above++; }
|
2017-07-05 10:28:15 +00:00
|
|
|
|
}
|
|
|
|
|
uint256 expansion;
|
2018-07-10 07:18:19 +00:00
|
|
|
|
if ( above >= interestCheckAboves ) {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
expansion = getTotalSupply() * interestRate / interestRateM / 100;
|
|
|
|
|
}
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
currentSchellingRound++;
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
pushRound(newRound);
|
|
|
|
|
setSchellingExpansion(currentSchellingRound, expansion);
|
|
|
|
|
require( moduleHandler(moduleHandlerAddress).broadcastSchellingRound(currentSchellingRound, expansion) );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
function addFunds(uint256 amount) isReady noContract external {
|
|
|
|
|
/*
|
|
|
|
|
Deposit taking.
|
|
|
|
|
Every participant entry with his own deposit.
|
|
|
|
|
In case of wrong vote only this amount of deposit will be burn.
|
|
|
|
|
The deposit will be sent to the address of Schelling, charged with transaction fee.
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
@amount Amount of deposit.
|
|
|
|
|
*/
|
2018-06-21 11:58:38 +00:00
|
|
|
|
_voter memory voter = getVoter(msg.sender);
|
|
|
|
|
uint256 funds = getFunds(msg.sender);
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2018-06-21 11:58:38 +00:00
|
|
|
|
(bool a, bool b) = moduleHandler(moduleHandlerAddress).isICO();
|
2017-07-05 10:28:15 +00:00
|
|
|
|
require( b && b );
|
|
|
|
|
require( voter.status == voterStatus.base );
|
|
|
|
|
require( amount > 0 );
|
|
|
|
|
require( moduleHandler(moduleHandlerAddress).transfer(msg.sender, address(this), amount, true) );
|
|
|
|
|
funds += amount;
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
setFunds(msg.sender, funds);
|
|
|
|
|
}
|
|
|
|
|
function getFunds() isReady noContract external {
|
|
|
|
|
/*
|
|
|
|
|
Deposit withdrawn.
|
|
|
|
|
If the deposit isn’t lost, it can be withdrawn.
|
|
|
|
|
By withdrawn, the deposit will be sent from Schelling address to the users address, charged with transaction fee..
|
|
|
|
|
*/
|
2018-06-21 11:58:38 +00:00
|
|
|
|
_voter memory voter = getVoter(msg.sender);
|
|
|
|
|
uint256 funds = getFunds(msg.sender);
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
require( funds > 0 );
|
|
|
|
|
require( voter.status == voterStatus.base );
|
|
|
|
|
setFunds(msg.sender, 0);
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
require( moduleHandler(moduleHandlerAddress).transfer(address(this), msg.sender, funds, true) );
|
|
|
|
|
}
|
2018-07-02 09:14:28 +00:00
|
|
|
|
function getCurrentSchellingRoundID() public view returns (uint256) {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
/*
|
|
|
|
|
Number of actual Schelling round.
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
@uint256 Schelling round.
|
|
|
|
|
*/
|
|
|
|
|
return getCurrentSchellingRound();
|
|
|
|
|
}
|
2018-07-02 09:14:28 +00:00
|
|
|
|
function getSchellingRound(uint256 id) public view returns (uint256 expansion) {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
/*
|
|
|
|
|
Amount of token emission of the Schelling round.
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
@id Number of Schelling round
|
|
|
|
|
@expansion Amount of token emission
|
|
|
|
|
*/
|
|
|
|
|
return getSchellingExpansion(id);
|
|
|
|
|
}
|
|
|
|
|
function getRoundWeight(uint256 aboveW, uint256 belowW) internal returns (uint256) {
|
|
|
|
|
/*
|
|
|
|
|
Inside function for calculating the weights of the votes.
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
@aboveW Weight of votes: ABOVE
|
|
|
|
|
@belowW Weight of votes: BELOW
|
|
|
|
|
@uint256 Calculatet weight
|
|
|
|
|
*/
|
|
|
|
|
if ( aboveW == belowW ) {
|
|
|
|
|
return aboveW + belowW;
|
|
|
|
|
} else if ( aboveW > belowW ) {
|
|
|
|
|
return aboveW;
|
|
|
|
|
} else if ( aboveW < belowW) {
|
|
|
|
|
return belowW;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-07-14 21:42:01 +00:00
|
|
|
|
function isWinner(_rounds memory round, bool aboveVote) internal returns (bool) {
|
2017-07-05 10:28:15 +00:00
|
|
|
|
/*
|
|
|
|
|
Inside function for calculating the result of the game.
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
@round Structure of Schelling round.
|
|
|
|
|
@aboveVote Is the vote = ABOVE or not
|
|
|
|
|
@bool Result
|
|
|
|
|
*/
|
|
|
|
|
if ( round.totalAboveWeight == round.totalBelowWeight ||
|
|
|
|
|
( round.totalAboveWeight > round.totalBelowWeight && aboveVote ) ) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
function getTotalSupply() internal returns (uint256 amount) {
|
|
|
|
|
/*
|
|
|
|
|
Inside function for querying the whole amount of the tokens.
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
@uint256 Whole token amount
|
|
|
|
|
*/
|
2018-06-21 11:58:38 +00:00
|
|
|
|
(bool _success, uint256 _amount) = moduleHandler(moduleHandlerAddress).totalSupply();
|
2017-07-05 10:28:15 +00:00
|
|
|
|
require( _success );
|
|
|
|
|
return _amount;
|
|
|
|
|
}
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
function getTokenBalance(address addr) internal returns (uint256 balance) {
|
|
|
|
|
/*
|
|
|
|
|
Inner function in order to poll the token balance of the address.
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
@addr Address
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
@balance Balance of the address.
|
|
|
|
|
*/
|
2018-06-21 11:58:38 +00:00
|
|
|
|
(bool _success, uint256 _balance) = moduleHandler(moduleHandlerAddress).balanceOf(addr);
|
2017-07-05 10:28:15 +00:00
|
|
|
|
require( _success );
|
|
|
|
|
return _balance;
|
|
|
|
|
}
|
2018-08-01 19:57:12 +00:00
|
|
|
|
|
2017-07-05 10:28:15 +00:00
|
|
|
|
modifier noContract {
|
|
|
|
|
/*
|
|
|
|
|
Contract can’t call this function, only a natural address.
|
|
|
|
|
*/
|
|
|
|
|
require( msg.sender == tx.origin ); _;
|
|
|
|
|
}
|
|
|
|
|
}
|