Können Verträge das Gas anstelle des Absenders der Nachricht bezahlen?

Ist es möglich, dass ein Vertrag die Gaskosten (oder einen Teil davon) bezahlt, die sich aus dem Abruf des Vertrags ergeben? Oder zahlt der Absender einer Nachricht in jedem Fall die anfallenden Spritkosten?

Irgendwie ja - siehe meine Antwort hier
> Gerade eine winzige Bibliothek veröffentlicht, um eine Möglichkeit zum Delegieren hinzuzufügen > Transaktionserstellung (Gebührenzahlung): > github.com/bitclave/Feeless Wie verhindert diese Methode doppelte Ausgaben?
Lesen Sie diese faule Migration von bitclave . Ich dachte daran, dies als Teil des Upgrade-Mechanismus zu verwenden, aber den Benutzer nicht bezahlen zu lassen. Ich denke, Ihre Bibliothek hilft.

Antworten (9)

Gegenwärtig muss der Benutzer, der die Transaktion einleitet, die Gebühr bezahlen. Serenity wird jedoch wahrscheinlich „Vertragszahlungssysteme“ ermöglichen. (Siehe Vitaliks Blogbeitrag hier ) Eine mögliche Problemumgehung ist ein Vertrag, der den Absender erstattet, dies würde jedoch immer noch erfordern, dass der Benutzer etwas Ether hält, und es böswilligen Parteien ermöglichen könnte, den Vertrag wiederholt aufzurufen, um seine Gelder zu erschöpfen.

Da gibt es bessere Workarounds. Ich werde versuchen, bei Gelegenheit eine Antwort zu posten.
Freue mich auf eure Workarounds
Ich hatte immer noch keine Zeit, dies zu tun, also werde ich anstelle einer vollständigen Antwort nur anmerken, dass Sie einen Mechanismus ähnlich dem Ethereum-Wecker verwenden können, um es so zu machen, dass Anwendungen ihre Transaktionen an zufällige Personen senden können, die dann " ihnen die Ether-Kosten des Vertrags leihen und dafür durch einen speziellen Vertrag erstattet werden, der vom Entwickler des Zielvertrags finanziert wird. Das Ergebnis ist eine App, bei der die Benutzer keinen Ether halten müssen. Offensichtlich möchte man der App eine Art Anti-Sybil-Element hinzufügen, um DoS zu verhindern. Eine einfache Möglichkeit wäre ein kleines PoW in der App.
@JeffColeman etwas spät warten, aber hast du zufällig mehr Details dazu geschrieben? Wäre wirklich daran interessiert, die vollständige Idee des Mechanismus zu bekommen, insbesondere wie der allererste Teil funktionieren würde.

Nein, ein Versender mit Zero Ether kann keinen Vertrag „verlangen“, um die Gaskosten zu bezahlen. Ein Absender mit Zero Ether kann nicht einmal eine Transaktion senden.

Weitere Details: Der Absender einer Transaktion muss über genügend Gas verfügen, um die Ausführung der Transaktion abzudecken. Dieses Gas wird benötigt, noch bevor ein Vertrag überhaupt abgerufen werden kann. Sobald die Gasanforderung erfüllt ist (so dass die Transaktion vollständig abläuft, ohne dass das Gas ausgeht), kann der aufgerufene Vertrag dem Absender den Betrag senden, den der Vertrag enthält: Das Nettoverhalten ist, dass der Absender am Ende mehr Ether haben kann als er angefangen, aber das unterscheidet sich von dem Vertrag, der das Gas bezahlt.

Es ist, als ob Sie zur Bank fahren könnten, um Geld zu holen, aber Sie brauchen zuerst Benzin, um zur Bank fahren zu können: Die Bank kann Ihnen kein Benzingeld schicken, bevor Sie zur Bank fahren.

Hier wird laufend über eine zukünftige Version (Serenity) diskutiert, die dieses Verhalten ändern kann.


Solidity hat eine gas()Syntax, wie die folgende, die in einer der Antworten hier erwähnt wird:

contract Gracious {
  function runMe() {
    this.realWork.gas(1000000)();
  }
}

gas()bedeutet nicht, den Ether des Vertrages zu verwenden, um das Gas zu bezahlen. gas()begrenzt die Gasmenge, die der Subcall ( realWork) erhält. Wenn runMemit 3.000.000 Gas versorgt wird, dann realWorkwerden höchstens 1.000.000 Gas verbraucht, so dass alle aufgerufenen Funktionen, wenn runMesie beendet sind, garantiert 2.000.000 Gas haben werden. Wenn realWorkmehr als 1.000.000 Gas verbraucht werden, wird sofort eine Ausnahme generiert, alle 3.000.000 Gas werden an den Miner gezahlt und die Transaktion wird rückgängig gemacht.

Kopieren meiner Antwort von hier Wie kann ich jemanden dazu bringen, für Gas zu bezahlen?

Es gibt 2 Problemumgehungen mit ihren Vor- und Nachteilen:

  1. Verwenden Sie Signaturen

    • Jede Funktion in Ihrem Smart Contract muss signatureParameter haben.
    • Personen, die mit dem Smart Contract interagieren möchten, müssen die Funktionsparameter mit dem privaten Schlüssel ihres Kontos signieren und an den Eigentümer des Smart Contract senden (über einen beliebigen Kommunikationskanal).
    • Der Eigentümer übermittelt dann die Parameter zusammen mit der Signatur an die Blockchain und bezahlt für Gas. Die Signatur garantiert, dass die Nachricht vom Benutzer genehmigt wurde.
  2. Erstattung des verbrauchten Gases am Ende der Transaktion. Dazu kann ein Modifikator verwendet werden (siehe unten).

Nachfolgend finden Sie weitere Details für jede Option:


Signaturen verwenden

Hier ist ein einfacher ReceiverPaysVertrag, der es ermöglicht, den Empfänger der Zahlung für Gas bezahlen zu lassen:

pragma solidity ^0.4.20;

contract ReceiverPays {
    address owner = msg.sender;

    mapping(uint256 => bool) usedNonces;

    // Funds are sent at deployment time.
    function ReceiverPays() public payable { }


    function claimPayment(uint256 amount, uint256 nonce, bytes sig) public {
        require(!usedNonces[nonce]);
        usedNonces[nonce] = true;

        // This recreates the message that was signed on the client.
        bytes32 message = prefixed(keccak256(msg.sender, amount, nonce, this));

        require(recoverSigner(message, sig) == owner);

        msg.sender.transfer(amount);
    }

    // Destroy contract and reclaim leftover funds.
    function kill() public {
        require(msg.sender == owner);
        selfdestruct(msg.sender);
    }


    // Signature methods

    function splitSignature(bytes sig)
        internal
        pure
        returns (uint8, bytes32, bytes32)
    {
        require(sig.length == 65);

        bytes32 r;
        bytes32 s;
        uint8 v;

        assembly {
            // first 32 bytes, after the length prefix
            r := mload(add(sig, 32))
            // second 32 bytes
            s := mload(add(sig, 64))
            // final byte (first byte of the next 32 bytes)
            v := byte(0, mload(add(sig, 96)))
        }

        return (v, r, s);
    }

    function recoverSigner(bytes32 message, bytes sig)
        internal
        pure
        returns (address)
    {
        uint8 v;
        bytes32 r;
        bytes32 s;

        (v, r, s) = splitSignature(sig);

        return ecrecover(message, v, r, s);
    }

    // Builds a prefixed hash to mimic the behavior of eth_sign.
    function prefixed(bytes32 hash) internal pure returns (bytes32) {
        return keccak256("\x19Ethereum Signed Message:\n32", hash);
    }
}

Weitere Details finden Sie in diesem Artikel https://programtheblockchain.com/posts/2018/02/17/signing-and-verifying-messages-in-ethereum/

Die Einschränkung dieses Ansatzes besteht darin, dass Ihr Smart Contract, wenn er mit anderen Verträgen interagieren muss, auch das gleiche Muster implementieren muss, indem er jeder Methode Signaturen hinzufügt.


Rückerstattung des verbrauchten Gases an den Transaktionssender

Es ist keine ideale Lösung, aber Sie können dem Absender der Transaktion die Benzinkosten erstatten. Sie können dies mit einem Modifikator tun:

pragma solidity^0.4.11;

contract SomeContract {

    event SomeEvent(address sender);

    // Need to allow depositing ether to the contract
    function() public payable {
    }

    modifier refundGasCost()
    {
        uint remainingGasStart = msg.gas;

        _;

        uint remainingGasEnd = msg.gas;
        uint usedGas = remainingGasStart - remainingGasEnd;
        // Add intrinsic gas and transfer gas. Need to account for gas stipend as well.
        usedGas += 21000 + 9700;
        // Possibly need to check max gasprice and usedGas here to limit possibility for abuse.
        uint gasCost = usedGas * tx.gasprice;
        // Refund gas cost
        tx.origin.transfer(gasCost);
    }

    function doSomething() external refundGasCost {
        SomeEvent(msg.sender);  
    }
}

Die Rückerstattung auf diese Weise bedeutet einen gewissen Overhead: Mindestens 9700 Gas müssen für den transferFunktionsaufruf innerhalb des refundGasCostModifikators extra bezahlt werden. Auch Gas für andere Opcodes in refundGasCostsollte hinzugefügt werden usedGas.


https://github.com/ethereum/wiki/wiki/Design-Rationale

Die Verpflichtung von Transaktionssendern, für Gas anstelle von Verträgen zu zahlen, erhöht die Benutzerfreundlichkeit für Entwickler erheblich. Sehr frühe Versionen von Ethereum hatten Verträge, in denen Gas bezahlt wurde, aber dies führte zu dem ziemlich hässlichen Problem, dass jeder Vertrag einen „Wach“-Code implementieren musste, der sicherstellen würde, dass jede eingehende Nachricht den Vertrag mit genügend Ether kompensierte, um für das Gas zu bezahlen, das es war verbraucht.

...

ORIGIN: Die primäre Verwendung des ORIGIN-Opcodes, der den Absender einer Transaktion angibt, besteht darin, Verträgen zu ermöglichen, Rückerstattungszahlungen für Gas zu leisten.

Dies sollte mehr positiv bewertet werden, da dies derzeit die einzige Möglichkeit ist, Gebühren für den Anrufer zu zahlen.

Nicht alle Anrufe mit Vertrag benötigen Gas. Es ist der sogenannte „Trockenlauf“. https://github.com/ethereum/go-ethereum/wiki/Contracts-and-Transactions#interacting-with-contracts

Nun werden alle im abi spezifizierten Funktionsaufrufe auf der Vertragsinstanz zur Verfügung gestellt. Sie können diese Methoden einfach auf der Vertragsinstanz aufrufen und sendTransaction(3, {from: address}) oder call(3) damit verketten. Der Unterschied zwischen den beiden besteht darin, dass call lokal auf Ihrem Computer einen „Trockenlauf“ durchführt, während sendTransaction Ihre Transaktion tatsächlich zur Aufnahme in die Blockchain einreicht und die Ergebnisse ihrer Ausführung schließlich Teil des globalen Konsenses werden. Mit anderen Worten, verwenden Sie call, wenn Sie nur am Rückgabewert interessiert sind, und verwenden Sie sendTransaction, wenn Sie sich nur um "Nebenwirkungen" auf den Vertragsstatus kümmern.

So ist es möglich, den Nutzern eine Methode in einem Vertrag zum Nullgaspreis zur Verfügung zu stellen – im Beispiel oben ist es die Multiplikationsfunktion.

Sie haben Recht, es gibt einen Trockenlauf und die Frage verwendet "Absender einer Nachricht" anstelle von "Absender einer Transaktion", was genauer wäre.

Ich habe gerade eine winzige Bibliothek veröffentlicht, um die Möglichkeit hinzuzufügen, die Transaktionserstellung (Gebührenzahlung) zu delegieren: https://github.com/bitclave/Feeless

Sie brauchen nur:

  1. Erben Sie Ihren Smart Contract von FeelessSmart Contract
  2. Fügen feelessSie einen Modifikator für alle Methoden hinzu, die Sie indirekt aufrufen möchten
  3. Verwenden Sie msgSenderstattdessen msg.senderin diesen Methoden und Methoden, die intern von ihnen aufgerufen werden

Und jeder wird in der Lage sein, Gebühren für jeden anderen völlig vertrauenslos zu bezahlen. Beispielsweise kann der Dienst Gebühren für Benutzertransaktionen zahlen und diese Gebühren mit eigenen Token-Gebühren kompensieren.

Nur um das klarzustellen, funktioniert dies, indem dem Anrufer Gebühren erstattet werden? Ich habe mir Ihren Code angesehen und habe Probleme herauszufinden, wo dies passiert. Die Zeilen 24-28 überprüfen die Signatur und Nonce, Zeile 30 ruft die gewünschte Funktion auf, aber wo findet die Berechnung des Rückzahlungsbetrags und die Rückzahlung selbst statt?
Dieser Vertrag ermöglicht es, einen Untervertrag zu erstellen, bei dem jeder etwas für jeden ausführen kann, basierend auf der Signaturüberprüfung. Es scheint, dass GSN auf dem gleichen Ansatz basiert.

Sehen Sie sich den Fuel Web3-Anbieter an : https://github.com/ahmb84/fuel-web3-provider

"Treibstoff ermöglicht es Entwicklern, ein Finanzierungssystem zu seiner DApp hinzuzufügen und so Transaktionen für den Endbenutzer gebührenfrei zu machen."

Hier ist eine Referenzimplementierung: https://github.com/ahmb84/fuel-node-example

Wie funktioniert es? Das kann ich auf der Github-Seite nicht sagen.

Diese Antworten sind gut, aber mir ist aufgefallen, dass sie ein wenig auf der alten Seite sind und es eine Möglichkeit gibt, eine Transaktion zu senden, auch wenn sie keinen Äther haben. Sie brauchen nur ein wenig Hilfe: https://medium.com/@andreafspeziale/understanding-ethereum-meta-transaction-d0d632da4eb2

Es ist schwierig, aber es hängt nicht von einem Protokoll-Upgrade ab.

Ein grob zusammengefasster Prozess funktioniert so:

  1. Der Unterzeichner unterzeichnet eine Transaktion für den Vertrag/die Blockchain, sendet sie aber nicht auf die übliche Weise. Das würde Sprit kosten.
  2. Der Unterzeichner leitet die Nachricht (off-chain) an ein Relay weiter. Das Relais ist irgendwo ein Server, der für Benzin bezahlt. Es hat eine signierte Nachricht, die gültig wäre , wenn sie an Ethereum gesendet würde.
  3. Das Relais sendet die unterzeichnete Transaktion und zahlt für Benzin.

Ich hoffe es hilft.

Derzeit nicht, wird aber derzeit mit einer EIP diskutiert. Gavin Wood sagt, dass es derzeit eine Möglichkeit gibt, dies zu tun, aber nach meinem Verständnis ist es so etwas wie ein Hack.

Irgendwelche Hinweise auf EIP?

Zunächst möchte ich @eth und @medvedev1088 für ihre Antworten danken. @eth sagt das

Es ist, als ob Sie zur Bank fahren könnten, um Geld zu holen, aber Sie brauchen zuerst Benzin, um zur Bank fahren zu können: Die Bank kann Ihnen kein Benzingeld schicken, bevor Sie zur Bank fahren.

Ich denke, dass jeder, der mit Utility-Token arbeitet, mit diesem anfänglichen Problem konfrontiert ist. Als Entwickler ist es mir wichtig, weil es nicht benutzerfreundlich ist, Benutzer zu fragen, die Ethereum von Börsen oder Einheimischen kaufen. Daher suche ich nach möglichen Lösungen, die das 'Erst-Token-Problem' umgehen. Die Antwort von @ medvedev1088 scheint auf den ersten Blick eine Lösung zu sein. Ich habe es vor dem Testen nicht bemerkt, aber nach dem Test, den ich gemacht habe, kann ich leicht sagen

Der Empfänger fordert seine Zahlung an, indem er die signierte Nachricht dem Smart Contract vorlegt. Der Smart Contract überprüft seine Authentizität und gibt dann die Gelder frei.

aus seinem Blog ist etwas irreführend. Denn wer zum ersten Mal mit Smart Contract interagieren will, braucht Gas.

Wenn Sie Ihr eigenes privates Netzwerk haben, können Sie es mit dem folgenden Code testen. (Bevor Sie es ausführen, müssen Sie mindestens 6 Ether vertraglich bereitstellen und von Ihrem Coinbase-Konto aus bereitstellen.)

Code kann in dieser Geige gefunden werden

Ich hoffe, ich habe den ersten Ansatz von @medvedev1088 nicht falsch verstanden.