contract EticaToken is ERC20Interface{

    using SafeMath for uint;
    using ExtendedMath for uint;

    string public name = "Etica";
    string public symbol = "ETI";
    uint public decimals = 18;

    uint public supply;
    uint public inflationrate; // fixed inflation rate of phase2 (after Etica supply has reached 21 Million ETI)
    uint public  periodrewardtemp; // Amount of ETI issued per period during phase1 (before Etica supply has reached 21 Million ETI)

    uint public PERIOD_CURATION_REWARD_RATIO = 38196601125; // 38.196601125% of period reward will be used as curation reward
    uint public PERIOD_EDITOR_REWARD_RATIO = 61803398875; // 61.803398875% of period reward will be used as editor reward

    uint public UNRECOVERABLE_ETI;

    // Etica is a neutral protocol, it has no founder I am only an initiator:
    string public constant initiatormsg = "Discovering our best Futures. All proposals are made under the Creative Commons license 4.0. Kevin Wad";

    mapping(address => uint) public balances;

    mapping(address => mapping(address => uint)) allowed;

   

    // ----------- Mining system state variables ------------ //
    uint public _totalMiningSupply;



     uint public latestDifficultyPeriodStarted;



    uint public epochCount; //number of 'blocks' mined


    uint public _BLOCKS_PER_READJUSTMENT = 2016;


    //a little number
    uint public  _MINIMUM_TARGET = 2**2;


    //a big number is easier ; just find a solution that is smaller
    //uint public  _MAXIMUM_TARGET = 2**224;  bitcoin uses 224
    //uint public  _MAXIMUM_TARGET = 2**242; // used for tests 243 much faster, 242 seems to be the limit where mining gets much harder
    uint public  _MAXIMUM_TARGET = 2**220; // used for prod


    uint public miningTarget;

    bytes32 public challengeNumber;   //generate a new one when a new reward is minted


    uint public blockreward;


    address public lastRewardTo;
    uint public lastRewardEthBlockNumber;


    mapping(bytes32 => bytes32) solutionForChallenge;

    uint public tokensMinted;

    bytes32 RANDOMHASH;

    // ----------- Mining system state variables ------------ //




    event Transfer(address indexed from, address indexed to, uint tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
    event Mint(address indexed from, uint blockreward, uint epochCount, bytes32 newChallengeNumber);


    constructor() public{
      supply = 100 * (10**18); // initial supply equals 100 ETI
      balances[address(this)] = balances[address(this)].add(100 * (10**18)); // 100 ETI as the default contract balance.


    // ------------ PHASE 1 (before 21 Million ETI has been reached) -------------- //
      
      /* Phase 1 will last about 10 years:
      --> 11 550 000 ETI to be distributed through MINING as block reward
      --> 9 450 000 ETI to be issued during phase 1 as periodrewardtemp for ETICA reward system
      

      Phase1 is divided between 10 eras:
      Each Era will allocate 2 100 000 ETI between mining reward and the staking system reward.
      Each era is supposed to last about a year but can vary depending on hashrate.
      Era1: 90% ETI to mining and 10% ETI to Staking  |  Era2: 80% ETI to mining and 20% ETI to Staking
      Era3: 70% ETI to mining and 30% ETI to Staking  |  Era4: 60% ETI to mining and 40% ETI to Staking
      Era5: 50% ETI to mining and 50% ETI to Staking  |  Era6: 50% ETI to mining and 50% ETI to Staking
      Era7: 50% ETI to mining and 50% ETI to Staking  |  Era8: 50% ETI to mining and 50% ETI to Staking
      Era9: 50% ETI to mining and 50% ETI to Staking  |  Era10: 50% ETI to mining and 50% ETI to Staking
      Era1: 1 890 000 ETI as mining reward and 210 000 ETI as Staking reward
      Era2: 1 680 000 ETI as mining reward and 420 000 ETI as Staking reward
      Era3: 1 470 000 ETI as mining reward and 630 000 ETI as Staking reward 
      Era4: 1 260 000 ETI as mining reward and 840 000 ETI as Staking reward
      From Era5 to era10: 1 050 000 ETI as mining reward and 1 050 000 ETI as Staking reward
      */

      // --- STAKING REWARD --- //
       // periodrewardtemp: It is the temporary ETI issued per period (7 days) as reward of Etica System during phase 1. (Will be replaced by dynamic inflation of golden number at phase 2)
         // Calculation of initial periodrewardtemp:
         // 210 000 / 52.1429 = 4027.3939500871643119; ETI per week
      periodrewardtemp = 4027393950087164311900; // 4027.393950087164311900 ETI per period (7 days) for era1
      // --- STAKING REWARD --- //

      // --- MINING REWARD --- //
      _totalMiningSupply = 11550000 * 10**uint(decimals);


      tokensMinted = 0;

      // Calculation of initial blockreward:
      // 1 890 000 / 52.1429 = 36246.5455507844788073; ETI per week
      // amounts to 5178.0779358263541153286 ETI per day;
      // amounts to 215.7532473260980881386917 ETI per hour;
      // amounts to 35.9588745543496813564486167 ETI per block for era1 of phase1;
      blockreward = 35958874554349681356;

      miningTarget = _MAXIMUM_TARGET;

      latestDifficultyPeriodStarted = block.timestamp;

      _startNewMiningEpoch();
      // --- MINING REWARD --- //

    // ------------ PHASE 1 (before 21 Million ETI has been reached) -------------- //
      

    // ------------ PHASE 2 (after the first 21 Million ETI have been issued) -------------- //

      // Golden number power 2: 1,6180339887498948482045868343656 * 1,6180339887498948482045868343656 = 2.6180339887498948482045868343656;
      // Thus yearly inflation target is 2.6180339887498948482045868343656%
      // inflationrate calculation:
      // Each Period is 7 days, so we need to get a weekly inflationrate from the yearlyinflationrate target (1.026180339887498948482045868343656): 
      // 1.026180339887498948482045868343656 ^(1 / 52.1429) = 1,0004957512263080183722688891602;
      // 1,0004957512263080183722688891602 - 1 = 0,0004957512263080183722688891602;
      // Hence weekly inflationrate is 0,04957512263080183722688891602%
      inflationrate = 4957512263080183722688891602;  // (need to multiple by 10^(-31) to get 0,0004957512263080183722688891602;

    // ------------ PHASE 2 (after the first 21 Million ETI have been issued) -------------- //


       //The creator gets nothing! The only way to earn Etica is to mine it or earn it as protocol reward
       //balances[creator] = _totalMiningSupply;
       //Transfer(address(0), creator, _totalMiningSupply);
    }


    function allowance(address tokenOwner, address spender) view public returns(uint){
        return allowed[tokenOwner][spender];
    }


    //approve allowance
    function approve(address spender, uint tokens) public returns(bool){
        require(balances[msg.sender] >= tokens);
        require(tokens > 0);

        allowed[msg.sender][spender] = tokens;
        emit Approval(msg.sender, spender, tokens);
        return true;
    }

    //transfer tokens from the  owner account to the account that calls the function
    function transferFrom(address from, address to, uint tokens) public returns(bool){

      balances[from] = balances[from].sub(tokens);

      allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens);

      balances[to] = balances[to].add(tokens);

      emit Transfer(from, to, tokens);

      return true;
    }

    function totalSupply() public view returns (uint){
        return supply;
    }

    function accessibleSupply() public view returns (uint){
        return supply.sub(UNRECOVERABLE_ETI);
    }

    function balanceOf(address tokenOwner) public view returns (uint balance){
         return balances[tokenOwner];
     }


    function transfer(address to, uint tokens) public returns (bool success){
         require(tokens > 0);

         balances[msg.sender] = balances[msg.sender].sub(tokens);

         balances[to] = balances[to].add(tokens);

         emit Transfer(msg.sender, to, tokens);

         return true;
     }


     // -------------  Mining system functions ---------------- //

         function mint(uint256 nonce, bytes32 challenge_digest) public returns (bool success) {


             //the PoW must contain work that includes a recent ethereum block hash (challenge number) and the msg.sender's address to prevent MITM attacks
             bytes32 digest =  keccak256(abi.encodePacked(challengeNumber, msg.sender, nonce));

             //the challenge digest must match the expected
             if (digest != challenge_digest) revert();

             //the digest must be smaller than the target
             if(uint256(digest) > miningTarget) revert();


             //only allow one reward for each challenge
              bytes32 solution = solutionForChallenge[challengeNumber];
              solutionForChallenge[challengeNumber] = digest;
              if(solution != 0x0) revert();  //prevent the same answer from awarding twice

              if(tokensMinted > 1890000 * 10**uint(decimals)){
 
              if(tokensMinted >= 6300000 * 10**uint(decimals)) {
                // 6 300 000 = 5 040 000 + 1 260 000;
                //era5 to era10
                blockreward = 19977152530194267420; // 19.977152530194267420 per block (amounts to 1050000 ETI a year)
                periodrewardtemp = 20136969750435821559600; // from era5 to era 10: 20136.9697504358215596 ETI per week
              }

              else if (tokensMinted < 3570000 * 10**uint(decimals)) {
                // 3 570 000 = 1 890 000 + 1 680 000;
                // era2
                blockreward = 31963444048310827872; // 31.963444048310827872 ETI per block (amounts to 1680000 ETI a year)
                periodrewardtemp = 8054787900174328623800; // era2 8054.787900174328623800 ETI per week
              }
              else if (tokensMinted < 5040000 * 10**uint(decimals)) {
                // 5 040 000 = 3 570 000 + 1 470 000;
                //era3
                blockreward = 27968013542271974388; // 27.968013542271974388 ETI per block (amounts to 1470000 ETI a year)
                periodrewardtemp = 12082181850261492935800; // era3 12082.181850261492935800 ETI per week
              }
              else {
                // era4
                blockreward = 23972583036233120904; // 23.972583036233120904 per block (amounts to 1260000 ETI a year)
                periodrewardtemp = 16109575800348657247700; // era4 16109.575800348657247700 ETI per week
              }

              }

             tokensMinted = tokensMinted.add(blockreward);
             //Cannot mint more tokens than there are: maximum ETI ever mined: _totalMiningSupply
             assert(tokensMinted < _totalMiningSupply);

             supply = supply.add(blockreward);
             balances[msg.sender] = balances[msg.sender].add(blockreward);


             //set readonly diagnostics data
             lastRewardTo = msg.sender;
             lastRewardEthBlockNumber = block.number;


              _startNewMiningEpoch();

               emit Mint(msg.sender, blockreward, epochCount, challengeNumber );
               emit Transfer(address(this), msg.sender,blockreward);

            return true;

         }


     //a new 'block' to be mined
     function _startNewMiningEpoch() internal {


       epochCount = epochCount.add(1);

       //every so often, readjust difficulty. Dont readjust when deploying
       if(epochCount % _BLOCKS_PER_READJUSTMENT == 0)
       {
         _reAdjustDifficulty();
       }


       //make the latest ethereum block hash a part of the next challenge for PoW to prevent pre-mining future blocks
       //do this last since this is a protection mechanism in the mint() function
       challengeNumber = blockhash(block.number.sub(1));
       challengeNumber = keccak256(abi.encode(challengeNumber, RANDOMHASH)); // updates challengeNumber with merged mining protection

     }




     //readjust the target with same rules as bitcoin
     function _reAdjustDifficulty() internal {

         uint _oldtarget = miningTarget;

          // should get as close as possible to (2016 * 10 minutes) seconds => 1 209 600 seconds
         uint ethTimeSinceLastDifficultyPeriod = block.timestamp.sub(latestDifficultyPeriodStarted);      

         //we want miners to spend 10 minutes to mine each 'block'
         uint targetTimePerDiffPeriod = _BLOCKS_PER_READJUSTMENT.mul(10 minutes); //Target is 1 209 600 seconds. (2016 * 10 minutes) seconds to mine _BLOCKS_PER_READJUSTMENT blocks of ETI.

         //if there were less ethereum seconds-timestamp than expected, make it harder
         if( ethTimeSinceLastDifficultyPeriod < targetTimePerDiffPeriod )
         {

              // New Mining Difficulty = Previous Mining Difficulty * (Time To Mine Last 2016 blocks / 1 209 600 seconds)  
              miningTarget = miningTarget.mul(ethTimeSinceLastDifficultyPeriod).div(targetTimePerDiffPeriod);

              // the maximum factor of 4 will be applied as in bitcoin
              if(miningTarget < _oldtarget.div(4)){

              //make it harder
              miningTarget = _oldtarget.div(4);

              }

         }else{

                // New Mining Difficulty = Previous Mining Difficulty * (Time To Mine Last 2016 blocks / 1 209 600 seconds)
                 miningTarget = miningTarget.mul(ethTimeSinceLastDifficultyPeriod).div(targetTimePerDiffPeriod);

                // the maximum factor of 4 will be applied as in bitcoin
                if(miningTarget > _oldtarget.mul(4)){

                 //make it easier
                 miningTarget = _oldtarget.mul(4);

                }

         }

        

         latestDifficultyPeriodStarted = block.timestamp;

         if(miningTarget < _MINIMUM_TARGET) //very difficult
         {
           miningTarget = _MINIMUM_TARGET;
         }

         if(miningTarget > _MAXIMUM_TARGET) //very easy
         {
           miningTarget = _MAXIMUM_TARGET;
         }
     }


     //this is a recent ethereum block hash, used to prevent pre-mining future blocks
     function getChallengeNumber() public view returns (bytes32) {
         return challengeNumber;
     }

     //the number of zeroes the digest of the PoW solution requires.  Auto adjusts
      function getMiningDifficulty() public view returns (uint) {
         return _MAXIMUM_TARGET.div(miningTarget);
     }

     function getMiningTarget() public view returns (uint) {
        return miningTarget;
    }


    //mining reward only if the protocol didnt reach the max ETI supply that can be ever mined: 
    function getMiningReward() public view returns (uint) {
         if(tokensMinted <= _totalMiningSupply){
          return blockreward;
         }
         else {
          return 0;
         }
         
    }

     //help debug mining software
     function getMintDigest(uint256 nonce, bytes32 challenge_digest, bytes32 challenge_number) public view returns (bytes32 digesttest) {

         bytes32 digest = keccak256(abi.encodePacked(challenge_number,msg.sender,nonce));

         return digest;

       }

         //help debug mining software
       function checkMintSolution(uint256 nonce, bytes32 challenge_digest, bytes32 challenge_number, uint testTarget) public view returns (bool success) {

           bytes32 digest = keccak256(abi.encodePacked(challenge_number,msg.sender,nonce));

           if(uint256(digest) > testTarget) revert();

           return (digest == challenge_digest);

         }


// ------------------      Mining system functions   -------------------------  //

// ------------------------------------------------------------------------

// Don't accept ETH

// ------------------------------------------------------------------------

function () payable external {

    revert();

}

}
function _reAdjustDifficulty() internal {

         uint _oldtarget = miningTarget;

          // should get as close as possible to (2016 * 10 minutes) seconds => 1 209 600 seconds
         uint ethTimeSinceLastDifficultyPeriod = block.timestamp.sub(latestDifficultyPeriodStarted);      

         //we want miners to spend 10 minutes to mine each 'block'
         uint targetTimePerDiffPeriod = _BLOCKS_PER_READJUSTMENT.mul(10 minutes); //Target is 1 209 600 seconds. (2016 * 10 minutes) seconds to mine _BLOCKS_PER_READJUSTMENT blocks of ETI.

         //if there were less ethereum seconds-timestamp than expected, make it harder
         if( ethTimeSinceLastDifficultyPeriod < targetTimePerDiffPeriod )
         {

              // New Mining Difficulty = Previous Mining Difficulty * (Time To Mine Last 2016 blocks / 1 209 600 seconds)  
              miningTarget = miningTarget.mul(ethTimeSinceLastDifficultyPeriod).div(targetTimePerDiffPeriod);

              // the maximum factor of 4 will be applied as in bitcoin
              if(miningTarget < _oldtarget.div(4)){

              //make it harder
              miningTarget = _oldtarget.div(4);

              }

         }else{

                // New Mining Difficulty = Previous Mining Difficulty * (Time To Mine Last 2016 blocks / 1 209 600 seconds)
                 miningTarget = miningTarget.mul(ethTimeSinceLastDifficultyPeriod).div(targetTimePerDiffPeriod);

                // the maximum factor of 4 will be applied as in bitcoin
                if(miningTarget > _oldtarget.mul(4)){

                 //make it easier
                 miningTarget = _oldtarget.mul(4);

                }

         }

        

         latestDifficultyPeriodStarted = block.timestamp;

         if(miningTarget < _MINIMUM_TARGET) //very difficult
         {
           miningTarget = _MINIMUM_TARGET;
         }

         if(miningTarget > _MAXIMUM_TARGET) //very easy
         {
           miningTarget = _MAXIMUM_TARGET;
         }
     }
//readjust the target with same rules as bitcoin