1

I ran into something weird I can't figure it out.

for(uint i = 0; i <= payroll.length; i++) {
payroll[i].transfer(0.1 ether + totalPrizePool);
}

Where: totalPrizePool is some amount of ethereum and payroll is array of addresses.

I'm forbidden from execution of function with that loop. I truly have no idea what is wrong here. Could someone enlight me please? :)

  • 1
    Can you share more code? The whole function at least. You could be missing the payable keyword on the function declaration, for example. Maybe your contract doesn't have enough ether, or you are running out of gas if the payroll length is too big, etc. Also, what's the error your get? – pabloruiz55 Oct 9 '17 at 16:58
  • I'm now at home, will share in 12h :) – Maarduk Oct 9 '17 at 20:31
3

The route that you are going down with the function is ill-advised for at least two reasons:

  • If the payroll array gets large then you might run out of gas (reach the block's gas limit) before you get to the end of the list.
  • I would recommend switching from pushing payments to the Withdrawl pattern

I would recommend doing some reading on Smart Contract security, and pitfalls, such as

  • Thanks man those are really great tips, I'll do my homework, truly appreciate, thanks. – Maarduk Oct 9 '17 at 20:33
2

(SteveJaxon's answer has some very important suggestions! This answer should only be considered in addition to it!)

The reason you're having an error is because your for-loop has an off-by-one error. Arrays in Solidity are 0-indexed. So for example, a 3 item list has items in slot 0, 1, and 2. There is no slot 3 in a 3-length list. When iterating over a list, you need to end your loop when i is equal to the list length. i <= payroll.length needs to be i < payroll.length.

-1

@pabloruiz55 and others, there is whole code. Also would love some more pro tips.

pragma solidity ^0.4.11;

contract Fund{
    uint startDate;
    uint endDate;
    uint totalPrizePool;
    uint[] indexes;
    uint num;
    uint payDay;
    uint nextCampaignId;
    uint reprocessLock;
    address owner;

    function Fund(){
        startDate = now;
        endDate   = now + 12 minutes;
        payDay = endDate;
        reprocessLock = 0;
        owner = msg.sender;
        totalPrizePool = 0;
    }

    mapping (address => uint) phoneBook;
    mapping (uint => Payment) payment;

    struct Payment {
    uint amount;
    uint dateOfPayment;
    uint paymentsCount;
    address payOutAddr;
    }

    event enrolled(address payoutAddress, address sender, uint dateOfTransaction);
    event checker(address adr, uint amount, uint date, int paycount);
    modifier validateIfContractOpen(){ if(startDate + 30 minutes < now ) revert(); _; }
    modifier validateIfAlreadyExist(address payOutAddr){ if(payment[phoneBook[payOutAddr]].paymentsCount != 0) revert(); _; }
    modifier validateMsg(){ if(msg.value != 0.1 ether) revert(); _; }

    function enroll(address payOutAddr) payable
    validateMsg()
    validateIfContractOpen()
    validateIfAlreadyExist(payOutAddr)
    {
        phoneBook[payOutAddr] = nextCampaignId;

        payment[phoneBook[payOutAddr]].payOutAddr = payOutAddr;
        payment[phoneBook[payOutAddr]].amount += msg.value;
        payment[phoneBook[payOutAddr]].dateOfPayment = now;
        payment[phoneBook[payOutAddr]].paymentsCount += 1;

        enrolled(payOutAddr,msg.sender,now);

        nextCampaignId++;
    }

    event paymentAccepted(address payoutAddress, address sender, uint dateOfTransaction);



    function paycount(address addr){
        logger(payment[phoneBook[addr]].paymentsCount);
    }

    modifier checkFee(address payOutAddr){
        uint lifeCycle = now - startDate;

        uint cycleOfContract = lifeCycle / 3 minutes; //ogarnac rounding
        uint begin = 3 minutes * cycleOfContract;
        uint end = begin + 3 minutes;

        int notPayedCycles = int(cycleOfContract - payment[phoneBook[payOutAddr]].paymentsCount);

        // && paymentCount == cycles
        if(lifeCycle > begin && lifeCycle < end){

            uint semiTotalFee = 0.02 ether * uint(notPayedCycles) + (0.1 ether * uint(notPayedCycles));
            uint totalFee = 0.1 ether + semiTotalFee;
            logger(semiTotalFee);
            logger(totalFee);
            if(msg.value != totalFee){
                revert();
            }
            _;
        }
        else{
            revert();
            _;
        }

    }


    modifier validatePaymentCountAndDate(address payOutAddr){ if (payment[phoneBook[payOutAddr]].paymentsCount == 3 ||
    (now - startDate / 3 minutes) == payment[phoneBook[payOutAddr]].paymentsCount) revert(); _; }

    modifier checkIfenrolled(address payOutAddr){  if (payment[phoneBook[payOutAddr]].paymentsCount < 1 ) revert(); _;  }

    function deposit(address payOutAddr) payable
    checkFee(payOutAddr)
    validatePaymentCountAndDate(payOutAddr) // moze placic raz na okienko
    {
        payment[phoneBook[payOutAddr]].amount += msg.value;
        payment[phoneBook[payOutAddr]].dateOfPayment = now;

        uint moneyWithoutFee = msg.value - (0.02 ether * (((((now - startDate)/3 minutes) - payment[phoneBook[payOutAddr]].paymentsCount))));

        payment[phoneBook[payOutAddr]].paymentsCount += moneyWithoutFee / 0.1 ether;
        paymentAccepted(payment[phoneBook[payOutAddr]].payOutAddr, msg.sender, now);

    }

    modifier validateIfEnded(){ if (endDate > now && reprocessLock != 0) revert(); _; } // srednio smiga

    event push(address sila);

    function reproccess()
    validateIfEnded()
    {
        uint i = 0;
        uint j = 0;
        uint prizePool;
        while(payment[i].paymentsCount != 0){
            if(payment[i].paymentsCount != 3){
                prizePool += payment[i].amount;
                payment[i].amount = 0; //opcjonalne
                j++;
            }
            if(payment[i].paymentsCount == 3){
                worthy[payment[i].payOutAddr] = 1;
            }
            i++;
        }
        reprocessLock = 1;
        totalPrizePool = (prizePool/(i-j))/3;
    }


    mapping (address => uint) worthy;


    modifier isWorth(address payOutAddress){ if( worthy[payOutAddress] != (now - endDate)/3 minutes + 1) revert(); _; }
    modifier checkReprocessLock(){ if (reprocessLock != 1) revert(); _; }

    function withDraw(address payOutAddress)
    isWorth(payOutAddress)
    checkReprocessLock()
    {
        payOutAddress.transfer(0.1 ether + totalPrizePool);
        worthy[payOutAddress] += 1;
    }



    function checkReprocess(){
        logger(reprocessLock);
    }

    function giveFunds()payable{}


    function checkpayroll(){

    }



    modifier own(){ if(msg.sender != owner) revert(); _; }
    function die()
    own()
    {
        msg.sender.transfer(this.balance);
    }

    function paaa(address addr){

        addr.transfer(0.1 ether);

    }

}

In brief, this contract is something like investment fund. First you enroll and pay 0.1 ether to it for a certain amount of time. Later on you can withdraw the ether.

  • 1
    Please update your question accordingly instead of answering your own question with more info. Also, in this updated code it seems you removed the code that was causing problems in your original question. – pabloruiz55 Oct 10 '17 at 11:27

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.