TxReceipt-Status schlägt fehl, ETH an Contract on Rinkeby zu senden

Ich sende ETH im Rinkeby-Netzwerk von meiner Brieftasche in Metamask zu einem Vertrag, der auf Rinkeby bereitgestellt wurde. Dies ist ein Crowdsale-Vertrag , der auf Open Zeppelin basiert .

Wenn ich jedoch die Transaktionsdetails auf Etherscan überprüfe, erhalte ich die folgende Fehlermeldung:

TxReceipt-Status: Fehlgeschlagen

Wie finde ich das Problem heraus?


Aktualisieren

Die vorgeschlagene Gasmenge von Metamask ist immer ungewöhnlich hoch, wenn die Transaktion fehlschlagen soll ...

ETH wurde zum TestTokenSale.solVertrag geschickt.

Rinkeby-Transaktion: 0xbbcff212c72e201412a3c4f4304d13e517212b793f04ae597399d2f375052b36

geth debug.traceTransaction: [Gist]

Der TestToken.solwird zuerst bereitgestellt, gefolgt vonTestTokenSale.sol

TestToken.sol

Konstruktorargumente:'qwe', 'qwe, 'qwe', 123

  pragma solidity ^0.4.15;

  import "./libs/zeppelin/token/MintableToken.sol";

  contract TestToken is MintableToken {

     string public name;
     string public symbol;
     uint8 public constant decimals = 18;
     string public constant version = "1.0";

     string public location;
     uint8 public power;

     uint256 public constant tokenUnit = 10 ** 18;

     function TestToken(string _name, string _symbol, string _location, uint8 _power) {
        name = _name;
        symbol = _symbol;

        location = _location;
        power = _power;
     }
  }

TestTokenSale.sol

Konstruktorargumente:1520889758, 1530889758, 500, 10000000, 0xcede48d8ac162d1b08ed9419010de3c99f2cfdd6, 0x37b925b6c72cc313bea41b95629b74478d9d442b

pragma solidity ^0.4.15;

import "./libs/zeppelin/crowdsale/CappedCrowdsale.sol";
import "./libs/zeppelin/crowdsale/FinalizableCrowdsale.sol";
import './TestToken.sol';



contract TestTokenSale is CappedCrowdsale, FinalizableCrowdsale {

  address public tokenContractAddress;

  function TestTokenSale(uint256 _startTime, uint256 _endTime, uint256 _rate, uint256 _cap, address _wallet, address _tokenContractAddress)
    CappedCrowdsale(_cap)
    FinalizableCrowdsale()
    Crowdsale(_startTime, _endTime, _rate, _wallet)
  {
    tokenContractAddress = _tokenContractAddress;
  }

  function createTokenContract(address tokenContractAddress) internal returns (MintableToken) {
    return TestToken(tokenContractAddress);
  }


  function finalization() internal {
  }

}

Aktualisierung 2

ETH senden an TestTokenSale.solschlägt immer noch fehl ...

Tx: 0x640771750ded31c0ef817d1e0df3a1ec16c186fd353a6034dd1799af26e486ed

TestTokenSale.sol

Konstruktorargumente:1511235849, 1530889758, 500, 10000000, 0xcede48d8ac162d1b08ed9419010de3c99f2cfdd6, 0x47a27fb4722f293b7ab499ef910d1f2ca78b94b6

pragma solidity ^0.4.15;

import "./libs/zeppelin/crowdsale/CappedCrowdsale.sol";
import "./libs/zeppelin/crowdsale/FinalizableCrowdsale.sol";
import './TestToken.sol';



contract TestTokenSale is CappedCrowdsale, FinalizableCrowdsale {

  address public tokenContractAddress;

  function TestTokenSale(uint256 _startTime, uint256 _endTime, uint256 _rate, uint256 _cap, address _wallet, address _tokenContractAddress)
    CappedCrowdsale(_cap)
    FinalizableCrowdsale()
    Crowdsale(_startTime, _endTime, _rate, _wallet)
  {
    token = TestToken(_tokenContractAddress);
  }

  function finalization() internal {
  }

}

Aktualisierung 3

Tx: 0x561f9cb4630905c2bb1391db3d3d1afd3b29cc454b238b25dbc3372f19c4a274

ETH sendet nur dann erfolgreich an den TestTokenSale.solVertrag, wenn Crowdsale.solbearbeitet wurde, um auszukommentieren require(validPurchase()):

Code funktioniert

  function buyTokens(address beneficiary) public payable {
    require(beneficiary != address(0));
    // require(validPurchase());
    ...

Code schlägt fehl

Das Senden von ETH schlägt fehl, wenn ich diese Zeile nicht auskommentiere, sondern validPurchase()auf setze return true:

  function buyTokens(address beneficiary) public payable {
    require(beneficiary != address(0));
    require(validPurchase());
    ...


  function validPurchase() internal constant returns (bool) {
    return true;
    // bool withinPeriod = now >= startTime && now <= endTime;
    // bool nonZeroPurchase = msg.value != 0;
    // return withinPeriod && nonZeroPurchase;
  }

Code funktioniert!!!

  // low level token purchase function
  function buyTokens(address beneficiary) public payable {
    require(beneficiary != address(0));
    require(now >= startTime);
    require(now <= endTime);
    require(msg.value != 0);
    // require(validPurchase());

Sollten require(validPurchase())keine Fehler ausgegeben werden, wenn validPurchase()zurückgegeben wird true?

Warum funktioniert es, wenn die 3 Bedingungen von validPurchase()out nach verschoben werden buyTokens, aber nicht funktionieren, wenn sie in `validPurchase()~ stehen?

Was passiert hier?

Haben Sie den Vertragscode? Von der Geth-Spur macht es nach einigen Überprüfungen eine Rückkehr. Und es ist noch früh bei der Ausführung, wahrscheinlich ist einer der Anforderungen/Zusicherungen fehlgeschlagen. Ohne Quellcode ist schwer mehr zu sagen.
@Ismael Ich habe den Vertragscode in der Frage gepostet und versucht, ihn erneut bereitzustellen, also beziehen Sie sich bitte auf den neuesten Transaktions-Hash 0xbbcff212c72e201412a3c4f4304d13e517212b793f04ae597399d2f375052b36. Sehen Sie etwas falsch mit dem Vertragscode?
Ihr Vertrag rinkeby.etherscan.io/address/… hat Parameter startTime: 0x5a139137 (1511231799) 2017-11-21T02:36:39+00:00, endTime: 0x5b3f861e (1530889758) 2018-07-06T15:09:18+00 :00. Ihre Sendung wurde um (1511232006) 2017-11-21T02:40:06+00:00 bearbeitet. Scheint also ok zu sein.
Das Problem sind Ihre Konstruktoraufrufe, Crowdsale()die wiederum aufrufen createTokenContract(), was zurückgeben wird TestToken(tokenContractAddress), aber es wird 0x0 zurückgeben, da tokenContractAddresses noch nicht initialisiert ist. Variable löschen tokenContractAddressund direkt in Ihrem Konstruktor zuweisentoken = MintableToken(_tokenContractAddress);
@Ismael Soll ich trotzdem überschreiben createTokenContract?
@Ismael Update 2 zur Frage basierend auf Ihrem Vorschlag hinzugefügt. Leider schlägt das Senden von ETH zum Vertrag immer noch fehl ...
Entschuldigung, aber ich kann Ihnen nicht weiter helfen, versuchen Sie es mit remix oder testrpc. Aus der Geth-Spur sind die letzten beiden Transaktionen genau gleich. Beachten Sie, dass mint()aufgerufen wird, buyTokens()aber es ist onlyOwnerso, dass Sie den Crowdsale als Besitzer des Tokens festlegen müssen, aber ich denke nicht, dass das hier der Fehler ist.
@Ismael Ich habe den Besitzer gewechselt und es sieht so aus, als würde es fast funktionieren! Damit es 100% funktioniert, musste ich require(validPurchase());in der Funktion buyTokensvon Crowdsale.sol... auskommentieren. Das Bearbeiten validPurchasevon führte dazu, return truedass der ETH-Versand auch fehlschlug ... Das ist so seltsam?
@Ismael Aktualisierter Beitrag mit Update 3 , um den vorherigen Kommentar besser zu erklären ... Ich bin so verwirrt

Antworten (2)

Wir hatten einige der gleichen Probleme wie du. Was wir herausgefunden haben, war Folgendes:

  1. startTimeund endTimemuss so eingestellt sein, dass Sie beim Aufrufen des Kontrakts tatsächlich Token kaufen, wenn der Verkauf offen ist. Wir haben eine hasStarted()Methode hinzugefügt und sowohl diese als auch die hasEnded()Methode aufgerufen, um sicherzustellen, dass wir uns tatsächlich innerhalb des Verkaufszeitraums befinden.
  2. Das startTimemuss in der Zukunft liegen. Ist dies nicht der Fall, wird nichts funktionieren. Aus diesem Grund addieren wir 90 Sekunden zum aktuellen Zeitstempel hinzu.
  3. Die Datentypen im Migrationsskript sind wirklich wichtig.
    • Sie können nicht einfach inn accounts[0]im Konstruktor senden – die Adresse muss eine Zeichenfolge sein, wenn sie aus der Migrationsdatei aufgerufen wird.
    • Sie können keine normale Nummer (wie 25) einsenden, da rate- es eine sein muss web3.BigNumber(25).

Als Referenz finden Sie hier unsere Migrationsdatei: 2_deploy_contracts.js

var MyTokenCrowdsale = artifacts.require("MyTokenCrowdsale");

module.exports = function(deployer, network, accounts) {
  const start = web3.eth.getBlock(web3.eth.blockNumber).timestamp + 90;
  const end = start + (86400 * 30); // 30 days
  const rate = new web3.BigNumber(25);
  wallet = accounts[1].toString();
  deployer.deploy(MyTokenCrowdsale, start, end, rate, wallet);
};
Arbeiten! Warum hast du eine web3.BigNumberstatt einer regulären intfür die bestanden?rate
Weil der Konstruktor erwartet, dass die Zahl a web3.BigNumberund nicht eine ist int.

Wenn man sich den Vertragscode ansieht, kann man sehen, dass der Vertrag Ether nur während des Zeitraums akzeptiert, in dem der Token-Verkauf stattfindet. Wenn Sie Ether außerhalb dieses Zeitraums senden, wird der Vertrag die Ausführung unterbrechen und Ihren Ether zurückgeben (dh was nach der Zahlung des Gases übrig ist, das für die Ausführung des Vertrags bis zu diesem Zeitpunkt erforderlich ist).

Der Zeitraum des Token-Verkaufs wird bei der Vertragserstellung durch Parameter _starttimeund _endtimevom Konstruktor festgelegt. Ich habe mir den Vertragsspeicher nicht angesehen, um zu überprüfen, welche Werte für _starttimeund festgelegt wurden _endtime. Sie könnten jedoch an dieser Stelle mit der Fehlersuche beginnen und überprüfen, ob angemessene Werte für _starttimeund _endtimebei der Vertragserstellung festgelegt wurden.

Ich habe überprüft, ob die Zeit, zu der ich die ETH zum Vertrag geschickt habe, zwischen dem _startTimeund liegt _endTime. Aber die Transaktion ist trotzdem fehlgeschlagen...
Zum Beispiel , _startTime=1511127652, _endTime=1530889758und die Zeit, zu der ich die ETH an den Vertrag gesendet habe, war 1511127656nach unixtimestamp.com/index.php
Das sollte also ok sein. Sie können versuchen, den Code beispielsweise mit Remix zu debuggen. Oder nehmen Sie Zeile für Zeile aus der buyTokens-Funktion heraus, setzen Sie den Vertrag jedes Mal ein, wenn Sie eine Zeile herausgenommen haben, und finden Sie heraus, in welcher Zeile die Dinge nicht so laufen, wie sie sollten. Allerdings etwas langweilig...
Toller Ansatz! Ich habe jede Codezeile einzeln auskommentiert, beginnend mit der letzten Zeile in der buyTokensFunktion, und token.mint(beneficiary, tokens);es scheint die Zeile zu sein, die dazu führt, dass der ETH-Sendevorgang fehlschlägt!
Der MintableTokenwurde getrennt vom CrowdsaleVertrag bereitgestellt, ich frage mich, ob dies ein Problem mit der mintFunktion mit den Modifikatoren verursacht onlyOwner canMint, vielleicht ist der Crowdsale-Vertrag nicht der Eigentümer des MintableToken?
Ich rannte transferOwnership, um das Eigentum an dem MintableTokenauf den CrowdsaleVertrag zu übertragen, und überprüfte, ob das ownerEigentum an MintableTokender Adresse des CrowdsaleVertrags ist. Das token.mint(beneficiary, tokens);Senden von ETH an den CrowdsaleVertrag scheitert jedoch immer noch ...