Was ist im Beispiel des Ethereum-Crowdsale-Vertrags die sichere Auszahlungsfunktion?

Mit sicherer Auszahlung meine ich, wenn ein Crowdsale das Ziel nicht erreicht, welcher Bereich des Codes die Token an die Investoren zurücksendet. Ich bin wirklich ratlos.

pragma solidity ^0.4.16;

interface token {
    function transfer(address receiver, uint amount);
}

contract Crowdsale {
    address public beneficiary;
    uint public fundingGoal;
    uint public amountRaised;
    uint public deadline;
    uint public price;
    token public tokenReward;
    mapping(address => uint256) public balanceOf;
    bool fundingGoalReached = false;
    bool crowdsaleClosed = false;

    event GoalReached(address recipient, uint totalAmountRaised);
    event FundTransfer(address backer, uint amount, bool isContribution);

    /**
     * Constrctor function
     *
     * Setup the owner
     */
    function Crowdsale(
        address ifSuccessfulSendTo,
        uint fundingGoalInEthers,
        uint durationInMinutes,
        uint etherCostOfEachToken,
        address addressOfTokenUsedAsReward
    ) {
        beneficiary = ifSuccessfulSendTo;
        fundingGoal = fundingGoalInEthers * 1 ether;
        deadline = now + durationInMinutes * 1 minutes;
        price = etherCostOfEachToken * 1 ether;
        tokenReward = token(addressOfTokenUsedAsReward);
    }

    /**
     * Fallback function
     *
     * The function without name is the default function that is called     whenever anyone sends funds to a contract
 */
function () payable {
    require(!crowdsaleClosed);
    uint amount = msg.value;
    balanceOf[msg.sender] += amount;
    amountRaised += amount;
    tokenReward.transfer(msg.sender, amount / price);
    FundTransfer(msg.sender, amount, true);
}

modifier afterDeadline() { if (now >= deadline) _; }

/**
 * Check if goal was reached
 *
 * Checks if the goal or time limit has been reached and ends the campaign
 */
function checkGoalReached() afterDeadline {
    if (amountRaised >= fundingGoal){
        fundingGoalReached = true;
        GoalReached(beneficiary, amountRaised);
    }
    crowdsaleClosed = true;
}


/**
 * Withdraw the funds
 *
 * Checks to see if goal or time limit has been reached, and if so, and the funding goal was reached,
 * sends the entire amount to the beneficiary. If goal was not reached, each contributor can withdraw
 * the amount they contributed.
 */
function safeWithdrawal() afterDeadline {
    if (!fundingGoalReached) {
        uint amount = balanceOf[msg.sender];
        balanceOf[msg.sender] = 0;
            if (amount > 0) {
                if (msg.sender.send(amount)) {
                    FundTransfer(msg.sender, amount, false);
                } else {
                    balanceOf[msg.sender] = amount;
                }
            }
        }

        if (fundingGoalReached && beneficiary == msg.sender) {
            if (beneficiary.send(amountRaised)) {
                FundTransfer(beneficiary, amountRaised, false);
            } else {
                //If we fail to send the funds to beneficiary, unlock funders balance
                fundingGoalReached = false;
            }
        }
    }
}
Es ist ein Auszahlungsmuster (im Gegensatz zu einem Sendemuster), also wird die Funktion von Investoren aufgerufen, um ihren Ether zurückzubekommen.
Was ich jedoch nicht verstehe, ist, welcher Teil des Codes tatsächlich der Teil ist, der es Anlegern ermöglicht, ihren Ether zurückzurufen. Ich sehe die Funktion safeWithdrawal, verstehe aber die beiden Teile davon nicht.
Ein Teil lässt den Begünstigten Ether abheben, ein Teil lässt Investoren Ether abheben. msg.sender.sendist, wo die Gelder gesendet werden.
Ah, ja, ich sehe jetzt den Unterschied zwischen den beiden Code-Blöcken. Danke!

Antworten (1)

Das sind die relevanten Teile:

modifier afterDeadline() { if (now >= deadline) _; }

Und

function safeWithdrawal() afterDeadline {
    if (!fundingGoalReached) {
        uint amount = balanceOf[msg.sender];
        balanceOf[msg.sender] = 0;
        if (amount > 0) {
            if (msg.sender.send(amount)) {
                FundTransfer(msg.sender, amount, false);
            } else {
                balanceOf[msg.sender] = amount;
            }
        }
    }

    if (fundingGoalReached && beneficiary == msg.sender) {
        if (beneficiary.send(amountRaised)) {
            FundTransfer(beneficiary, amountRaised, false);
        } else {
            //If we fail to send the funds to beneficiary, unlock funders balance
            fundingGoalReached = false;
        }
    }
}

Der Modifikator prüft, ob der Crowdsale beendet ist. Wenn es nicht vorbei ist, wird es safeWithdrawalbeendet, ohne etwas zu tun. safeWithdrawalprüft dann, ob das Fundingziel erreicht wurde. Wenn es nicht erreicht wurde, dann prüft es, ob die Absenderadresse etwas hinterlegt hat. Wenn der Absender eingezahlt hat, wird das Guthaben zurückgegeben und das Guthaben im Vertrag auf 0 gesetzt.

Die zweite Hälfte von safeWithdrawal betrifft die Gruppe, die das ICO durchgeführt hat. Wenn das Finanzierungsziel erreicht wurde und die Absenderadresse beneficiary(die Gruppe, die die Mittel erhält) lautet, werden die Mittel gesendet. Wenn das Senden dann fehlschlägt, werden die Gelder für die Mitwirkenden freigeschaltet.

Ah, das macht sehr viel Sinn. Du hast es wirklich für mich aufgeklärt, danke! Eine andere Frage, gibt es eine Möglichkeit, ein Mindestziel zu erstellen? Soweit ich sehe, ist das „fundingGoalReached“ ein maximales Ziel – der Crowdsale endet, wenn er es erreicht. Ist es möglich, ein Minimum (und möglicherweise auch ein Maximum) zu haben?
Kein Problem! Das „fundingGoalReached“ ist also tatsächlich ein Minimum, und im aktuellen System gibt es kein Maximum. Sie können ein Maximum festlegen, indem Sie die Zahlungsfunktion so ändern, dass Beiträge nicht akzeptiert werden, wenn amountRaisedsie einen bestimmten Betrag überschreiten.