@gooddollar/goodcontracts
Version:
GoodDollar Contracts
924 lines • 3.52 MB
JSON
{
"contractName": "GenesisProtocolLogic",
"abi": [
{
"constant": true,
"inputs": [
{
"name": "",
"type": "bytes32"
}
],
"name": "parameters",
"outputs": [
{
"name": "queuedVoteRequiredPercentage",
"type": "uint256"
},
{
"name": "queuedVotePeriodLimit",
"type": "uint256"
},
{
"name": "boostedVotePeriodLimit",
"type": "uint256"
},
{
"name": "preBoostedVotePeriodLimit",
"type": "uint256"
},
{
"name": "thresholdConst",
"type": "uint256"
},
{
"name": "limitExponentValue",
"type": "uint256"
},
{
"name": "quietEndingPeriod",
"type": "uint256"
},
{
"name": "proposingRepReward",
"type": "uint256"
},
{
"name": "votersReputationLossRatio",
"type": "uint256"
},
{
"name": "minimumDaoBounty",
"type": "uint256"
},
{
"name": "daoBountyConst",
"type": "uint256"
},
{
"name": "activationTime",
"type": "uint256"
},
{
"name": "voteOnBehalf",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "NO",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "proposalsCnt",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "bytes32"
}
],
"name": "proposals",
"outputs": [
{
"name": "organizationId",
"type": "bytes32"
},
{
"name": "callbacks",
"type": "address"
},
{
"name": "state",
"type": "uint8"
},
{
"name": "winningVote",
"type": "uint256"
},
{
"name": "proposer",
"type": "address"
},
{
"name": "currentBoostedVotePeriodLimit",
"type": "uint256"
},
{
"name": "paramsHash",
"type": "bytes32"
},
{
"name": "daoBountyRemain",
"type": "uint256"
},
{
"name": "daoBounty",
"type": "uint256"
},
{
"name": "totalStakes",
"type": "uint256"
},
{
"name": "confidenceThreshold",
"type": "uint256"
},
{
"name": "expirationCallBountyPercentage",
"type": "uint256"
},
{
"name": "daoRedeemItsWinnings",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_proposalId",
"type": "bytes32"
},
{
"name": "_vote",
"type": "uint256"
},
{
"name": "_rep",
"type": "uint256"
},
{
"name": "_voter",
"type": "address"
}
],
"name": "vote",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getAllowedRangeOfChoices",
"outputs": [
{
"name": "min",
"type": "uint256"
},
{
"name": "max",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "pure",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "isAbstainAllow",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "pure",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "stakingToken",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_proposalId",
"type": "bytes32"
}
],
"name": "cancelVote",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "NUM_OF_CHOICES",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_proposalId",
"type": "bytes32"
}
],
"name": "getNumberOfChoices",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "YES",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_proposalId",
"type": "bytes32"
},
{
"name": "_choice",
"type": "uint256"
}
],
"name": "voteStatus",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "bytes32"
}
],
"name": "organizations",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "bytes32"
}
],
"name": "averagesDownstakesOfBoosted",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_proposalId",
"type": "bytes32"
}
],
"name": "isVotable",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "bytes32"
}
],
"name": "orgBoostedProposalsCnt",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_stakingToken",
"type": "address"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_proposalId",
"type": "bytes32"
},
{
"indexed": true,
"name": "_organization",
"type": "address"
},
{
"indexed": true,
"name": "_staker",
"type": "address"
},
{
"indexed": false,
"name": "_vote",
"type": "uint256"
},
{
"indexed": false,
"name": "_amount",
"type": "uint256"
}
],
"name": "Stake",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_proposalId",
"type": "bytes32"
},
{
"indexed": true,
"name": "_organization",
"type": "address"
},
{
"indexed": true,
"name": "_beneficiary",
"type": "address"
},
{
"indexed": false,
"name": "_amount",
"type": "uint256"
}
],
"name": "Redeem",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_proposalId",
"type": "bytes32"
},
{
"indexed": true,
"name": "_organization",
"type": "address"
},
{
"indexed": true,
"name": "_beneficiary",
"type": "address"
},
{
"indexed": false,
"name": "_amount",
"type": "uint256"
}
],
"name": "RedeemDaoBounty",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_proposalId",
"type": "bytes32"
},
{
"indexed": true,
"name": "_organization",
"type": "address"
},
{
"indexed": true,
"name": "_beneficiary",
"type": "address"
},
{
"indexed": false,
"name": "_amount",
"type": "uint256"
}
],
"name": "RedeemReputation",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_proposalId",
"type": "bytes32"
},
{
"indexed": false,
"name": "_proposalState",
"type": "uint8"
}
],
"name": "StateChange",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_proposalId",
"type": "bytes32"
},
{
"indexed": false,
"name": "_executionState",
"type": "uint8"
}
],
"name": "GPExecuteProposal",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_proposalId",
"type": "bytes32"
},
{
"indexed": true,
"name": "_beneficiary",
"type": "address"
},
{
"indexed": false,
"name": "_amount",
"type": "uint256"
}
],
"name": "ExpirationCallBounty",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_proposalId",
"type": "bytes32"
},
{
"indexed": false,
"name": "_confidenceThreshold",
"type": "uint256"
}
],
"name": "ConfidenceLevelChange",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_proposalId",
"type": "bytes32"
},
{
"indexed": true,
"name": "_organization",
"type": "address"
},
{
"indexed": false,
"name": "_numOfChoices",
"type": "uint256"
},
{
"indexed": false,
"name": "_proposer",
"type": "address"
},
{
"indexed": false,
"name": "_paramsHash",
"type": "bytes32"
}
],
"name": "NewProposal",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_proposalId",
"type": "bytes32"
},
{
"indexed": true,
"name": "_organization",
"type": "address"
},
{
"indexed": false,
"name": "_decision",
"type": "uint256"
},
{
"indexed": false,
"name": "_totalReputation",
"type": "uint256"
}
],
"name": "ExecuteProposal",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_proposalId",
"type": "bytes32"
},
{
"indexed": true,
"name": "_organization",
"type": "address"
},
{
"indexed": true,
"name": "_voter",
"type": "address"
},
{
"indexed": false,
"name": "_vote",
"type": "uint256"
},
{
"indexed": false,
"name": "_reputation",
"type": "uint256"
}
],
"name": "VoteProposal",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_proposalId",
"type": "bytes32"
},
{
"indexed": true,
"name": "_organization",
"type": "address"
}
],
"name": "CancelProposal",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_proposalId",
"type": "bytes32"
},
{
"indexed": true,
"name": "_organization",
"type": "address"
},
{
"indexed": true,
"name": "_voter",
"type": "address"
}
],
"name": "CancelVoting",
"type": "event"
},
{
"constant": false,
"inputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "_paramsHash",
"type": "bytes32"
},
{
"name": "_proposer",
"type": "address"
},
{
"name": "_organization",
"type": "address"
}
],
"name": "propose",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_proposalId",
"type": "bytes32"
}
],
"name": "executeBoosted",
"outputs": [
{
"name": "expirationCallBounty",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_params",
"type": "uint256[11]"
},
{
"name": "_voteOnBehalf",
"type": "address"
}
],
"name": "setParameters",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_proposalId",
"type": "bytes32"
},
{
"name": "_beneficiary",
"type": "address"
}
],
"name": "redeem",
"outputs": [
{
"name": "rewards",
"type": "uint256[3]"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_proposalId",
"type": "bytes32"
},
{
"name": "_beneficiary",
"type": "address"
}
],
"name": "redeemDaoBounty",
"outputs": [
{
"name": "redeemedAmount",
"type": "uint256"
},
{
"name": "potentialAmount",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_proposalId",
"type": "bytes32"
}
],
"name": "shouldBoost",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_paramsHash",
"type": "bytes32"
},
{
"name": "_organizationId",
"type": "bytes32"
}
],
"name": "threshold",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_params",
"type": "uint256[11]"
},
{
"name": "_voteOnBehalf",
"type": "address"
}
],
"name": "getParametersHash",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "pure",
"type": "function"
}
],
"metadata": "",
"bytecode": "0x",
"deployedBytecode": "0x",
"sourceMap": "",
"deployedSourceMap": "",
"source": "pragma solidity ^0.5.4;\n\nimport \"./IntVoteInterface.sol\";\nimport { RealMath } from \"../libs/RealMath.sol\";\nimport \"./VotingMachineCallbacksInterface.sol\";\nimport \"./ProposalExecuteInterface.sol\";\nimport \"openzeppelin-solidity/contracts/math/SafeMath.sol\";\nimport \"openzeppelin-solidity/contracts/math/Math.sol\";\nimport \"openzeppelin-solidity/contracts/token/ERC20/IERC20.sol\";\nimport \"openzeppelin-solidity/contracts/utils/Address.sol\";\n\n\n\n/**\n * @title GenesisProtocol implementation -an organization's voting machine scheme.\n */\ncontract GenesisProtocolLogic is IntVoteInterface {\n using SafeMath for uint256;\n using Math for uint256;\n using RealMath for uint216;\n using RealMath for uint256;\n using Address for address;\n\n enum ProposalState { None, ExpiredInQueue, Executed, Queued, PreBoosted, Boosted, QuietEndingPeriod}\n enum ExecutionState { None, QueueBarCrossed, QueueTimeOut, PreBoostedBarCrossed, BoostedTimeOut, BoostedBarCrossed}\n\n //Organization's parameters\n struct Parameters {\n uint256 queuedVoteRequiredPercentage; // the absolute vote percentages bar.\n uint256 queuedVotePeriodLimit; //the time limit for a proposal to be in an absolute voting mode.\n uint256 boostedVotePeriodLimit; //the time limit for a proposal to be in boost mode.\n uint256 preBoostedVotePeriodLimit; //the time limit for a proposal\n //to be in an preparation state (stable) before boosted.\n uint256 thresholdConst; //constant for threshold calculation .\n //threshold =thresholdConst ** (numberOfBoostedProposals)\n uint256 limitExponentValue;// an upper limit for numberOfBoostedProposals\n //in the threshold calculation to prevent overflow\n uint256 quietEndingPeriod; //quite ending period\n uint256 proposingRepReward;//proposer reputation reward.\n uint256 votersReputationLossRatio;//Unsuccessful pre booster\n //voters lose votersReputationLossRatio% of their reputation.\n uint256 minimumDaoBounty;\n uint256 daoBountyConst;//The DAO downstake for each proposal is calculate according to the formula\n //(daoBountyConst * averageBoostDownstakes)/100 .\n uint256 activationTime;//the point in time after which proposals can be created.\n //if this address is set so only this address is allowed to vote of behalf of someone else.\n address voteOnBehalf;\n }\n\n struct Voter {\n uint256 vote; // YES(1) ,NO(2)\n uint256 reputation; // amount of voter's reputation\n bool preBoosted;\n }\n\n struct Staker {\n uint256 vote; // YES(1) ,NO(2)\n uint256 amount; // amount of staker's stake\n uint256 amount4Bounty;// amount of staker's stake used for bounty reward calculation.\n }\n\n struct Proposal {\n bytes32 organizationId; // the organization unique identifier the proposal is target to.\n address callbacks; // should fulfill voting callbacks interface.\n ProposalState state;\n uint256 winningVote; //the winning vote.\n address proposer;\n //the proposal boosted period limit . it is updated for the case of quiteWindow mode.\n uint256 currentBoostedVotePeriodLimit;\n bytes32 paramsHash;\n uint256 daoBountyRemain; //use for checking sum zero bounty claims.it is set at the proposing time.\n uint256 daoBounty;\n uint256 totalStakes;// Total number of tokens staked which can be redeemable by stakers.\n uint256 confidenceThreshold;\n //The percentage from upper stakes which the caller for the expiration was given.\n uint256 expirationCallBountyPercentage;\n uint[3] times; //times[0] - submittedTime\n //times[1] - boostedPhaseTime\n //times[2] -preBoostedPhaseTime;\n bool daoRedeemItsWinnings;\n // vote reputation\n mapping(uint256 => uint256 ) votes;\n // vote reputation\n mapping(uint256 => uint256 ) preBoostedVotes;\n // address voter\n mapping(address => Voter ) voters;\n // vote stakes\n mapping(uint256 => uint256 ) stakes;\n // address staker\n mapping(address => Staker ) stakers;\n }\n\n event Stake(bytes32 indexed _proposalId,\n address indexed _organization,\n address indexed _staker,\n uint256 _vote,\n uint256 _amount\n );\n\n event Redeem(bytes32 indexed _proposalId,\n address indexed _organization,\n address indexed _beneficiary,\n uint256 _amount\n );\n\n event RedeemDaoBounty(bytes32 indexed _proposalId,\n address indexed _organization,\n address indexed _beneficiary,\n uint256 _amount\n );\n\n event RedeemReputation(bytes32 indexed _proposalId,\n address indexed _organization,\n address indexed _beneficiary,\n uint256 _amount\n );\n\n event StateChange(bytes32 indexed _proposalId, ProposalState _proposalState);\n event GPExecuteProposal(bytes32 indexed _proposalId, ExecutionState _executionState);\n event ExpirationCallBounty(bytes32 indexed _proposalId, address indexed _beneficiary, uint256 _amount);\n event ConfidenceLevelChange(bytes32 indexed _proposalId, uint256 _confidenceThreshold);\n\n mapping(bytes32=>Parameters) public parameters; // A mapping from hashes to parameters\n mapping(bytes32=>Proposal) public proposals; // Mapping from the ID of the proposal to the proposal itself.\n mapping(bytes32=>uint) public orgBoostedProposalsCnt;\n //organizationId => organization\n mapping(bytes32 => address ) public organizations;\n //organizationId => averageBoostDownstakes\n mapping(bytes32 => uint256 ) public averagesDownstakesOfBoosted;\n uint256 constant public NUM_OF_CHOICES = 2;\n uint256 constant public NO = 2;\n uint256 constant public YES = 1;\n uint256 public proposalsCnt; // Total number of proposals\n IERC20 public stakingToken;\n address constant private GEN_TOKEN_ADDRESS = 0x543Ff227F64Aa17eA132Bf9886cAb5DB55DCAddf;\n uint256 constant private MAX_BOOSTED_PROPOSALS = 4096;\n\n /**\n * @dev Constructor\n */\n constructor(IERC20 _stakingToken) public {\n //The GEN token (staking token) address is hard coded in the contract by GEN_TOKEN_ADDRESS .\n //This will work for a network which already hosted the GEN token on this address (e.g mainnet).\n //If such contract address does not exist in the network (e.g ganache)\n //the contract will use the _stakingToken param as the\n //staking token address.\n if (address(GEN_TOKEN_ADDRESS).isContract()) {\n stakingToken = IERC20(GEN_TOKEN_ADDRESS);\n } else {\n stakingToken = _stakingToken;\n }\n }\n\n /**\n * @dev Check that the proposal is votable\n * a proposal is votable if it is in one of the following states:\n * PreBoosted,Boosted,QuietEndingPeriod or Queued\n */\n modifier votable(bytes32 _proposalId) {\n require(_isVotable(_proposalId));\n _;\n }\n\n /**\n * @dev register a new proposal with the given parameters. Every proposal has a unique ID which is being\n * generated by calculating keccak256 of a incremented counter.\n * @param _paramsHash parameters hash\n * @param _proposer address\n * @param _organization address\n */\n function propose(uint256, bytes32 _paramsHash, address _proposer, address _organization)\n external\n returns(bytes32)\n {\n // solhint-disable-next-line not-rely-on-time\n require(now > parameters[_paramsHash].activationTime, \"not active yet\");\n //Check parameters existence.\n require(parameters[_paramsHash].queuedVoteRequiredPercentage >= 50);\n // Generate a unique ID:\n bytes32 proposalId = keccak256(abi.encodePacked(this, proposalsCnt));\n proposalsCnt = proposalsCnt.add(1);\n // Open proposal:\n Proposal memory proposal;\n proposal.callbacks = msg.sender;\n proposal.organizationId = keccak256(abi.encodePacked(msg.sender, _organization));\n\n proposal.state = ProposalState.Queued;\n // solhint-disable-next-line not-rely-on-time\n proposal.times[0] = now;//submitted time\n proposal.currentBoostedVotePeriodLimit = parameters[_paramsHash].boostedVotePeriodLimit;\n proposal.proposer = _proposer;\n proposal.winningVote = NO;\n proposal.paramsHash = _paramsHash;\n if (organizations[proposal.organizationId] == address(0)) {\n if (_organization == address(0)) {\n organizations[proposal.organizationId] = msg.sender;\n } else {\n organizations[proposal.organizationId] = _organization;\n }\n }\n //calc dao bounty\n uint256 daoBounty =\n parameters[_paramsHash].daoBountyConst.mul(averagesDownstakesOfBoosted[proposal.organizationId]).div(100);\n if (daoBounty < parameters[_paramsHash].minimumDaoBounty) {\n proposal.daoBountyRemain = parameters[_paramsHash].minimumDaoBounty;\n } else {\n proposal.daoBountyRemain = daoBounty;\n }\n proposal.totalStakes = proposal.daoBountyRemain;\n proposals[proposalId] = proposal;\n proposals[proposalId].stakes[NO] = proposal.daoBountyRemain;//dao downstake on the proposal\n\n emit NewProposal(proposalId, organizations[proposal.organizationId], NUM_OF_CHOICES, _proposer, _paramsHash);\n return proposalId;\n }\n\n /**\n * @dev executeBoosted try to execute a boosted or QuietEndingPeriod proposal if it is expired\n * @param _proposalId the id of the proposal\n * @return uint256 expirationCallBounty the bounty amount for the expiration call\n */\n function executeBoosted(bytes32 _proposalId) external returns(uint256 expirationCallBounty) {\n Proposal storage proposal = proposals[_proposalId];\n require(proposal.state == ProposalState.Boosted || proposal.state == ProposalState.QuietEndingPeriod,\n \"proposal state in not Boosted nor QuietEndingPeriod\");\n require(_execute(_proposalId), \"proposal need to expire\");\n uint256 expirationCallBountyPercentage =\n // solhint-disable-next-line not-rely-on-time\n (uint(1).add(now.sub(proposal.currentBoostedVotePeriodLimit.add(proposal.times[1])).div(15)));\n if (expirationCallBountyPercentage > 100) {\n expirationCallBountyPercentage = 100;\n }\n proposal.expirationCallBountyPercentage = expirationCallBountyPercentage;\n expirationCallBounty = expirationCallBountyPercentage.mul(proposal.stakes[YES]).div(100);\n require(stakingToken.transfer(msg.sender, expirationCallBounty), \"transfer to msg.sender failed\");\n emit ExpirationCallBounty(_proposalId, msg.sender, expirationCallBounty);\n }\n\n /**\n * @dev hash the parameters, save them if necessary, and return the hash value\n * @param _params a parameters array\n * _params[0] - _queuedVoteRequiredPercentage,\n * _params[1] - _queuedVotePeriodLimit, //the time limit for a proposal to be in an absolute voting mode.\n * _params[2] - _boostedVotePeriodLimit, //the time limit for a proposal to be in an relative voting mode.\n * _params[3] - _preBoostedVotePeriodLimit, //the time limit for a proposal to be in an preparation\n * state (stable) before boosted.\n * _params[4] -_thresholdConst\n * _params[5] -_quietEndingPeriod\n * _params[6] -_proposingRepReward\n * _params[7] -_votersReputationLossRatio\n * _params[8] -_minimumDaoBounty\n * _params[9] -_daoBountyConst\n * _params[10] -_activationTime\n * @param _voteOnBehalf - authorized to vote on behalf of others.\n */\n function setParameters(\n uint[11] calldata _params, //use array here due to stack too deep issue.\n address _voteOnBehalf\n )\n external\n returns(bytes32)\n {\n require(_params[0] <= 100 && _params[0] >= 50, \"50 <= queuedVoteRequiredPercentage <= 100\");\n require(_params[4] <= 16000 && _params[4] > 1000, \"1000 < thresholdConst <= 16000\");\n require(_params[7] <= 100, \"votersReputationLossRatio <= 100\");\n require(_params[2] >= _params[5], \"boostedVotePeriodLimit >= quietEndingPeriod\");\n require(_params[8] > 0, \"minimumDaoBounty should be > 0\");\n require(_params[9] > 0, \"daoBountyConst should be > 0\");\n\n bytes32 paramsHash = getParametersHash(_params, _voteOnBehalf);\n //set a limit for power for a given alpha to prevent overflow\n uint256 limitExponent = 172;//for alpha less or equal 2\n uint256 j = 2;\n for (uint256 i = 2000; i < 16000; i = i*2) {\n if ((_params[4] > i) && (_params[4] <= i*2)) {\n limitExponent = limitExponent/j;\n break;\n }\n j++;\n }\n\n parameters[paramsHash] = Parameters({\n queuedVoteRequiredPercentage: _params[0],\n queuedVotePeriodLimit: _params[1],\n boostedVotePeriodLimit: _params[2],\n preBoostedVotePeriodLimit: _params[3],\n thresholdConst:uint216(_params[4]).fraction(uint216(1000)),\n limitExponentValue:limitExponent,\n quietEndingPeriod: _params[5],\n proposingRepReward: _params[6],\n votersReputationLossRatio:_params[7],\n minimumDaoBounty:_params[8],\n daoBountyConst:_params[9],\n activationTime:_params[10],\n voteOnBehalf:_voteOnBehalf\n });\n return paramsHash;\n }\n\n /**\n * @dev redeem a reward for a successful stake, vote or proposing.\n * The function use a beneficiary address as a parameter (and not msg.sender) to enable\n * users to redeem on behalf of someone else.\n * @param _proposalId the ID of the proposal\n * @param _beneficiary - the beneficiary address\n * @return rewards -\n * [0] stakerTokenReward\n * [1] voterReputationReward\n * [2] proposerReputationReward\n */\n // solhint-disable-next-line function-max-lines,code-complexity\n function redeem(bytes32 _proposalId, address _beneficiary) public returns (uint[3] memory rewards) {\n Proposal storage proposal = proposals[_proposalId];\n require((proposal.state == ProposalState.Executed)||(proposal.state == ProposalState.ExpiredInQueue),\n \"Proposal should be Executed or ExpiredInQueue\");\n Parameters memory params = parameters[proposal.paramsHash];\n uint256 lostReputation;\n if (proposal.winningVote == YES) {\n lostReputation = proposal.preBoostedVotes[NO];\n } else {\n lostReputation = proposal.preBoostedVotes[YES];\n }\n lostReputation = (lostReputation.mul(params.votersReputationLossRatio))/100;\n //as staker\n Staker storage staker = proposal.stakers[_beneficiary];\n uint256 totalStakes = proposal.stakes[NO].add(proposal.stakes[YES]);\n uint256 totalWinningStakes = proposal.stakes[proposal.winningVote];\n\n if (staker.amount > 0) {\n uint256 totalStakesLeftAfterCallBounty =\n totalStakes.sub(proposal.expirationCallBountyPercentage.mul(proposal.stakes[YES]).div(100));\n if (proposal.state == ProposalState.ExpiredInQueue) {\n //Stakes of a proposal that expires in Queue are sent back to stakers\n rewards[0] = staker.amount;\n } else if (staker.vote == proposal.winningVote) {\n if (staker.vote == YES) {\n if (proposal.daoBounty < totalStakesLeftAfterCallBounty) {\n uint256 _totalStakes = totalStakesLeftAfterCallBounty.sub(proposal.daoBounty);\n rewards[0] = (staker.amount.mul(_totalStakes))/totalWinningStakes;\n }\n } else {\n rewards[0] = (staker.amount.mul(totalStakesLeftAfterCallBounty))/totalWinningStakes;\n }\n }\n staker.amount = 0;\n }\n //dao redeem its winnings\n if (proposal.daoRedeemItsWinnings == false &&\n _beneficiary == organizations[proposal.organizationId] &&\n proposal.state != ProposalState.ExpiredInQueue &&\n proposal.winningVote == NO) {\n rewards[0] =\n rewards[0].add((proposal.daoBounty.mul(totalStakes))/totalWinningStakes).sub(proposal.daoBounty);\n proposal.daoRedeemItsWinnings = true;\n }\n\n //as voter\n Voter storage voter = proposal.voters[_beneficiary];\n if ((voter.reputation != 0) && (voter.preBoosted)) {\n if (proposal.state == ProposalState.ExpiredInQueue) {\n //give back reputation for the voter\n rewards[1] = ((voter.reputation.mul(params.votersReputationLossRatio))/100);\n } else if (proposal.winningVote == voter.vote) {\n rewards[1] = ((voter.reputation.mul(params.votersReputationLossRatio))/100)\n .add((voter.reputation.mul(lostReputation))/proposal.preBoostedVotes[proposal.winningVote]);\n }\n voter.reputation = 0;\n }\n //as proposer\n if ((proposal.proposer == _beneficiary)&&(proposal.winningVote == YES)&&(proposal.proposer != address(0))) {\n rewards[2] = params.proposingRepReward;\n proposal.proposer = address(0);\n }\n if (rewards[0] != 0) {\n proposal.totalStakes = proposal.totalStakes.sub(rewards[0]);\n require(stakingToken.transfer(_beneficiary, rewards[0]), \"transfer to beneficiary failed\");\n emit Redeem(_proposalId, organizations[proposal.organizationId], _beneficiary, rewards[0]);\n }\n if (rewards[1].add(rewards[2]) != 0) {\n VotingMachineCallbacksInterface(proposal.callbacks)\n .mintReputation(rewards[1].add(rewards[2]), _beneficiary, _proposalId);\n emit RedeemReputation(\n _proposalId,\n organizations[proposal.organizationId],\n _beneficiary,\n rewards[1].add(rewards[2])\n );\n }\n }\n\n /**\n * @dev redeemDaoBounty a reward for a successful stake.\n * The function use a beneficiary address as a parameter (and not msg.sender) to enable\n * users to redeem on behalf of someone else.\n * @param _proposalId the ID of the proposal\n * @param _beneficiary - the beneficiary address\n * @return redeemedAmount - redeem token amount\n * @return potentialAmount - potential redeem token amount(if there is enough tokens bounty at the organization )\n */\n function redeemDaoBounty(bytes32 _proposalId, address _beneficiary)\n public\n returns(uint256 redeemedAmount, uint256 potentialAmount) {\n Proposal storage proposal = proposals[_proposalId];\n require(proposal.state == ProposalState.Executed);\n uint256 totalWinningStakes = proposal.stakes[proposal.winningVote];\n Staker storage staker = proposal.stakers[_beneficiary];\n if (\n (staker.amount4Bounty > 0)&&\n (staker.vote == proposal.winningVote)&&\n (proposal.winningVote == YES)&&\n (totalWinningStakes != 0)) {\n //as staker\n potentialAmount = (staker.amount4Bounty * proposal.daoBounty)/totalWinningStakes;\n }\n if ((potentialAmount != 0)&&\n (VotingMachineCallbacksInterface(proposal.callbacks)\n .balanceOfStakingToken(stakingToken, _proposalId) >= potentialAmount)) {\n staker.amount4Bounty = 0;\n proposal.daoBountyRemain = proposal.daoBountyRemain.sub(potentialAmount);\n require(\n VotingMachineCallbacksInterface(proposal.callbacks)\n .stakingTokenTransfer(stakingToken, _beneficiary, potentialAmount, _proposalId));\n redeemedAmount = potentialAmount;\n emit RedeemDaoBounty(_proposalId, organizations[proposal.organizationId], _beneficiary, redeemedAmount);\n }\n }\n\n /**\n * @dev shouldBoost check if a proposal should be shifted to boosted phase.\n * @param _proposalId the ID of the proposal\n * @return bool true or false.\n */\n function shouldBoost(bytes32 _proposalId) public view returns(bool) {\n Proposal memory proposal = proposals[_proposalId];\n return (_score(_proposalId) > threshold(proposal.paramsHash, proposal.organizationId));\n }\n\n /**\n * @dev threshold return the organization's score threshold which required by\n * a proposal to shift to boosted state.\n * This threshold is dynamically set and it depend on the number of boosted proposal.\n * @param _organizationId the organization identifier\n * @param _paramsHash the organization parameters hash\n * @return uint256 organization's score threshold as real number.\n */\n function threshold(bytes32 _paramsHash, bytes32 _organizationId) public view returns(uint256) {\n uint256 power = orgBoostedProposalsCnt[_organizationId];\n Parameters storage params = parameters[_paramsHash];\n\n if (power > params.limitExponentValue) {\n power = params.limitExponentValue;\n }\n\n return params.thresholdConst.pow(power);\n }\n\n /**\n * @dev hashParameters returns a hash of the given parameters\n */\n function getParametersHash(\n uint[11] memory _params,//use array here due to stack too deep issue.\n address _voteOnBehalf\n )\n public\n pure\n returns(bytes32)\n {\n //double call to keccak256 to avoid deep stack issue when call with too many params.\n return keccak256(\n abi.encodePacked(\n keccak256(\n abi.encodePacked(\n _params[0],\n _params[1],\n _params[2],\n _params[3],\n _params[4],\n _params[5],\n _params[6],\n _params[7],\n _params[8],\n _params[9],\n _params[10])\n ),\n _voteOnBehalf\n ));\n }\n\n /**\n * @dev execute check if the proposal has been decided, and if so, execute the proposal\n * @param _proposalId the id of the proposal\n * @return bool true - the proposal has been executed\n * false - otherwise.\n */\n // solhint-disable-next-line function-max-lines,code-complexity\n function _execute(bytes32 _proposalId) internal votable(_proposalId) returns(bool) {\n Proposal storage proposal = proposals[_proposalId];\n Parameters memory params = parameters[proposal.paramsHash];\n Proposal memory tmpProposal = proposal;\n uint256 totalReputation =\n VotingMachineCallbacksInterface(proposal.callbacks).getTotalReputationSupply(_proposalId);\n //first divide by 100 to prevent overflow\n uint256 executionBar = (totalReputation/100) * params.queuedVoteRequiredPercentage;\n ExecutionState executionState = ExecutionState.None;\n uint256 averageDownstakesOfBoosted;\n uint256 confidenceThreshold;\n\n if (proposal.votes[proposal.winningVote] > executionBar) {\n // someone crossed the absolute vote execution bar.\n if (proposal.state == ProposalState.Queued) {\n executionState = ExecutionState.QueueBarCrossed;\n } else if (proposal.state == ProposalState.PreBoosted) {\n executionState = ExecutionState.PreBoostedBarCrossed;\n } else {\n executionState = ExecutionState.BoostedBarCrossed;\n }\n proposal.state = ProposalState.Executed;\n } else {\n if (proposal.state == ProposalState.Queued) {\n // solhint-disable-next-line not-rely-on-time\n if ((now - proposal.times[0]) >= params.queuedVotePeriodLimit) {\n proposal.state = ProposalState.ExpiredInQueue;\n proposal.winningVote = NO;\n executionState = ExecutionState.QueueTimeOut;\n } else {\n confidenceThreshold = threshold(proposal.paramsHash, proposal.organizationId);\n if (_score(_proposalId) > confidenceThreshold) {\n //change proposal mode to PreBoosted mode.\n proposal.state = ProposalState.PreBoosted;\n // solhint-disable-next-line not-rely-on-time\n proposal.times[2] = now;\n proposal.confidenceThreshold = confidenceThreshold;\n }\n }\n }\n\n if (proposal.state == ProposalState.PreBoosted) {\n confidenceThreshold = threshold(proposal.paramsHash, proposal.organizationId);\n // solhint-disable-next-line not-rely-on-time\n if ((now - proposal.times[2]) >= params.preBoostedVotePeriodLimit) {\n if (_score(_proposalId) > confidenceThreshold) {\n if (orgBoostedProposalsCnt[proposal.organizationId] < MAX_BOOSTED_PROPOSALS) {\n //change proposal mode to Boosted mode.\n proposal.state = ProposalState.Boosted;\n // solhint-disable-next-line not-rely-on-time\n proposal.times[1] = now;\n orgBoostedProposalsCnt[proposal.organizationId]++;\n //add a value to average -> average = average + ((value - average) / nbValues)\n averageDownstakesOfBoosted = averagesDownstakesOfBoosted[proposal.organizationId];\n // solium-disable-next-line indentation\n averagesDownstakesOfBoosted[proposal.organizationId] =\n uint256(int256(averageDownstakesOfBoosted) +\n ((int256(proposal.stakes[NO])-int256(averageDownstakesOfBoosted))/\n int256(orgBoostedProposalsCnt[proposal.organizationId])));\n }\n } else {\n proposal.state = ProposalState.Queued;\n }\n } else { //check the Confidence level is stable\n uint256 proposalScore = _score(_proposalId);\n if (proposalScore <= proposal.confidenceThreshold.min(confidenceThreshold)) {\n proposal.state = ProposalState.Queued;\n } else if (proposal.confidenceThreshold > proposalScore) {\n proposal.confidenceThreshold = confidenceThreshold;\n emit ConfidenceLevelChange(_proposalId, confidenceThreshold);\n }\n }\n }\n }\n\n if ((proposal.state == ProposalState.Boosted) ||\n (proposal.state == ProposalState.QuietEndingPeriod)) {\n // solhint-disable-next-line not-rely-on-time\n if ((now - proposal.times[1]) >= proposal.currentBoostedVotePeriodLimit) {\n proposal.state = ProposalState.Executed;\n executionState = ExecutionState.BoostedTimeOut;\n }\n }\n\n if (executionState != ExecutionState.None) {\n if ((executionState == ExecutionState.BoostedTimeOut) ||\n (executionState == ExecutionState.BoostedBarCrossed)) {\n orgBoostedProposalsCnt[tmpProposal.organizationId] =\n orgBoostedProposalsCnt[tmpProposal.organizationId].sub(1);\n //remove a value from average = ((average * nbValues) - value) / (nbValues - 1);\n uint256 boostedProposals = orgBoostedProposalsCnt[tmpProposal.organizationId];\n if (boostedProposals == 0) {\n averagesDownstakesOfBoosted[proposal.organizationId] = 0;\n } else {\n averageDownstakesOfBoosted = averagesDownstakesOfBoosted[proposal.organizationId];\n averagesDownstakesOfBoosted[proposal.organizationId] =\n (averageDownstakesOfBoosted.mul(boostedProposals+1).sub(proposal.stakes[NO]))/boostedProposals;\n }\n }\n emit ExecuteProposal(\n _proposalId,\n organizations[proposal.organizationId],\n proposal.winningVote,\n totalReputation\n );\n emit GPExecuteProposal(_proposalId, executionState);\n ProposalExecuteInterface(proposal.callbacks).executeProposal(_proposalId, int(proposal.winningVote));\n proposal.daoBounty = proposal.daoBountyRemain;\n }\n if (tmpProposal.state != proposal.state) {\n emit StateChange(_proposalId, proposal.state);\n }\n return (executionState != ExecutionState.None);\n }\n\n /**\n * @dev staking function\n * @param _proposalId id of the proposal\n * @param _vote NO(2) or YES(1).\n * @param _amount the betting amount\n * @return bool true - the proposal has been executed\n * false - otherwise.\n */\n function _stake(bytes32 _proposalId, uint256 _vote, uint256 _amount, address _staker) internal returns(bool) {\n // 0 is not a valid vote.\n require(_vote <= NUM_OF_CHOICES && _vote > 0, \"wrong vote value\");\n require(_amount > 0, \"staking amount should be >0\");\n\n if (_execute(_proposalId)) {\n return true;\n }\n Proposal storage proposal = proposals[_proposalId];\n\n if ((proposal.state != ProposalState.PreBoosted) &&\n (proposal.state != ProposalState.Queued)) {\n return false;\n }\n\n // enable to increase stake only on the previous stake vote\n Staker storage staker = proposal.stakers[_staker];\n if ((staker.amount > 0) && (staker.vote != _vote)) {\n return false;\n }\n\n uint256 amount = _amount;\n require(stakingToken.transferFrom(_staker, address(this), amount), \"fail transfer from staker\");\n proposal.totalStakes = proposal.totalStakes.add(amount); //update totalRedeemableStakes\n staker.amount = staker.amount.add(amount);\n //This is to prevent average downstakes calculation overflow\n //Note that any how GEN cap is 100000000 ether.\n require(staker.amount <= 0x100000000000000000000000000000000, \"staking amount is too high\");\n require(proposal.totalStakes <= 0x100000000000000000000000000000000, \"total stakes is too high\");\n\n if (_vote == YES) {\n staker.amount4Bounty = staker.amount4Bounty.add(amount);\n }\n staker.vote = _vote;\n\n proposal.