New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EIP1035: Transaction execution batching and delegation #1035

Open
k06a opened this Issue Apr 25, 2018 · 8 comments

Comments

Projects
None yet
6 participants
@k06a

k06a commented Apr 25, 2018


eip: EIP1035
title: Transaction execution batching and delegation
author: Anton Bukov (@k06a) k06aaa@gmail.com
discussions-to: k06aaa@gmail.com
status: Draft
type: Core
category: Core
created: 2018-04-25
updated: 2018-04-26
relates: #901

Simple Summary

It will be great to allow trustless delegated execution of the transactions inside EVM. I mean some account can sign target, call data, account nonce, network chain_id and pass them to any other, who will be able to perform this call and pay Ethereum fees like this:

target.authorizedcall(data, account , nonce, chain_id, signature)

This also will allow batching/chaining account transactions and many other features. One more use case: sender of any ERC20 tokens can signed necessary call and pass it to receiver, and receiver (exchange?) will be able to pay fees for this transaction.

Abstract

Abstract implementation of target.authorizedcall(data, account, nonce, chain_id, signature) method should perform:

  1. Check nonce of the account to be valid
  2. Check chain_id to be valid for this network
  3. Check signature of target|data|nonce|chain_id and extract signer
  4. Check signer is the same as account
  5. Perform data call on target with msg.sender == account
  6. Increment account nonce

Motivation

  1. Ethereum fees is a real problem for some new users, who had some (bounty?) tokens and can't even spend this tokens without buying some ether.
  2. Look at #827, #1003 – these protocols are trying to solve the problem of batching/chaining user transactions.

Specification

From solidity side this should looks like function on every smart contract:

function authorizedcall(bytes data, address account, uint256 nonce, uint256 chain_id, bytes signature);

Test Cases

Test cases for an implementation are mandatory for EIPs that are affecting consensus changes. Other EIPs can choose to include links to test cases if applicable.

Implementation

This is working example: https://github.com/bitclave/Feeless

Complete code:

import { ECRecovery } from "zeppelin-solidity/contracts/ECRecovery.sol";


contract Feeless {
    
    address internal msgSender;
    mapping(address => uint256) public nonces;
    
    modifier feeless {
        if (msgSender == address(0)) {
            msgSender = msg.sender;
            _;
            msgSender = address(0);
        } else {
            _;
        }
    }

    function performFeelessTransaction(address sender, bytes data, uint256 nonce, bytes sig) public payable {
        bytes memory prefix = "\x19Ethereum Signed Message:\n32";
        bytes32 hash = keccak256(prefix, keccak256(data, nonce));
        msgSender = ECRecovery.recover(hash, sig);
        require(msgSender == sender);

        require(nonces[msgSender]++ == nonce);
        require(address(this).call.value(msg.value)(data));
        msgSender = address(0);
    }
    
}

Usage:

contract MyToken is StandardToken, Feeless {

    string public constant symbol = "XXX";
    string public constant name = "MyToken";
    uint8 public constant decimals = 18;
    string public constant version = "1.0";

    function transfer(address _to, uint256 _value) public feeless returns (bool) {
        balances[msgSender] = balances[msgSender].sub(_value);
        balances[_to] = balances[_to].add(_value);
        Transfer(msgSender, _to, _value);
        return true;
    }

}

Signing call data:

const target = myToken.options.address;
const nonce = await myToken.methods.nonces(wallet1).call();
const data = await myToken.methods.transfer(wallet2, 5 * 10**18).encodeABI();
const hash = web3.utils.sha3(target + data.substr(2) + web3.utils.toBN(nonce).toString(16,64));
const sig = await web3.eth.accounts.sign(hash, wallet1PrivateKey);

Delegated execution by any other account:

await myToken.performFeelessTransaction(wallet1, target, data, nonce, sig).send({ from: wallet2 });

@k06a k06a changed the title from Transaction execution delegation to EIP1035: Transaction execution delegation Apr 25, 2018

@MicahZoltu

This comment has been minimized.

Show comment
Hide comment
@MicahZoltu

MicahZoltu Apr 25, 2018

Contributor

I would personally prefer this to be an EVM layer change, rather than contract layer. It feels silly that the person authorizing the transaction has to be the same person paying fees for the transaction. Miners care whether they get fees, they don't care about who they get fees from. Users care about other people not being able to use/spend assets under the control of their private keys, they don't care about how the transaction ends up in a block.

I would like to see transactions be two layers, the outer layer is signed by the fee payer and contains feePayerNonce, gasPrice, gasLimit, feePayerSignature, transactorNonce, to, value, data, transactorSignature. It would be even cooler if transactorNonce, to, value, data, transactorSignature was actually an array, for batching.

The above scheme would allow users to pay for "transaction submission services" off-chain via other mechanisms (e.g., monthly subscription, pre-paid, paid with fiat, add-on benefit to other services, etc.). It would also indirectly enable gas payments in non-eth if batching was supported, as the transactor executing the transaction could provide two signed transactions to the feePayer, one that transfers them some tokens and another that does the thing desired, with the nonce of the token transfer being one more than the nonce of the desired action. The feePayer can batch these two transactions together to effectively be paid in tokens, while miners are still paid in ETH. Alternatively, if the transactor is willing to enter into a trusted relationship with the feePayer then they could pre-pay for submissions via something like DAI.

Contributor

MicahZoltu commented Apr 25, 2018

I would personally prefer this to be an EVM layer change, rather than contract layer. It feels silly that the person authorizing the transaction has to be the same person paying fees for the transaction. Miners care whether they get fees, they don't care about who they get fees from. Users care about other people not being able to use/spend assets under the control of their private keys, they don't care about how the transaction ends up in a block.

I would like to see transactions be two layers, the outer layer is signed by the fee payer and contains feePayerNonce, gasPrice, gasLimit, feePayerSignature, transactorNonce, to, value, data, transactorSignature. It would be even cooler if transactorNonce, to, value, data, transactorSignature was actually an array, for batching.

The above scheme would allow users to pay for "transaction submission services" off-chain via other mechanisms (e.g., monthly subscription, pre-paid, paid with fiat, add-on benefit to other services, etc.). It would also indirectly enable gas payments in non-eth if batching was supported, as the transactor executing the transaction could provide two signed transactions to the feePayer, one that transfers them some tokens and another that does the thing desired, with the nonce of the token transfer being one more than the nonce of the desired action. The feePayer can batch these two transactions together to effectively be paid in tokens, while miners are still paid in ETH. Alternatively, if the transactor is willing to enter into a trusted relationship with the feePayer then they could pre-pay for submissions via something like DAI.

@k06a

This comment has been minimized.

Show comment
Hide comment
@k06a

k06a Apr 26, 2018

@MicahZoltu the more I think about this proposal the more I see this is the solution for tx batching to replace ERC827 (and ERC1003). Ethereum also can provide default smart contract (0x05?) for batching transactions with the methods like this:

function batchWithRequire(
    address account,
    address[] targets,
    bytes[] datas,
    uint256 firstNonce,
    uint256 chain_id,
    bytes[] sigs) public
{
    for (uint i = 0; i < targets.length; i++) {
        require(targets[i].authorizedcall(datas[i], account, firstNonce + i, chain_id, sigs[i]));
    }
}   

k06a commented Apr 26, 2018

@MicahZoltu the more I think about this proposal the more I see this is the solution for tx batching to replace ERC827 (and ERC1003). Ethereum also can provide default smart contract (0x05?) for batching transactions with the methods like this:

function batchWithRequire(
    address account,
    address[] targets,
    bytes[] datas,
    uint256 firstNonce,
    uint256 chain_id,
    bytes[] sigs) public
{
    for (uint i = 0; i < targets.length; i++) {
        require(targets[i].authorizedcall(datas[i], account, firstNonce + i, chain_id, sigs[i]));
    }
}   

@k06a k06a changed the title from EIP1035: Transaction execution delegation to EIP1035: Transaction execution batching and delegation Apr 26, 2018

@k06a

This comment has been minimized.

Show comment
Hide comment
@k06a

k06a Jun 24, 2018

This EIP will help a lot in inter-chain development.

k06a commented Jun 24, 2018

This EIP will help a lot in inter-chain development.

@ukstv

This comment has been minimized.

Show comment
Hide comment
@ukstv

ukstv Jun 25, 2018

Yay! That would greatly help with off-chain scaling schemes like state channels.

ukstv commented Jun 25, 2018

Yay! That would greatly help with off-chain scaling schemes like state channels.

@PhABC

This comment has been minimized.

Show comment
Hide comment
@PhABC

PhABC Jul 2, 2018

Contributor

Strongly related to #1077 by @alexvandesande. Have you considered collaborating on this one @k06a?

Contributor

PhABC commented Jul 2, 2018

Strongly related to #1077 by @alexvandesande. Have you considered collaborating on this one @k06a?

@k06a

This comment has been minimized.

Show comment
Hide comment
@k06a

k06a Jul 2, 2018

@PhABC thanks, I'll dig into it!

k06a commented Jul 2, 2018

@PhABC thanks, I'll dig into it!

@MohamedLEGH

This comment has been minimized.

Show comment
Hide comment
@MohamedLEGH

MohamedLEGH Sep 1, 2018

I agree with @MicahZoltu , I think we should allow any Ethereum transaction to have gas payment delegated, with no need of in contract function. I think this proposal is related to #1228 and #865 .

MohamedLEGH commented Sep 1, 2018

I agree with @MicahZoltu , I think we should allow any Ethereum transaction to have gas payment delegated, with no need of in contract function. I think this proposal is related to #1228 and #865 .

@rstormsf

This comment has been minimized.

Show comment
Hide comment
@rstormsf

rstormsf Sep 1, 2018

If someone is looking for ETH, ERC20 batch sender - feel free to use:
https://rstormsf.github.io/multisender/#/

rstormsf commented Sep 1, 2018

If someone is looking for ETH, ERC20 batch sender - feel free to use:
https://rstormsf.github.io/multisender/#/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment