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?
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.
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 runMe
mit 3.000.000 Gas versorgt wird, dann realWork
werden höchstens 1.000.000 Gas verbraucht, so dass alle aufgerufenen Funktionen, wenn runMe
sie beendet sind, garantiert 2.000.000 Gas haben werden. Wenn realWork
mehr 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:
Verwenden Sie Signaturen
signature
Parameter haben.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 ReceiverPays
Vertrag, 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 transfer
Funktionsaufruf innerhalb des refundGasCost
Modifikators extra bezahlt werden. Auch Gas für andere Opcodes in refundGasCost
sollte 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.
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.
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:
Feeless
Smart Contractfeeless
Sie einen Modifikator für alle Methoden hinzu, die Sie indirekt aufrufen möchtenmsgSender
stattdessen msg.sender
in diesen Methoden und Methoden, die intern von ihnen aufgerufen werdenUnd 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.
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
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:
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.
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.
SCBürgel
David Ju
shonjs