0

An investment round ask new investors to put exactly 0.1 ether to enter the round.

function invest() public payable {
    require(msg.value == 0.1 ether);   
}
  • How can I save every new investor address into an indexed list? Considering that there could be thousands of investors.

The idea is that, given a condition, the investors will exit the round. So the list (investorsList) should be iterable with a for loop, kind of like this:

function withdraw() public {
    for (uint i = 0; i < investorsList.length; i++){     // iterates investors list
            if (address(this).balance = 1 ether){       // if condition reached
                investorsList[i].transfer( 0.5 ether); // transfers eth to investor
        }
    }

// Eth amounts are just for example

EDIT: This question asks for a use case where could be hundreds of thousands of addresses stored and iterate over them, so the contract should never get stuck, it should be able to run forever.

1

Constructing a list isn't especially hard.

You could, for example declare a global state:

address public investorList;

and then append to the list as you go:

investorList.push(msg.sender);

You can find more general storage patterns over here: Are there well-solved and simple storage patterns for Solidity?

There is a big problem. The intuitive idea of iterating over the list with a for loop will get you into trouble. This can create a situation where it is impossible to recover funds from the contract. Have a look over here for a more complete description of this anti-pattern: https://blog.b9lab.com/getting-loopy-with-solidity-1d51794622ad

There is another big problem. If any address on the list is a contract with a default non-payable fallback function or malicious, then it will be impossible to recover funds from the contract. This is because the function must succeed or fail entirely. A single failed transfer will cause the whole thing to revert.

There is a big can of worms there. You could think about using the send method instead of transfers, but then you have to consider what to do next. It gets complicated.

The simplest known solution is to favor pull over push, a.k.a. the Withdrawal pattern. Each investor will approach the contract and claim their refund. As a bonus, they pay for the gas.

Here's a little sketch with those suggestions in mind:

pragma solidity 0.4.25;

contract Refund {

    bool public isRefunding;
    mapping(address => uint) public balances;

    event LogInvestment(address investor); // nothing else to say because amount is fixed
    event LogRefundStarted();
    event LogRefundSent(address investor, uint amount);

    function invest() public payable returns(bool success) {
        require(!isRefunding);
        require(msg.value == 0.1 ether);  
        balances[msg.sender] +=  msg.value;
        emit LogInvestment(msg.sender);
        return true;
    }

    // onlyOwner access control omitted for brevity.

    function setRefunding() public returns(bool success) {
        require(!isRefunding);
        emit LogRefundStarted();
        return true;
    }

    function claimRefund() public returns(bool success) {
        uint amount = balances[msg.sender];
        require(amount > 0);
        balances[msg.sender] = 0;
        emit LogRefundSent(msg.sender, amount);
        return true;
    }

}

Hope it helps.

  • Thanks a lot Rob. I've trying to find away to iterate over the indexes and it's been difficult without running out of gas. Will see how can I evolve and avoid this. – user47673 Nov 22 '18 at 12:24
  • My pleasure, Ian. Please vote and accept an answer. Voting helps this site's reputation with StackOverflow and we need that. ;-) – Rob Hitchens - B9lab Nov 22 '18 at 16:34
0

You should simply declare an array and save the address of the sender in it:

address[] private investorsList;

function invest() public payable {
  require(msg.value == 0.1 ether);
  investorsList.push(msg.sender); 
}

function withdraw() public {
  for (uint i = 0; i < investorsList.length; i++){  // iterates investors list
    if (address(this).balance > 1 ether){           // if condition reached
      investorsList[i].transfer( 0.5 ether);        // transfers eth to investor
    }
  }
}
  • Thanks marco, the problem here is if you want to iterate over many thousands of indexes you will quickly run out of gas. I already tried this pattern. – user47673 Nov 22 '18 at 12:26
  • Good you edited your question now. I would have not spent time writing my answer – Marco Ottolini Nov 22 '18 at 17:05

Your Answer

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