1

I'm developing a quite simple contract :

pragma solidity ^0.4.10;

contract Lottery {

    // CONSTANTS
    int constant LOTTERY_INTERVAL = 1 days;
    uint256 constant private TICKET_PRICE=1;
    uint constant FEE_FACTOR = 200; // 0.5 %

    // VARIABLES
    uint256 totalBalance=0;
    uint totalParticipants=0;
    uint winnerCounter=0;

    // Structs
    struct TicketHolder {
        address ticketHolder;
        uint estimation;
        uint buyingTimeScore;
        uint timestamp;
        uint score;
    }

    // Mappings
    mapping (address => TicketHolder) ticketHolders;
    mapping (uint => TicketHolder) ticketHoldersIndex;

    // Arrays
    address[] ticketHoldersAddress;
    address [] winners;

    // Constructor
    function Lottery(){

    }

    //Getters setters
      function getBuyingTime(address ticketHolder) returns (uint){
        return ticketHolders[ticketHolder].buyingTimeScore;
    }


    function getEstimation(address ticketHolder) returns (uint){
        return ticketHolders[ticketHolder].estimation;
    }

    function getScore(address ticketHolder) returns (uint){
        return ticketHolders[ticketHolder].score;
    }


    function getMinute(uint timestamp) constant returns (uint8) {
        return uint8((timestamp / 60) % 60);
    }

    function setScore(address ticketHolder,uint score){
        ticketHolders[ticketHolder].score = score;
    }

    function calculateBuyingTimeScore() returns (uint){
        uint timeBeforeNewRound=60-getMinute(now);
        return timeBeforeNewRound*100*100/60;
    }

    function calculateDeviationScore(uint courseValue, uint estimatedValue) returns (uint){
        uint difference=0;
        if(courseValue>=estimatedValue){
            difference=courseValue-estimatedValue;
        }else if(courseValue<estimatedValue){
            difference=estimatedValue-courseValue;
        }

        // Calculated standard deviation
        uint deviation = (difference*10000/courseValue);
        uint score=10000-deviation;
        return score;
    }

    //TODO: add more conditions
    function buyTicket(address ticketHolder, uint estimation) payable returns (uint){
        if(msg.value < TICKET_PRICE) throw;
        uint buyingTimeScore=calculateBuyingTimeScore();
        totalBalance += msg.value;
        ticketHolders[ticketHolder] = TicketHolder(ticketHolder,estimation,buyingTimeScore, now, 0);
        ticketHoldersIndex[totalParticipants++] = TicketHolder(ticketHolder,estimation,buyingTimeScore, now, 0);
        ticketHoldersAddress.push(ticketHolder);
        return totalBalance;
    }

    function calculateScore(uint courseValue) {
        if(totalParticipants==0) throw;
        for(uint participant = 0; participant < totalParticipants; participant++){
            TicketHolder ticketHolder = ticketHoldersIndex[participant];
            uint deviationScore = calculateDeviationScore(courseValue,ticketHolder.estimation) / 2;
            uint buyingTimeScore = ticketHolder.buyingTimeScore / 2;
            uint totalScore =deviationScore + buyingTimeScore;
            setScore(ticketHolder.ticketHolder, totalScore);
        }
    }

    function determineWinners() returns (uint){
         uint highestScore=0;
         for(uint participant = 0; participant < totalParticipants; participant++){
             TicketHolder ticketHolder = ticketHoldersIndex[participant];
             uint score = ticketHolder.score;
             if(score>=highestScore){
                 winners.push(ticketHolder.ticketHolder);
                 winnerCounter++;
                 highestScore=score;
             }
         }
         return  ticketHoldersAddress.length;
    }

    function test() returns (uint){
        uint testa = totalBalance/winnerCounter;
        return testa;
    }

    function payout(uint courseValue){
        if(totalParticipants==0) throw;
        calculateScore(courseValue);
        determineWinners();
        uint256 winAmount=totalBalance/winnerCounter;
        for(uint i= 0; i<winnerCounter;i++){
            address winnerTicket = winners[i];
            winnerTicket.transfer(winAmount);
        }
    }

}

Unfortunately in solidity browser (https://ethereum.github.io/browser-solidity/) it gives me an error:

Exception during execution. (invalid opcode). Please debug the transaction for more information.

in this row:

winnerTicket.transfer(winAmount);

Is it possible to transfer money in solidity browser? What is the issue here?

  • There is no "winnerTicket.transfer" in the code. Can you elaborate? – Rob Hitchens Jul 1 '17 at 20:30
  • @RobHitchens transfer is a method of all address types. It's like send but throws on failure. – Tjaden Hess Jul 1 '17 at 21:22
  • nvmd ... found it. – Rob Hitchens Jul 2 '17 at 18:14
1

You're getting invalid opcode because the function throws, by design.

If this is deployed and nothing else is done, then the function is called, this line:

if(totalParticipants==0) throw;

That's a fair bit of code to wade through so that's as far as I went. I noticed something that looks like it might be a concern. You use for loops over the number of participants in a few places. That puts a hidden limit on the number of participants. Probably not what you want.

Consider refactoring to avoid unbounded loops.

Hope it helps.

  • Thats a fair point - how can I refactor these? – Fabian Lurz Jul 2 '17 at 18:58
  • This will be a little abstract because I haven't really absorbed all the rules of the lottery. General idea ... to push loops out of the contract, invert flow control. Instead of the contract pushing to all (via a loop), have each contestant check in (pull) to see if they won. That means the contestants pay the gas to claim their prize or forfeit if they don't check in. Each check-in pushes the evaluation forward a little bit. You can use a purpose-built UI to make check-in a "client" and not a "human" responsibility. You may have to implement phases, e.g. wager, reveal/eval, claim. – Rob Hitchens Jul 2 '17 at 23:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.