Wie kann man jemand anderen für Gas bezahlen lassen?

Mein Verständnis ist, dass msg.senderdie Gasgebühr bezahlt wird. Kann ein Smart Contract so geschrieben werden, dass immer der Vertragsinhaber die Gebühren bezahlt?

Als Beispiel zahlt jemand bei einem ERC20-Token die Gasgebühr, wenn er die Token überträgt, aber was ist, wenn die Gasgebühr für jeden transferSmart-Contract-Inhaber bezahlt werden muss?

In einem der kommenden Ethereum-Updates können Sie Ihren Vertrag für das Gas bezahlen lassen.
@Orry Wir sind 3 Jahre nach deinem Kommentar, ist dieses Update schon gekommen?

Antworten (5)

Es gibt 2 Möglichkeiten 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 refundGasCostverwendet 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.

Außerdem ist der obige Code potenziell anfällig für Reentrancy und andere Angriffe. Ich habe es nur als Beispiel angegeben und nicht gründlich getestet.


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.

Danke! Ich suchte nach etwas, bei dem der Smart-Contract-Benutzer in erster Linie kein Gas zahlen muss. Trotzdem ist deine Lösung wirklich interessant :)
Interessant. Hat das jemand versucht?
Ich habe es nur im Remix probiert. Das berechnete verbrauchte Gas entspricht nicht genau dem tatsächlich verbrauchten Gas, liegt aber ziemlich nahe daran.
Sich auf tx.origin zu verlassen wird seit einiger Zeit nicht mehr empfohlen ethereum.stackexchange.com/a/200
@Ismael ist es ein echter Vitalik Buterin oder ein Troll? Ich habe nirgendwo in den offiziellen Dokumenten festgestellt, dass man sich auf tx.origin verlassen kann (außer es kann nicht für die Autorisierung herangezogen werden).
@Ismael Interessanterweise habe ich dies gerade in Design Rationale gefunden: ORIGIN: Die Hauptverwendung des ORIGIN-Opcodes, der den Absender einer Transaktion bereitstellt, besteht darin, Verträgen die Möglichkeit zu geben, Rückerstattungszahlungen für Gas zu leisten. github.com/ethereum/wiki/wiki/Design-Rationale
@medvedev1088 Er ist der Echte. Es gab einen Exploit, bei dem ein böswilliger Vertrag einen Vertrag angreifen kann, der sich auf tx.origin verlässt, um sich als unvorsichtiger Benutzer auszugeben.

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.

Sehr elegant! Versuchen Sie, Ihre Antwort auch hier zu posten ethereum.stackexchange.com/questions/144/… . Vielleicht bekommt es mehr Reichweite.

Die Frage wurde im Februar 2018 gestellt, das scheint eine alte Geschichte im Etheruem-Raum zu sein.


Stichworte „Meta-Transaktionen“ und „Tankstellennetz“:

Jüngste Beispiele für gaslose Token-Sends:

USDC

https://medium.com/centre-blog/centre-consortium-announces-release-of-usd-coin-version-2-0-37ee8b27e09b

USDC 2.0 führt „Gasless Sends“ ein, was es Wallet- und App-Entwicklern ermöglicht, die Komplexität der Gasgebühren (und die Notwendigkeit, dass der Kunde ein Ether-Guthaben halten muss) zu abstrahieren und stattdessen die Zahlung der Gasgebühren an eine andere Adresse zu delegieren. Dies ermöglicht Entwicklern, diesen Dienst entweder selbst bereitzustellen oder einem Drittanbieter die damit verbundenen Gebühren zu zahlen.

ANTv2

https://aragon.org/blog/antv2

Es gab auch andere erstaunliche Entwicklungen in der Welt der Ethereum-Token, einschließlich gasloser Überweisungen. Gaslose Transfers ermöglichen es Relayern oder anderen Dritten, Token-Transfers für Benutzer zu subventionieren

EIP-3009, die sie verwenden: https://eips.ethereum.org/EIPS/eip-3009

Leider nein, es ist nicht möglich, dass ein anderer Benutzer als der Benutzer, der die Transaktion veranlasst hat, für das Benzin bezahlt. Über msg.sendersiehe die Bearbeitung unten.

Es gab einige Diskussionen darüber, die Signatur aus dem Protokoll zu abstrahieren und dann selbstzahlende Smart-Contracts zuzulassen.

Dies waren jedoch nur Diskussionen und dieses Feature ist nicht einmal in einer technischen Implementierung entworfen.

Den Beginn der Diskussion finden Sie hier und die aktuelle Fortführung der Diskussion dort

BEARBEITEN :

Beachten Sie zur Information, dass msg.senderdies nicht unbedingt der Benutzer ist, der die Transaktion initiiert hat.

Nehmen wir Two Contract A & B und stellen wir uns vor, A ruft eine Methode in B Contract auf. Dann hat die in B aufgerufene Methode für die msg.senderVertragsadresse von A.

Die ursprüngliche Adresse wird meistens als tx.origindie Adresse bezeichnet, von der die Transaktion stammt, wo immer wir in der Transaktion zeigen.

Beachten Sie auch, dass es beim Codieren eines Smart-Contracts nicht empfohlen wird tx.origin, festzustellen, wer die Transaktion gesendet hat, sondern einen Parameter in der Methodensignatur zu verwenden, um den Benutzer zu identifizieren.

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