Layer 2 gas payment abstraction


#1

Suppose that a user wants to make an ERC20 token transfer, but pay transaction fees in that ERC20, instead of ether. We can do that without modifying the base layer protocol by extending the ERC20 protocol as follows. We add a function submitSignedPayments({to: address, value: uint256, fee: uint256, deadline: uint256, seq: uint256, sig: bytes[65]}[]), which works as follows. For each submitted payment:

  • Let sender = ecrecover(hash(to, value, fee, seq, deadline, self), sig)
  • Verify that balances[sender] >= value + fee
  • Verify that seqs[sender] == seq
  • Verify that block.number <= deadline
  • Set balances[sender] -= value + fee
  • Set balances[to] += value
  • Set balances[msg.sender] += fee
  • Set seqs[sender] += 1

Users wishing to send ERC20 tokens could publish offchain messages offering a fee, and then simply wait until someone includes their message in a transaction.

Note that the 21000 gas overhead of a publishing transaction can be shared between multiple ERC20 contracts, by creating a central routing contract that accepts a list of signed payment objects and then calls submitSignedPayments of each ERC20 contract with its associated signed payment as needed.


We can abstract this much further if we combine it together with an account abstraction scheme. Consider an abstraction scheme where user accounts are contracts, and transactions are calls to accounts, with the msg.sender set to the block.coinbase. We assume also that with account abstraction, users can create transactions that queue up multiple operations. However, user accounts can’t just be called by transactions, you can also have another contract call the user account as part of a transaction.

A user can send a transaction with two operations: (i) send the msg.sender some tokens of some ERC20, (ii) perform some other task. A series of transactions of this type can then be put into a wrapper transaction which pays ETH fees, which can then get published on chain. The publisher of the wrapper transaction would collect the tokens.


#2

Coincidentally, the first part of this is exactly what we considered doing for Althea. Our ERC20 could mint tokens 1-1 from DAI, wrapping it. In addition to the gasless transfers it would also have gasless payment channel operations, plus an extra reward for “bounty hunting” by preventing an old update attack.


#3

Yes! I love this kind of stuff. I did the first part for one of my weekly R&D pieces a couple weeks ago! I totally missed the deadline part but that would be important.

It seems like we should be integrating signed message recovery into all of our newly deployed contracts just to provide for better UX in the future.

Here is the repo with a screencast:


Here is the article:

As for batched signed messages, I like George at LimeChain’s:

The last part about account abstraction is out of my wheelhouse and I’ll have to read more. I’m assuming we aren’t just talking delegated execution through an identity contract.


#4

I recently submitted ERC draft 1613 that supports similar operations, but extends to any dapp rather than specifically for tokens.

Basically it’s a protocol for adding “reverse charge” calls to contracts, using a central contract (RelayHub), through which multiple trustless relayers can “mine” transactions. Adding a token-based payment mechanism on top of that EIP can be done in the recipient’s map_relay() function.

One primary difference from @vbuterin 's suggestion above is that the user gets immediate guarantee that the transaction has been handled, without waiting for someone to pick the transaction from the pool. The user selects the relayer from RelayHub’s registrar, interacts with the relayer, and gets a signed transaction that acts as a “performance bond”, ensuring that the relay will submit the transaction, or would be penalized otherwise. Misbehaving relayers can be detected immediately without causing delays or malfunctions.

Trust is placed in the singleton contract (RelayHub) so the rest of the system is decentralized, with proper incentives to all actors to ensure that the system remains robust and fair. The different actors in the system (relays, users, contracts) don’t need to trust each other, as behaviors are enforced by RelayHub.

Got some good feedback for the draft above from community members. I’d love to get more.

Initial implementation available here.


#5

Thanks! I will look very closely at that medium article!


#6

This proposal is very similar to ERC-865, worth taking a look if you have time.

A simplification of account abstraction would be to say that account abstraction is making all accounts smart wallets by default. For L2 account abstraction, Gnosis Safe is probably the best model that I know of.


#7

if block.coinbase is used instead of msg.sender and msg.gasPrice == 0 then we could remove the transaction publisher signature verification, as it would be only bloating the processing and no represent no state change over publisher balance.
I posted this suggestion here Gas Abstraction: Non signed "block validator"-only procedures
This is not necessary for the implementation of gas abstraction but nodes would benefit from less processing.


#8

I’m also working into a payment channel for paying the gas of transaction, where instead of the relayed transaction moving tokens it would simply kick a nonce in the payment channel, which would be necessary for payout using the sender signature.

This function is called by the Account Contract after the execution is complete:


That ends up in:

Which is required here:


#9

What’s the point of this? The recipient gets no guarantee, because the sender could just double-spend by cooperating with a different relayer that uses a higher gasprice to move all their coins out.


#10

The guarantee is not for the tokens recipient. The recipient still needs to see the transaction mined on-chain. This is not a layer 2 network, but a way to transact on layer 1 without having ETH for gas. The guarantee is for the sender, that the relayer will actually relay it to the blockchain in a timely manner, with the parameters and gas price set by the sender.

The point is to avoid the need for an additional off-chain transaction pool, and guarantee that the transaction ends up in the mining pool. The sender selects a single relayer from the RelayHub registrar and talks to it (through web API or a similar channel) rather than submitting the transaction to a global relaying pool. Therefore the sender needs to know immediately whether the relayer relayed the transaction, and not wait for mining. Otherwise a group of malicious relayers could censor transactions by just stalling. If the relayer is misbehaving, the sender knows it immediately and connects to a different relayer, so the delay is measured in seconds rather than minutes. No way for a relayer to stall the sender from getting to the blockchain.

The motivation to talk to a single relayer from a decentralized relayers-pool, rather than a transaction pool, is to:

  1. Not add delay, in addition to that of the Ethereum mining process. Gasless transactions take the same amount of time as normal transactions, and are as secure as normal trasactions.
  2. Not require the use of a P2P protocol, since a similar level of censorship-resistance can be achieved through “standard” protocols. We’re trying to make Ethereum accessible to etherless users running mobile apps, possibly in restricted environments (e.g. enterprise/gov networks). As long as the user can open an http connection (even proxied), the user can transact on Ethereum. This removes two of the biggest technical obstacles for Ethereum adoption in such environments - the need for users to have ETH, and the requirement to use non-http protocols. Currently, mobile apps rely on centralized nodes (e.g. Infura) to communicate with the blockchain. This protocol decentralizes it while remaining practical for mobile apps and enterprise environments.

As for why this protocol achieves the desired level of censorship resistance, see “Attacks and mitigations” section under https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1613.md#rationale

What we’re doing here, is removing the wait and the someone from it.

The user is in control. The user selects a relayer to publish the transaction, agrees on the fee, and gets a service guarantee. At that point, the transaction is guaranteed to end up in the transaction pool with all other Ethereum transactions.


#11

In the original proposal, assuming that there’s profit to be made from relaying transactions, the market should make sure that someone is willing to do so. There shouldn’t be any delay in this occurring since there will be race to earn what is essentially free money.

That actually points to an issue which is that there is a significant coordination problem. It’s likely that a large number of people will all attempt to submit the transaction assuming that there is a profit to be made. All of the transactions except for the first will fail and cost the submitter gas without any reward.

Selecting a particular relayer eliminates this issue.


#12

Exactly. That’s part of what we were aiming to solve. The sender is the one most incentivized to get the transaction to the blockchain, so we leave it to the sender to find a relayer and negotiate the fee (and we give the sender the tools to do that, with on-chain information).

The sender and the contract are both incentivized to get the transaction delivered, so the system is focused on incentivizing relayers to provide the service, and lets the users and dapp owners decide who to work with, how much to pay, etc. Prices will be determined by the market, with rates published by relayers through RelayHub.