Warum schlagen meine DAO-zu-ETH-Rückerstattungen fehl?

Ein Benutzer auf thadao.slack.com hatte Probleme, seine Rückerstattungen vom The DAO Withdrawal Contact abzuheben.

WithdrawDAOIch habe den Kontakt überprüft und festgestellt, dass viele andere Transaktionen fehlschlagen:Geben Sie hier die Bildbeschreibung ein

Warum schlägt die The DAO to ETH-Rückerstattung des Benutzers fehl?

In diesem Fall hat der Benutzer die Jaxx-Wallet verwendet, um die Rückerstattungen auszuführen.

Siehe auch:

Antworten (1)

Zusammenfassung

Das Problem - Es scheint ein Problem mit bestimmten Wallets mit Rundungsfehlern zu geben.

Die Lösung - Die Lösung besteht darin, einen Betrag zu genehmigen, der größer ist als das Guthaben in The DAO. Der Benutzer muss sich an Jaxx wenden, wenn dieses Problem innerhalb der Jaxx-Wallet-Funktionalität auftritt.

Alternativ kann der Benutzer die Auszahlung mit einer der 4 Methoden durchführen, die in Wie wandle ich meine The DAO-Token in Ether um, indem ich den Auszahlungsvertrag nach der Hard Fork verwende?

Beachten Sie , dass die meisten fehlgeschlagenen DAO -> ETH-Transaktionen darauf zurückzuführen sind, dass in The DAO ein DAO-Saldo von 0 vorhanden ist. Dies könnte daran liegen, dass der Benutzer seine DAO -> ETH-Rückerstattungen bereits ausgeführt hat oder die Rückerstattungen auf den falschen Konten durchführt.



Einzelheiten

Der WithdrawDAOVertrag beruht darauf, dass der Benutzer die DAOs ausführt approve(...), um es dem WithdrawDAOVertrag zu ermöglichen, die Token vom Konto des Benutzers auf sich selbst zu übertragen, um im Gegenzug den entsprechenden Betrag auf das Konto des Benutzers zurückzuerstatten. Aufgrund eines Rundungsfehlers irgendwo im Prozess wird ein niedrigerer Betrag als der Saldo genehmigt, was zu einem Fehler im Auszahlungsprozess führt.


Bestätigen des Rundungsfehlers

Ich habe eine der fehlgeschlagenen Auszahlungen mit der unten gezeigten Fehlermeldung überprüft Warning! Error encountered during contract execution [Bad jump destination]:Geben Sie hier die Bildbeschreibung ein

Ich habe das folgende Skript ausgeführt geth consoleund es bestätigte, dass der für die Überweisung genehmigte Betrag und der Restbetrag 341 Wei lagen.

var theDAOABIFragment = [{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"type":"function"}, {"type":"function","outputs":[{"type":"uint256","name":"balance"}],"name":"balanceOf","inputs":[{"type":"address","name":"_owner"}],"constant":true}];
undefined
> var theDAOAddress = "0xbb9bc244d798123fde783fcc1c72d3bb8c189413"
undefined
> var theDAO = web3.eth.contract(theDAOABIFragment).at(theDAOAddress);
undefined
> var owner = "0x2de4452025f0f2c92f0cde55c0990e44abdc55b5".toLowerCase();
undefined
> var spender = "0xbf4ed7b27f1d666546e30d74d50d173d20bca754".toLowerCase();
undefined
> var amount = theDAO.allowance(owner, spender);
undefined
> var balance = theDAO.balanceOf(owner);
undefined
> var difference = amount.minus(balance);
undefined
> amount;
8333333333333332992
> balance;
8333333333333333333
> difference;
-341
> 

Im folgenden Code können Sie sehen, dass WithdrawDAO.withdraw()Anrufe TheDAO.transferFrom(...)mit dem vollen Guthaben, aber TheDAO.transferFrom(...)die folgenden Überprüfungen haben:

balances[_from] >= _amount
&& allowed[_from][msg.sender] >= _amount

Was eine Auszahlung des Guthabens über dem genehmigten Betrag nicht zulässt.

Hier ist eine weitere fehlgeschlagene Transaktion :

> var owner = "0x1062eecd8d3ce44a469eddb82f309971dd02ec92".toLowerCase();
undefined
> var amount = theDAO.allowance(owner, spender);
undefined
> var balance = theDAO.balanceOf(owner);
undefined
> var difference = amount.minus(balance);
undefined
> amount;
41338832000199999488
> balance;
41338832000200000000
> difference;
-512

Und noch eine fehlgeschlagene Transaktion :

> var owner = "0xe69619509a867775bf2c8b96408a82157fda695d".toLowerCase();
undefined
undefined
> var amount = theDAO.allowance(owner, spender);
undefined
> var balance = theDAO.balanceOf(owner);
undefined
> var difference = amount.minus(balance);
undefined
> amount;
2051130434782608640
> balance;
2051130434782608695
> difference;
-55

Und noch eins :

> var owner = "0x34657ab7e8a352e7c0a08c9a14a7f07a15ae98ce".toLowerCase();
undefined
> var amount = theDAO.allowance(owner, spender);
undefined
> var balance = theDAO.balanceOf(owner);
undefined
> var difference = amount.minus(balance);
undefined
> amount;
20682758620689653760
> balance;
20682758620689655172
> difference;
-1412

Einige Benutzer haben die Überweisung nicht genehmigt, bevor sie die Auszahlung aufgerufen haben :

> var owner = "0x98ba5387be9f93d777b52aef0d9c579851ee8142".toLowerCase();
> var amount = theDAO.allowance(owner, spender);
undefined
> var balance = theDAO.balanceOf(owner);
undefined
> var difference = amount.minus(balance);
undefined
> amount;
0
> balance;
39485714285714
> difference;
-39485714285714
> 

Und einige haben null Guthaben zu genehmigen oder zu übertragen :

> var owner = "0x9c0af3a6f4a2266b3e2cf1cf81d30258e3862481".toLowerCase();
undefined
> var amount = theDAO.allowance(owner, spender);
undefined
> var balance = theDAO.balanceOf(owner);
undefined
> var difference = amount.minus(balance);
undefined
> amount;
0
> balance;
0
> difference;
0
> 


Der WithdrawDAOVertrag

Es folgt ein Fragment des WithdrawDAO-Vertrags, der die withdraw()Methode zeigt:

contract WithdrawDAO {
    ...    
    function withdraw(){
        uint balance = mainDAO.balanceOf(msg.sender);

        if (!mainDAO.transferFrom(msg.sender, this, balance) || !msg.sender.send(balance))
            throw;
    }
    ...    
}


The DAOVertrag

Es folgen Fragmente von The DAO contact , die nur die relevanten Klassen und Methoden zeigen:

contract TokenInterface {
    mapping (address => uint256) balances;
    mapping (address => mapping (address => uint256)) allowed;
    ...
    /// @param _owner The address from which the balance will be retrieved
    /// @return The balance
    function balanceOf(address _owner) constant returns (uint256 balance);
    ...
    /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
    /// is approved by `_from`
    /// @param _from The address of the origin of the transfer
    /// @param _to The address of the recipient
    /// @param _amount The amount of tokens to be transferred
    /// @return Whether the transfer was successful or not
    function transferFrom(address _from, address _to, uint256 _amount) returns (bool success);

    /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
    /// its behalf
    /// @param _spender The address of the account able to transfer the tokens
    /// @param _amount The amount of tokens to be approved for transfer
    /// @return Whether the approval was successful or not
    function approve(address _spender, uint256 _amount) returns (bool success);

    /// @param _owner The address of the account owning tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @return Amount of remaining tokens of _owner that _spender is allowed
    /// to spend
    function allowance(
        address _owner,
        address _spender
    ) constant returns (uint256 remaining);
    ...
}

contract Token is TokenInterface {
    ...
    function balanceOf(address _owner) constant returns (uint256 balance) {
        return balances[_owner];
    }

    function transferFrom(
        address _from,
        address _to,
        uint256 _amount
    ) noEther returns (bool success) {

        if (balances[_from] >= _amount
            && allowed[_from][msg.sender] >= _amount
            && _amount > 0) {

            balances[_to] += _amount;
            balances[_from] -= _amount;
            allowed[_from][msg.sender] -= _amount;
            Transfer(_from, _to, _amount);
            return true;
        } else {
            return false;
        }
    }

    function approve(address _spender, uint256 _amount) returns (bool success) {
        allowed[msg.sender][_spender] = _amount;
        Approval(msg.sender, _spender, _amount);
        return true;
    }

    function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
        return allowed[_owner][_spender];
    }
}
...

// The DAO contract itself
contract DAO is DAOInterface, Token, TokenCreation {
    ...
    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
        if (isFueled
            && now > closingTime
            && !isBlocked(_from)
            && transferPaidOut(_from, _to, _value)
            && super.transferFrom(_from, _to, _value)) {

            return true;
        } else {
            throw;
        }
    }
    ...
}