Este contrato recolecta ETH a cambio de tokens de votación. ¿Qué función me permitirá transferir el ETH recolectado a una billetera?

pragma solidity ^0.4.23;

contract Voting {
    bytes32[] public candidateList;

    uint public totalTokens;
    uint public balanceTokens;
    uint public tokenPrice;

    // what is the voter address?
    // total tokens purchased
    // tokens voted per candidate 

    struct voter {
        address voterAddress;
        uint tokensBought;
        uint[] tokensUsedPerCandidate;
    }

    mapping(address => voter) public voterInfo;
    mapping(bytes32 => uint) public votesReceived;

    constructor (uint _totalTokens, uint _tokenPrice, bytes32[] _candidateNames) public {
        totalTokens = _totalTokens;
        balanceTokens = _totalTokens;
        tokenPrice = _tokenPrice;
        candidateList = _candidateNames;
    }

    //1. Users should be able to purchase tokens 
    //2. Users should be able to vote for candidates with tokens
    //3. Anyone should have the ability to lookup voter info

    function buy() payable public {
        uint tokensToBuy = msg.value / tokenPrice;
        require(tokensToBuy <= balanceTokens);
        voterInfo[msg.sender].voterAddress = msg.sender;
        voterInfo[msg.sender].tokensBought += tokensToBuy;
        balanceTokens -= tokensToBuy;
    }

    function voteForCandidate(bytes32 candidate, uint tokens) public {
        // Check to make sure user has enough tokens to vote
        // Increment vote count for candidate
        // Update the voter struct tokensUsedPerCandidate for this voter

        uint availableTokens = voterInfo[msg.sender].tokensBought - totalTokensUsed(voterInfo[msg.sender].tokensUsedPerCandidate);

        require(tokens <= availableTokens, "You don't have enough tokens");
        votesReceived[candidate] += tokens;

        if (voterInfo[msg.sender].tokensUsedPerCandidate.length == 0) {
            for(uint i=0; i<candidateList.length; i++) {
                voterInfo[msg.sender].tokensUsedPerCandidate.push(0);
            }
        }

        uint index = indexOfCandidate(candidate);
        voterInfo[msg.sender].tokensUsedPerCandidate[index] += tokens;
    }

    function indexOfCandidate(bytes32 candidate) view public returns(uint) {
        for(uint i=0; i<candidateList.length; i++) {
            if (candidateList[i] == candidate) {
                return i;
            }
        }
        return uint(-1);
    }

    function totalTokensUsed(uint[] _tokensUsedPerCandidate) private pure returns (uint) {
        uint totalUsedTokens = 0;
        for(uint i=0; i<_tokensUsedPerCandidate.length; i++) {
            totalUsedTokens += _tokensUsedPerCandidate[i];
        }
        return totalUsedTokens;
    }

    function voterDetails(address user) view public returns (uint, uint[]) {
        return (voterInfo[user].tokensBought, voterInfo[user].tokensUsedPerCandidate);
    }

    function tokensSold() public view returns (uint) {
        return totalTokens - balanceTokens;
    }

    function allCandidates() public view returns (bytes32[]) {
        return candidateList;
    }

    function totalVotesFor(bytes32 candidate) public view returns (uint) {
        return votesReceived[candidate];
   }
}

Respuestas (2)

La función para transferir Ether a una cuenta podría ser algo como esto:

function transferBalance() public {
    owner.transfer(address(this).balance);
}

Y en su constructor, puede configurar el propietario de esta manera (quienquiera que implemente el contrato es el propietario y solo ellos obtienen el Ether)

 owner = msg.sender
Esta implementación permite que cualquiera pueda iniciar la transferencia. Esto no significa que el éter pueda ser robado, porque de todos modos se envía al propietario, pero esto podría dificultar el seguimiento de la cantidad de éter que se retiró.

[Edité la pregunta original para que el código sea más comprensible. Una vez que hice eso, se hizo evidente que] este código (tal como está escrito) no contiene forma de extraer ningún éter que pueda acumularse a través de la función de pago buy .

La única "especie de" explicación de por qué el código puede tener este aspecto es que se supone que el autor del contrato es heredado por otro contrato que proporciona el código para extraer el éter.

Creo que separar la lógica que acepta el éter de la lógica que permite eliminar el éter del contrato es un diseño muy malo, al igual que incorporar la función de votación en el contacto que acepta el éter.

O bien, debe haber dos contratos (uno que se ocupe del éter y otro que se ocupe de la votación) o un solo contrato que se ocupe completamente de ambos.