Is it possible for a contract to pay the gas costs (or part of it) that result from the contract being called? Or does the sender of a message always pay the resulting gas costs no matter what?
-
2Kind of yes - see my answer here– SCBuergelCommented Jan 28, 2018 at 15:59
-
1> Just published a tiny library to add an ability to delegate > transaction creation (fees payment): > github.com/bitclave/Feeless How does this method prevent double spending?– David YuCommented Apr 26, 2018 at 8:28
-
Read this lazy migration from bitclave . Was thinking of using this as part of upgrade mechanism, but not let the user pay. I think your library helps.– shonjsCommented Aug 12, 2018 at 15:14
9 Answers
At present the user initiating the transaction must pay the fee. However Serenity is likely to enable 'contract pays' schemes. (See Vitalik's blog post here) A possible work around is a contract which refunds the sender however this would still require the user to hold some Ether and might allow malicious parties to repeatedly call the contract to deplete its funds.
-
There are better workarounds then that. I'll try and post an answer when I get a chance. Commented Jan 21, 2016 at 3:41
-
1
-
5Still haven't had time to do this, so in lieu of a full answer I'll just note that you can use a mechanism similar to the Ethereum Alarm Clock to make it so that applications can submit their transactions to random individuals who then "lend" them the ether cost of the contract and are reimbursed for it by a special contract funded by the destination contract's developer. The result is an app which does not require users to hold any ether. Obviously one would want to add some sort of anti-sybil element to the app to prevent DoS. One simple way would be a small PoW in the app. Commented Feb 28, 2016 at 17:10
-
2@JeffColeman a bit of a late wait on this one, but did you by any chance write more details on this one? Would be really interested to get the full mechanism idea, especially how the very first part would work.– el-florCommented Oct 5, 2017 at 21:13
-
Has Vitaliks's suggestions ever been implemented in or since Serenity? Can we now have the "contract pays" dynamic? Commented Feb 26 at 11:51
No, a sender with zero ether cannot "ask" a contract to pay for the gas costs. A sender with zero ether cannot even send a transaction.
More details: The sender of a transaction must have enough gas to cover execution of the transaction. That gas is required even before a contract can even be called. Once the gas requirement is met (so that the transaction runs fully without running out of gas), the called contract can send the sender whatever amount of funds the contract holds: the net behavior is that the sender can end up with more ether than they started with, but that is different from the contract paying the gas.
It's like you can drive to the bank to get money, but you need fuel first to be able to drive to the bank: the bank can't send you fuel money before you drive to the bank.
There is ongoing discussion here for a future release (Serenity) that can change this behavior.
Solidity has gas()
syntax, like the following mentioned in one of the answers here:
contract Gracious {
function runMe() {
this.realWork.gas(1000000)();
}
}
gas()
does not mean use contract's ether to pay for the gas.
gas()
limits the amount of gas that the subcall (realWork
) gets. If runMe
is provided with 3,000,000 gas, then realWork
will at most consume 1,000,000 gas, so that any functions called when runMe
is finished, will be guaranteed to have 2,000,000 gas. If realWork
consumes more than 1,000,000 gas, then an exception will be generated immediately, all 3,000,000 gas is paid to the miner, and the transaction is reverted.
Copying my anwer from here How to make someone else pay for Gas?
There are 2 workarounds with their pros and cons:
Use signatures
- Every function in your smart contract must have
signature
parameter. - People who want to interact with the smart contract must sign the function parameters with their account's private key and send it to the smart contract owner (via any communication channel).
- The owner then submits the parameters along with the signature to the blockchain, paying for gas. The signature guarantees that the message was approved by the user.
- Every function in your smart contract must have
Refund used gas at the end of the transaction. A modifier can be used for this (see below).
Below are more details for each option:
Using signatures
Here is a simple ReceiverPays
contract that allows making the receiver of the payment pay for gas:
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);
}
}
More details can be found in this article https://programtheblockchain.com/posts/2018/02/17/signing-and-verifying-messages-in-ethereum/
The limitation of this approach is that if your smart contract needs to interact with other contracts, then they must also implement the same pattern with adding signatures to every method.
Refunding used gas to the transaction sender
It's not an ideal solution but you can refund gas cost to the transaction sender. You can do this with a modifier:
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);
}
}
Refunding in this way implies some overhead: at least 9700 gas has to be payed extra for the transfer
function call inside refundGasCost
modifier. Also gas for other opcodes in refundGasCost
should be added to usedGas
.
https://github.com/ethereum/wiki/wiki/Design-Rationale
Requiring transaction senders to pay for gas instead of contracts substantially increases developer usability. Very early versions of Ethereum had contracts pay for gas, but this led to the rather ugly problem that every contract had to implement "guard" code that would make sure that every incoming message compensated the contract with enough ether to pay for the gas that it consumed.
...
ORIGIN: the primary use of the ORIGIN opcode, which provides the sender of a transaction, is to allow contracts to make refund payments for gas.
-
1This should be upvoted more, since it‘s currently the only way to pay fees for the caller.– ivicaaCommented Apr 4, 2018 at 8:07
Just published a tiny library to add an ability to delegate transaction creation (fees payment): https://github.com/bitclave/Feeless
You need just:
- Inherit your smart contract from
Feeless
smart contract - Add
feeless
modifier for any methods you wanna allow to call indirectly - Use
msgSender
instead ofmsg.sender
in these methods and methods internally called by them
And anyone will be able to pay fees for any other in a fully trustless way. For example, service can pay fees for user transactions and compensate this fees with own tokens fees.
-
Just to be clear, this works by refunding fees to the caller? I have looked at your code and I'm having trouble figuring out where this happens. Lines 24-28 verify the signature and nonce, line 30 calls the desired function, but where does calculation of payback amount and the payback itself happen? Commented Jan 7, 2021 at 16:19
-
This contract allows to build subcontract where anyone can execute something for anyone based on signature verification. It seems GSN is build on the same approach.– k06aCommented Jan 8, 2021 at 17:04
Not all calls on a contract need gas. It is the so called "dry-run". https://github.com/ethereum/go-ethereum/wiki/Contracts-and-Transactions#interacting-with-contracts
Now all the function calls specified in the abi are made available on the contract instance. You can just call those methods on the contract instance and chain sendTransaction(3, {from: address}) or call(3) to it. The difference between the two is that call performs a "dry run" locally, on your computer, while sendTransaction would actually submit your transaction for inclusion in the block chain and the results of its execution will eventually become part of the global consensus. In other words, use call, if you are interested only in the return value and use sendTransaction if you only care about "side effects" on the state of the contract.
So it is possible to provide a method in a contract to users for zero gas costs - in the example above it is the multiply function.
-
1You're right there is dry-run and the question used "sender of a message" instead of "sender of a transaction" which would be more precise.– eth ♦Commented Jan 26, 2016 at 14:18
Check out Fuel Web3 Provider: https://github.com/ahmb84/fuel-web3-provider
"Fuel enable developers to add a funding system to his Dapp and so make transactions feesless for the end user."
Here is a reference implementation: https://github.com/ahmb84/fuel-node-example
-
How does it work? I can't tell from the github site. Commented Jan 7, 2021 at 16:31
These answers are good but I noticed they are a little on the old side and there is a way to send a transaction even when they have no ether. They just need a little help: https://medium.com/@andreafspeziale/understanding-ethereum-meta-transaction-d0d632da4eb2
It's tricky, but it doesn't depend on a protocol upgrade.
A grossly summarized process works like this:
- The signer signs a transaction for the contract/blockchain but doesn't send it in the usual way. That would cost gas.
- The signer forwards the message (off-chain) to a relay. The relay is a server somewhere that pays for gas. It has a signed message that would be valid if it was sent to Ethereum.
- The relay sends the signed transaction and pays for gas.
Hope it helps.
Not at present but is currently being discussed with an EIP. Gavin Wood says that there is a way to do it presently but from my understanding it's something of a hack.
-
5
Firstly, I want to thanks @eth and @medvedev1088 for their answers. @eth states that
It's like you can drive to the bank to get money, but you need fuel first to be able to drive to the bank: the bank can't send you fuel money before you drive to the bank.
I think that everyone who works on utility tokens, face this initial problem. I care as a developer because it's not user friendly to ask users purchasing ethereum from exchanges or locals. Therefore, I search for possible solutions which work around 'first token problem'. @medvedev1088's answer seems as a solution at first-glance. I did not realize before testing it, but after the test I have done, I can easily say
The recipient claims their payment by presenting the signed message to the smart contract. The smart contract verifies its authenticity and then releases the funds.
from his blog is a bit misleading. Because anyone who wants to interact with smart contract for the first time needs gas.
If you have your own private network, you can test with below code. (Before executing it, you need to deploy contract at least 6 ether, and deploy it from your coinbase account)
Code can be found in this fiddle
I hope, I did not misunderstand @medvedev1088's first approach.