¿Cómo puedo construir esta lista de direcciones?

Una ronda de inversión pide a los nuevos inversores que pongan exactamente 0,1 éter para entrar en la ronda.

function invest() public payable {
    require(msg.value == 0.1 ether);   
}
  • ¿Cómo puedo guardar cada nueva dirección de inversionista en una lista indexada? Teniendo en cuenta que podría haber miles de inversores.

La idea es que, dada una condición, los inversores salgan de la ronda. Entonces, la lista (investorsList) debe ser iterable con un bucle for, algo así:

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

EDITAR: esta pregunta solicita un caso de uso en el que podría haber cientos de miles de direcciones almacenadas e iterar sobre ellas, por lo que el contrato nunca debería atascarse, debería poder ejecutarse para siempre.

Respuestas (2)

Construir una lista no es especialmente difícil.

Podría, por ejemplo, declarar un estado global:

address public investorList;

y luego agregue a la lista a medida que avanza:

investorList.push(msg.sender);

Puede encontrar patrones de almacenamiento más generales aquí: ¿ Existen patrones de almacenamiento simples y bien resueltos para Solidity?

Hay un gran problema. La idea intuitiva de iterar sobre la lista con un forbucle le traerá problemas. Esto puede crear una situación en la que sea imposible recuperar los fondos del contrato. Eche un vistazo aquí para obtener una descripción más completa de este antipatrón: https://blog.b9lab.com/getting-loopy-with-solidity-1d51794622ad

Hay otro gran problema. Si alguna dirección de la lista es un contrato con una función de respaldo no pagable predeterminada o es maliciosa, entonces será imposible recuperar los fondos del contrato. Esto se debe a que la función debe tener éxito o fallar por completo. Una sola transferencia fallida hará que todo se revierta.

Hay una gran lata de gusanos allí. Podría pensar en usar el método de envío en lugar de las transferencias, pero luego debe considerar qué hacer a continuación. Se complica

La solución conocida más simple es favorecer el pull over push, también conocido como el patrón de Retiro. Cada inversor se acercará al contrato y reclamará su devolución. Como beneficio adicional, pagan por el gas.

Aquí hay un pequeño boceto con esas sugerencias en mente:

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;
    }

}

Espero eso ayude.

muchas gracias roberto He intentado encontrar una forma de iterar sobre los índices y ha sido difícil sin quedarme sin combustible. Veré cómo puedo evolucionar y evitar esto.
Un placer, Ian. Vota y acepta una respuesta. Votar ayuda a la reputación de este sitio con StackOverflow y lo necesitamos. ;-)

Simplemente debe declarar una matriz y guardar la dirección del remitente en ella:

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
    }
  }
}
Gracias marco, el problema aquí es que si desea iterar sobre muchos miles de índices, rápidamente se quedará sin combustible. Ya probé este patrón.
Bien, editaste tu pregunta ahora. no hubiera perdido tiempo escribiendo mi respuesta