aboutsummaryrefslogtreecommitdiffstats
path: root/test/compilationTests/corion/schelling.sol
diff options
context:
space:
mode:
Diffstat (limited to 'test/compilationTests/corion/schelling.sol')
-rw-r--r--test/compilationTests/corion/schelling.sol577
1 files changed, 577 insertions, 0 deletions
diff --git a/test/compilationTests/corion/schelling.sol b/test/compilationTests/corion/schelling.sol
new file mode 100644
index 00000000..8c8e093c
--- /dev/null
+++ b/test/compilationTests/corion/schelling.sol
@@ -0,0 +1,577 @@
+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) {
+ require( owner == 0x00 || msg.sender == owner );
+ owner = newOwner;
+ return true;
+ }
+ modifier isOwner { require( msg.sender == owner ); _; }
+ /*
+ Constructor
+ */
+ function schellingDB() {
+ rounds.length = 2;
+ rounds[0].blockHeight = block.number;
+ currentSchellingRound = 1;
+ }
+ /*
+ Funds
+ */
+ mapping(address => uint256) private funds;
+ function getFunds(address _owner) constant returns(bool, uint256) {
+ return (true, funds[_owner]);
+ }
+ function setFunds(address _owner, uint256 _amount) isOwner external returns(bool) {
+ funds[_owner] = _amount;
+ return true;
+ }
+ /*
+ Rounds
+ */
+ _rounds[] private rounds;
+ function getRound(uint256 _id) constant returns(bool, uint256, uint256, uint256, uint256, bool) {
+ 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;
+ }
+ function getCurrentRound() constant returns(bool, uint256) {
+ return (true, rounds.length-1);
+ }
+ /*
+ Voter
+ */
+ mapping(address => _voter) private voter;
+ function getVoter(address _owner) constant returns(bool success, uint256 roundID,
+ 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;
+ function getSchellingExpansion(uint256 _id) constant returns(bool, uint256) {
+ 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;
+ }
+ function getCurrentSchellingRound() constant returns(bool, uint256) {
+ return (true, currentSchellingRound);
+ }
+}
+
+contract schelling is module, announcementTypes, schellingVars {
+ /*
+ Schelling contract
+ */
+ /*
+ module callbacks
+ */
+ function replaceModule(address addr) external returns (bool) {
+ require( super.isModuleHandler(msg.sender) );
+ require( db.replaceOwner(addr) );
+ super._replaceModule(addr);
+ return true;
+ }
+ function transferEvent(address from, address to, uint256 value) external returns (bool) {
+ /*
+ Transaction completed. This function can be called only by the ModuleHandler.
+ If this contract is the receiver, the amount will be added to the prize pool of the current round.
+
+ @from From who
+ @to To who
+ @value Amount
+ @bool Was the transaction succesfull?
+ */
+ require( super.isModuleHandler(msg.sender) );
+ if ( to == address(this) ) {
+ var currentRound = getCurrentRound();
+ var round = getRound(currentRound);
+ round.reward += value;
+ setRound(currentRound, round);
+ }
+ return true;
+ }
+ modifier isReady {
+ var (_success, _active) = super.isActive();
+ require( _success && _active );
+ _;
+ }
+ /*
+ Schelling database functions.
+ */
+ function getFunds(address addr) internal returns (uint256) {
+ var (a, b) = db.getFunds(addr);
+ require( a );
+ return b;
+ }
+ function setFunds(address addr, uint256 amount) internal {
+ require( db.setFunds(addr, amount) );
+ }
+ function setVoter(address owner, _voter voter) internal {
+ require( db.setVoter(owner,
+ voter.roundID,
+ voter.hash,
+ voter.status,
+ voter.voteResult,
+ voter.rewards
+ ) );
+ }
+ function getVoter(address addr) internal returns (_voter) {
+ var (a, b, c, d, e, f) = db.getVoter(addr);
+ require( a );
+ return _voter(b, c, d, e, f);
+ }
+ function setRound(uint256 id, _rounds round) internal {
+ require( db.setRound(id,
+ round.totalAboveWeight,
+ round.totalBelowWeight,
+ round.reward,
+ round.blockHeight,
+ round.voted
+ ) );
+ }
+ function pushRound(_rounds round) internal returns (uint256) {
+ var (a, b) = db.pushRound(
+ round.totalAboveWeight,
+ round.totalBelowWeight,
+ round.reward,
+ round.blockHeight,
+ round.voted
+ );
+ require( a );
+ return b;
+ }
+ function getRound(uint256 id) internal returns (_rounds) {
+ var (a, b, c, d, e, f) = db.getRound(id);
+ require( a );
+ return _rounds(b, c, d, e, f);
+ }
+ function getCurrentRound() internal returns (uint256) {
+ var (a, b) = db.getCurrentRound();
+ require( a );
+ return b;
+ }
+ function setCurrentSchellingRound(uint256 id) internal {
+ require( db.setCurrentSchellingRound(id) );
+ }
+ function getCurrentSchellingRound() internal returns(uint256) {
+ var (a, b) = db.getCurrentSchellingRound();
+ require( a );
+ return b;
+ }
+ function setSchellingExpansion(uint256 id, uint256 amount) internal {
+ require( db.setSchellingExpansion(id, amount) );
+ }
+ function getSchellingExpansion(uint256 id) internal returns(uint256) {
+ var (a, b) = db.getSchellingExpansion(id);
+ 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;
+
+ function schelling(address _moduleHandler, address _db, bool _forReplace) {
+ /*
+ Installation function.
+
+ @_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 ) {
+ require( db.replaceOwner(this) );
+ }
+ }
+ function configure(announcementType a, uint256 b) external returns(bool) {
+ /*
+ Can be called only by the ModuleHandler.
+
+ @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.
+ 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.
+ Votes can be sent only on the actually Schelling round.
+
+ @votehash Hash of the vote
+ @roundID Number of Schelling round
+ */
+ nextRound();
+
+ var currentRound = getCurrentRound();
+ var round = getRound(currentRound);
+ _voter memory voter;
+ uint256 funds;
+
+ require( roundID == currentRound );
+
+ 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;
+
+ setVoter(msg.sender, voter);
+ round.voted = true;
+
+ setRound(currentRound, round);
+ }
+ function sendVote(string vote) isReady noContract external {
+ /*
+ 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.
+
+ @vote Hash of the content of the vote.
+ */
+ nextRound();
+
+ var currentRound = getCurrentRound();
+ _rounds memory round;
+ _voter memory voter;
+ uint256 funds;
+
+ bool lostEverything;
+ voter = getVoter(msg.sender);
+ round = getRound(voter.roundID);
+ funds = getFunds(msg.sender);
+
+ require( voter.status == voterStatus.afterPrepareVote );
+ require( voter.roundID < currentRound );
+ if ( sha3(vote) == voter.hash ) {
+ 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;
+ }
+
+ 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();
+
+ var currentRound = getCurrentRound();
+ _rounds memory round;
+ _voter memory voter;
+ uint256 funds;
+
+ voter = getVoter(msg.sender);
+ round = getRound(voter.roundID);
+ funds = getFunds(msg.sender);
+
+ require( voter.status == voterStatus.afterSendVoteOk ||
+ 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;
+ } else { throw; }
+
+ 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.
+
+ @beneficiary Address of the beneficiary
+ */
+ var voter = getVoter(msg.sender);
+ var funds = getFunds(msg.sender);
+
+ address _beneficiary = msg.sender;
+ if (beneficiary != 0x0) { _beneficiary = beneficiary; }
+ 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) );
+
+ setVoter(msg.sender, voter);
+ }
+ function checkReward() public constant returns (uint256 reward) {
+ /*
+ Withdraw of the amount of the prize (it’s only information).
+
+ @reward Prize
+ */
+ var voter = getVoter(msg.sender);
+ 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.
+ */
+ var currentRound = getCurrentRound();
+ var round = getRound(currentRound);
+ _rounds memory newRound;
+ _rounds memory prevRound;
+ var currentSchellingRound = getCurrentSchellingRound();
+
+ if ( round.blockHeight+roundBlockDelay > block.number) { return false; }
+
+ newRound.blockHeight = block.number;
+ if ( ! round.voted ) {
+ newRound.reward = round.reward;
+ }
+ uint256 aboves;
+ for ( uint256 a=currentRound ; a>=currentRound-interestCheckRounds ; a-- ) {
+ if (a == 0) { break; }
+ prevRound = getRound(a);
+ if ( prevRound.totalAboveWeight > prevRound.totalBelowWeight ) { aboves++; }
+ }
+ uint256 expansion;
+ if ( aboves >= interestCheckAboves ) {
+ expansion = getTotalSupply() * interestRate / interestRateM / 100;
+ }
+
+ currentSchellingRound++;
+
+ 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.
+
+ @amount Amount of deposit.
+ */
+ var voter = getVoter(msg.sender);
+ var funds = getFunds(msg.sender);
+
+ var (a, b) = moduleHandler(moduleHandlerAddress).isICO();
+ require( b && b );
+ require( voter.status == voterStatus.base );
+ require( amount > 0 );
+ require( moduleHandler(moduleHandlerAddress).transfer(msg.sender, address(this), amount, true) );
+ funds += amount;
+
+ 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..
+ */
+ var voter = getVoter(msg.sender);
+ var funds = getFunds(msg.sender);
+
+ require( funds > 0 );
+ require( voter.status == voterStatus.base );
+ setFunds(msg.sender, 0);
+
+ require( moduleHandler(moduleHandlerAddress).transfer(address(this), msg.sender, funds, true) );
+ }
+ function getCurrentSchellingRoundID() public constant returns (uint256) {
+ /*
+ Number of actual Schelling round.
+
+ @uint256 Schelling round.
+ */
+ return getCurrentSchellingRound();
+ }
+ function getSchellingRound(uint256 id) public constant returns (uint256 expansion) {
+ /*
+ Amount of token emission of the Schelling round.
+
+ @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.
+
+ @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;
+ }
+ }
+ function isWinner(_rounds round, bool aboveVote) internal returns (bool) {
+ /*
+ Inside function for calculating the result of the game.
+
+ @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;
+ }
+
+ function getTotalSupply() internal returns (uint256 amount) {
+ /*
+ Inside function for querying the whole amount of the tokens.
+
+ @uint256 Whole token amount
+ */
+ var (_success, _amount) = moduleHandler(moduleHandlerAddress).totalSupply();
+ require( _success );
+ return _amount;
+ }
+
+ function getTokenBalance(address addr) internal returns (uint256 balance) {
+ /*
+ Inner function in order to poll the token balance of the address.
+
+ @addr Address
+
+ @balance Balance of the address.
+ */
+ var (_success, _balance) = moduleHandler(moduleHandlerAddress).balanceOf(addr);
+ require( _success );
+ return _balance;
+ }
+
+ modifier noContract {
+ /*
+ Contract can’t call this function, only a natural address.
+ */
+ require( msg.sender == tx.origin ); _;
+ }
+}