91

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?

3
  • 2
    Kind of yes - see my answer here
    – SCBuergel
    Commented 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 Yu
    Commented 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.
    – shonjs
    Commented Aug 12, 2018 at 15:14

9 Answers 9

41

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.

5
  • 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
    Looking forward to your workarounds
    – Randomblue
    Commented Feb 8, 2016 at 22:35
  • 5
    Still 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-flor
    Commented 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
31

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.

16

Copying my anwer from here How to make someone else pay for Gas?

There are 2 workarounds with their pros and cons:

  1. 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.
  2. 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.

1
  • 1
    This should be upvoted more, since it‘s currently the only way to pay fees for the caller.
    – ivicaa
    Commented Apr 4, 2018 at 8:07
8

Just published a tiny library to add an ability to delegate transaction creation (fees payment): https://github.com/bitclave/Feeless

You need just:

  1. Inherit your smart contract from Feeless smart contract
  2. Add feeless modifier for any methods you wanna allow to call indirectly
  3. Use msgSender instead of msg.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.

2
  • 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.
    – k06a
    Commented Jan 8, 2021 at 17:04
7

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.

1
  • 1
    You'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
2

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

1
2

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:

  1. The signer signs a transaction for the contract/blockchain but doesn't send it in the usual way. That would cost gas.
  2. 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.
  3. The relay sends the signed transaction and pays for gas.

Hope it helps.

1

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.

1
  • 5
    Any pointers to EIP? Commented Oct 17, 2017 at 20:10
1

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.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.