contract PEpsilon {
  Pinakion public pinakion;
  Kleros public court;
   uint public balance;
  uint public disputeID;
  uint public desiredOutcome;
  uint public epsilon;
  bool public settled;
  uint public maxAppeals; // The maximum number of appeals this cotracts promises to pay
  mapping (address => uint) public withdraw; // We'll use a withdraw pattern here to avoid multiple sends when a juror has voted multiple times.
   address public attacker;
  uint public remainingWithdraw; // Here we keep the total amount bribed jurors have available for withdraw.
   modifier onlyBy(address _account) {require(msg.sender == _account); _;}
   event AmountShift(uint val, uint epsilon ,address juror);
  event Log(uint val, address addr, string message);
   /** @dev Constructor.
   *  @param _pinakion The PNK contract.
   *  @param _kleros   The Kleros court.
   *  @param _disputeID The dispute we are targeting.
   *  @param _desiredOutcome The desired ruling of the dispute.
   *  @param _epsilon  Jurors will be paid epsilon more for voting for the desiredOutcome.
   *  @param _maxAppeals The maximum number of appeals this contract promises to pay out
   */
  constructor(Pinakion _pinakion, Kleros _kleros, uint _disputeID, uint _desiredOutcome, uint _epsilon, uint _maxAppeals) public {
    pinakion = _pinakion;
    court = _kleros;
    disputeID = _disputeID;
    desiredOutcome = _desiredOutcome;
    epsilon = _epsilon;
    attacker = msg.sender;
    maxAppeals = _maxAppeals;
  }
   /** @dev Callback of approveAndCall - transfer pinakions in the contract. Should be called by the pinakion contract. TRUSTED.
   *  The attacker has to deposit sufficiently large amount of PNK to cover the payouts to the jurors.
   *  @param _from The address making the transfer.
   *  @param _amount Amount of tokens to transfer to this contract (in basic units).
   */
  function receiveApproval(address _from, uint _amount, address, bytes) public onlyBy(pinakion) {
    require(pinakion.transferFrom(_from, this, _amount));
     balance += _amount;
  }
   /** @dev Jurors can withdraw their PNK from here
   */
  function withdrawJuror() {
    withdrawSelect(msg.sender);
  }
   /** @dev Withdraw the funds of a given juror
   *  @param _juror The address of the juror
   */
  function withdrawSelect(address _juror) {
    uint amount = withdraw[_juror];
    withdraw[_juror] = 0;
     balance = sub(balance, amount); // Could underflow
    remainingWithdraw = sub(remainingWithdraw, amount);
     // The juror receives d + p + e (deposit + p + epsilon)
    require(pinakion.transfer(_juror, amount));
  }
   /**
  * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
    assert(_b <= _a);
    return _a - _b;
  }
   /** @dev The attacker can withdraw their PNK from here after the bribe has been settled.
   */
  function withdrawAttacker(){
    require(settled);
     if (balance > remainingWithdraw) {
      // The remaning balance of PNK after settlement is transfered to the attacker.
      uint amount = balance - remainingWithdraw;
      balance = remainingWithdraw;
       require(pinakion.transfer(attacker, amount));
    }
  }
   /** @dev Settles the p + e bribe with the jurors.
   * If the dispute is ruled differently from desiredOutcome:
   *    The jurors who voted for desiredOutcome receive p + d + e in rewards from this contract.
   * If the dispute is ruled as in desiredOutcome:
   *    The jurors don't receive anything from this contract.
   */
  function settle() public {
    require(court.disputeStatus(disputeID) ==  Arbitrator.DisputeStatus.Solved); // The case must be solved.
    require(!settled); // This function can be executed only once.
     settled = true; // settle the bribe
     // From the dispute we get the # of appeals and the available choices
    var (, , appeals, choices, , , ,) = court.disputes(disputeID);
     if (court.currentRuling(disputeID) != desiredOutcome){
      // Calculate the redistribution amounts.
      uint amountShift = court.getStakePerDraw();
      uint winningChoice = court.getWinningChoice(disputeID, appeals);
       // Rewards are calculated as per the one shot token reparation.
      uint lastRound = (appeals > maxAppeals ? maxAppeals : appeals);
       // Note that we don't check if the result was a tie becuse we are getting a funny compiler error: "stack is too deep" if we check.
      // TODO: Account for ties
      if (winningChoice != 0){
        // votesLen is the length of the votes per each appeal. There is no getter function for that, so we have to calculate it here.
        // We must end up with the exact same value as if we would have called dispute.votes[lastRound].length
        uint votesLen = 0;
        for (uint c = 0; c <= choices; c++) { // Iterate for each choice of the dispute.
          votesLen += court.getVoteCount(disputeID, lastRound, c);
        }
         emit Log(amountShift, 0x0 ,"stakePerDraw");
        emit Log(votesLen, 0x0, "votesLen");
         uint totalToRedistribute = 0;
        uint nbCoherent = 0;
         // Now we will use votesLen as a substitute for dispute.votes[lastRound].length
        for (uint j=0; j < votesLen; j++){
          uint voteRuling = court.getVoteRuling(disputeID, lastRound, j);
          address voteAccount = court.getVoteAccount(disputeID, lastRound, j);
           emit Log(voteRuling, voteAccount, "voted");
           if (voteRuling != winningChoice){
            totalToRedistribute += amountShift;
             if (voteRuling == desiredOutcome){ // If the juror voted as we desired.
              // Transfer this juror back the penalty.
              withdraw[voteAccount] += amountShift + epsilon;
              remainingWithdraw += amountShift + epsilon;
              emit AmountShift(amountShift, epsilon, voteAccount);
            }
          } else {
            nbCoherent++;
          }
        }
        // toRedistribute is the amount each juror received when he voted coherently.
        uint toRedistribute = (totalToRedistribute - amountShift) / (nbCoherent + 1);
         // We use votesLen again as a substitute for dispute.votes[lastRound].length
        for (j = 0; j < votesLen; j++){
          voteRuling = court.getVoteRuling(disputeID, lastRound, j);
          voteAccount = court.getVoteAccount(disputeID, lastRound, j);
           if (voteRuling == desiredOutcome){
            // Add the coherent juror reward to the total payout.
            withdraw[voteAccount] += toRedistribute;
            remainingWithdraw += toRedistribute;
            emit AmountShift(toRedistribute, 0, voteAccount);
          }
        }
      }
    }
  }
}
/** @title PEpsilonLastRound
 *  @author based on a contract by Daniel Babbev, modified by William George
 *
 *  This contract implements a p + epsilon attack against the Kleros court where the bribe is only offered to jurors in the last appeal round.
 *  The attack is described by VitaliK Buterin here: https://blog.ethereum.org/2015/01/28/p-epsilon-attack/
 */
function settle() public {
  require(court.disputeStatus(disputeID) ==  Arbitrator.DisputeStatus.Solved); // The case must be solved.
  require(!settled); // This function can be executed only once.
   settled = true; // settle the bribe
   // From the dispute we get the # of appeals and the available choices
  var (, , appeals, choices, , , ,) = court.disputes(disputeID);
   if (court.currentRuling(disputeID) != desiredOutcome){
    // Calculate the redistribution amounts.
    uint amountShift = court.getStakePerDraw();
    uint winningChoice = court.getWinningChoice(disputeID, appeals);
     // Rewards are calculated as per the one shot token reparation.
    uint lastRound = (appeals > maxAppeals ? maxAppeals : appeals);
     // Note that we don't check if the result was a tie becuse we are getting a funny compiler error: "stack is too deep" if we check.
    // TODO: Account for ties
    if (winningChoice != 0){
      // votesLen is the length of the votes per each appeal. There is no getter function for that, so we have to calculate it here.
      // We must end up with the exact same value as if we would have called dispute.votes[lastRound].length
      uint votesLen = 0;
      for (uint c = 0; c <= choices; c++) { // Iterate for each choice of the dispute.
        votesLen += court.getVoteCount(disputeID, lastRound, c);
      }
       emit Log(amountShift, 0x0 ,"stakePerDraw");
      emit Log(votesLen, 0x0, "votesLen");
       uint totalToRedistribute = 0;
      uint nbCoherent = 0;
       // Now we will use votesLen as a substitute for dispute.votes[lastRound].length
      for (uint j=0; j < votesLen; j++){
        uint voteRuling = court.getVoteRuling(disputeID, lastRound, j);
        address voteAccount = court.getVoteAccount(disputeID, lastRound, j);
         emit Log(voteRuling, voteAccount, "voted");
         if (voteRuling != winningChoice){
          totalToRedistribute += amountShift;
           if (voteRuling == desiredOutcome){ // If the juror voted as we desired.
            // Transfer this juror back the penalty.
            withdraw[voteAccount] += amountShift + epsilon;
            remainingWithdraw += amountShift + epsilon;
            emit AmountShift(amountShift, epsilon, voteAccount);
          }
        } else {
          nbCoherent++;
        }
      }
      // toRedistribute is the amount each juror received when he voted coherently.
      uint toRedistribute = (totalToRedistribute - amountShift) / (nbCoherent + 1);
       // We use votesLen again as a substitute for dispute.votes[lastRound].length
      for (j = 0; j < votesLen; j++){
        voteRuling = court.getVoteRuling(disputeID, lastRound, j);
        voteAccount = court.getVoteAccount(disputeID, lastRound, j);
         if (voteRuling == desiredOutcome){
          // Add the coherent juror reward to the total payout.
          withdraw[voteAccount] += toRedistribute;
          remainingWithdraw += toRedistribute;
          emit AmountShift(toRedistribute, 0, voteAccount);
        }
      }
    }
  }
}

/** @dev Settles the p + e bribe with the jurors.
 * If the dispute is ruled differently from desiredOutcome:
 *    The jurors who voted for desiredOutcome receive p + d + e in rewards from this contract.
 * If the dispute is ruled as in desiredOutcome:
 *    The jurors don't receive anything from this contract.
 */