Title: EIP_3074__AUTH_and_AUTHCALL_opcodes
Category: EIPs

Author: SamWilsn
Date: 2020-10-28T15:46:37.457Z

Ethereum Improvement Proposals


EIP-3074: AUTH and AUTHCALL opcodes
Allow externally owned accounts to delegate control to a contract.






Creates a new precompile, analogous to CALL, that sets CALLER based on an ECDSA signature.
This EIP creates two precompiles:

CALL_PRECOMPILE - forwards a CALL, setting msg.sender according to an ECDSA signature, using a relayer-sponsee nonce for replay protection.
NONCE_PRECOMPILE - provides access to relayer-sponsee nonces expected by CALL_PRECOMPILE.

Author: sergio_lerner
Date: 2020-11-02T13:46:22.924Z

The proposal has several problems, the two most important are:


It’s incompatible with EIP-712 and the mapping selected could be used to confuse existing wallets into signing an unintended message.


It doesn’t include the chainID in the signed fields , as advertised. Therefore it’s open to network reply attacks.


This is the list of fields signed, and how they map to a normal Ethereum transaction:
Normal -> EIP-3074
Nonce    -> Nonce
GasPrice -> GasLimit
GasLimit -> ReceiveAddress
ReceiveAddress -> Value
Value -> Data
Data -> relayer
chainId (not present)
empty (not present)
empty (not present)

Author: SamWilsn
Date: 2020-11-13T14:28:28.406Z

Thanks for the feedback! I updated the signed fields to include chainid.
Is EIP-712 final yet? I wanted to avoid it until it’s finalized.
If a malicious website wanted to confuse a user, they’d have to present something like this:
Nonce: 3
GasLimit: 66000000000 (66 Gwei, current gas price)
ReceiveAddress: 0x0000000000000000000000000000000000Be8c72 (current block gas limit)
Value: 611382286831621467233887798921.843936019654057231 ETH (some address)
...

I’ve probably missed some of the specifics of the RLP offsets, but it seems like it would be a very suspicious transaction. I’m not opposed to modifying the format to make it impossible though, if you have any suggestions.

Author: MicahZoltu
Date: 2021-02-23T04:33:09.852Z

Recommend having the transaction be a 2718 typed transaction, which means grabbing a number and signing over secp256k1(keccak256(TransactionType || rlp([nonce, gaslimit, to, value, data, invoker, chainid]))).  This would make it so we don’t have to worry about having the signature collide with some other future transaction type.
This wouldn’t technically be a 2718 transaction because it has no receipt and doesn’t end up in a block header, but we should reserve the transaction type number and follow the signing rules.

Author: MicahZoltu
Date: 2021-02-23T07:09:41.498Z

Other changes I would like to see:

Signature should be yParity, r, s.  v shouldn’t really be used anymore.
Signature first.  This enables some minor optimizations and comes at no cost.
data last.  This is pretty minor, but having the variable length thing at the end makes some stuff a tad easier and this change comes with no cost.
Remove chainId.  This can be addressed by the invoker with CREATE2 using CHAIN_ID as a salt.  In the case of a fork (chain ID change), the invoker can be redeployed. This can be automated with a factory.  By not having a chain ID, transactions and invokers can be constructed that intentionally support replays across chains.
Remove nonce and nonce checking and only include 32 bytes of extra data in the signature.  The invoker can then do nonce management (or not!).
Use ABI Encoding or SSZ instead of RLP encoding.  We don’t need the space savings provided by RLP, and ABI encoding and SSZ are a bit easier to work with when you have fixed width data elements followed by a single dynamic length data element.
Rename gaslimit to mingas.  This value doesn’t represent a gas limit, but instead represents the minimum amount of gas that needs to be supplied.

Author: SamWilsn
Date: 2021-03-03T16:18:05.110Z

MicahZoltu:


Remove chainId. This can be addressed by the invoker with CREATE2 using CHAIN_ID as a salt. In the case of a fork (chain ID change), the invoker can be redeployed. This can be automated with a factory. By not having a chain ID, transactions and invokers can be constructed that intentionally support replays across chains.



Being able to replay a transaction-like package across multiple chains is a bit of a niche feature. How often do you think a user would want to do that? I think the common case (one chain per transaction) is good enough, and matches what users will want to do.
Safely implementing the one-chain-per-transaction rule in the invoker would require either stuffing the chainID into nextra, or checking that the chainID hasn’t changed before every sponsored call.

Author: SamWilsn
Date: 2021-03-03T22:41:21.379Z

I expanded the section on why I don’t believe using the revert reason to indicate precondition failures is a good idea.
I’ve also reordered the signature input, so hopefully that takes care of everything!

Author: MicahZoltu
Date: 2021-03-04T14:30:20.402Z

Still outstanding (ignoring the things we disagree on):


yParity instead of v (which aligns with 2930 and 1559 transactions)
data as the last field in the signed data.  It is the only variable length item, and having it last has potential to simplify things at essentially no extra cost other than moving it in the spec.

New comments:

You pass value twice, once as an actual attached ETH amount and again in the data blob.  This is unnecessary given they must be equal.
I feel like we should be putting everything on the stack, rather than a mix of stack and encoded data:IMPERSONATECALL gas, value, y_parity, r, s, sponsee, type, nextra, to, mingas, data_start, data_length


Add rationale as to why STATICCALL context is allowed at all.  I can’t think of a situation where this would be useful in a static context.

Author: SamWilsn
Date: 2021-03-04T18:11:20.094Z

MicahZoltu:


yParity instead of v (which aligns with 2930 and 1559 transactions)



Is this just renaming v to yParity, or is it also removing chain id?



 MicahZoltu:

Add rationale as to why STATICCALL context is allowed at all. I can’t think of a situation where this would be useful in a static context.


I’m inclined to leave it in, even if I can’t think of a good reason for it. After all, you can CALL inside of a static context.

Author: MicahZoltu
Date: 2021-03-04T18:40:24.705Z

SamWilsn:

Is this just renaming v to yParity, or is it also removing chain id?


It removes the chainId and the +27.  From 2930:

YParity The parity (0 for even, 1 for odd) of the y-value of a secp256k1 signature.

Author: MicahZoltu
Date: 2021-03-04T18:41:16.442Z

Also, so we have it documented, I recommend renaming TXCALL to IMPERSONATECALL to make it more clear what this version of call actually does.

Author: SamWilsn
Date: 2021-03-04T19:46:07.465Z

While I am opposed to removing chainid, I am not opposed to encoding it separately. Thought?

Author: SamWilsn
Date: 2021-03-04T19:51:55.910Z

MicahZoltu:

Also, so we have it documented, I recommend renaming TXCALL to IMPERSONATECALL to make it more clear what this version of call actually does.


IMPERSONATECALL is used by the draft EIP-2997. I’m down with renaming the opcode, but I’m not sure which name I prefer:

IMPERSONATECALL - decent name, and I guess you can impersonate yourself if you want?
CALLAS - breaks the pattern of *CALL, but it’s short and descriptive.
SIGNEDCALL - Less descriptive.
SIGNCALL - seems backwards, since you aren’t signing a call, you’re making a call with a signed package, plus it’s also not descriptive.
TXCALL - call with transaction-like package

Author: MicahZoltu
Date: 2021-03-04T20:11:39.465Z

SamWilsn:

While I am opposed to removing chainid, I am not opposed to encoding it separately. Thought?


What do you mean by “encoding it separately”?

Author: SamWilsn
Date: 2021-03-04T20:21:37.813Z

Instead of packing yParity and chainid into v, having separate fields for yParity and chainid

Author: adietrichs
Date: 2021-03-05T00:57:02.609Z

I created a (relatively) simple example for what an invoker contract for EIP-3074 could look like:


gist.github.com


https://gist.github.com/adietrichs/ab69fa2e505341e3744114eda98a05ab
EIP3074Relayer.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol";

interface WETH9 {
    function balanceOf(address) external returns (uint256);
    function deposit() external payable;
    function withdraw(uint256) external;
This file has been truncated. show original

Author: MicahZoltu
Date: 2021-03-05T06:02:50.843Z

SamWilsn:

Instead of packing yParity and chainid into v, having separate fields for yParity and chainid


We may be saying the same thing, but I want to verify:
chain_id would be part of the signed data, but would not be part of the data passed to the opcode.  When validating the signature, it would use whatever chain_id the EVM has internally for the chain it is executing on.  The signature would just be y_parity, r, s.

Author: chriseth
Date: 2021-03-05T08:51:24.830Z

I have several requests / questions concerning this EIP:

Can you please extend the description of the semantics of the opcode (it mostly focuses on the arguments and the return values)?
Why is so much data put into the arguments instead of using stack slots? I would assume almost everything to be taken from the stack apart from the actual payload.
EDIT: It does exactly that, sorry for the confusion! PREVIOUS TEXT: Maybe I didn’t get it but what is the idea behind setting tx.origin / caller instead of msg.sender / sender? Until now, the distinguishing feature of tx.origin is that this is the account that pays for the gas. This property would be destroyed. Also if this is kept as it is, please mention that you ALSO set msg.sender because that is probably also the idea, isn’t it?
It would be nice to improve the presentation a bit. It is a bit hard to keep track of 5 different addresses plus other data - is that really needed?
There are many more points where this specification is not really clear. For example, the behaviour of the function abi.encode strongly depends on the types of its arguments, but those are not specified.

Author: chriseth
Date: 2021-03-05T09:17:01.429Z

Since this is not really about a transaction (for me, transactions are objects that are stored in blocks), I would prefer a name similar to impersonatecall or substitutecall.

Author: matt
Date: 2021-03-05T13:59:05.992Z

chriseth:

There are many more points where this specification is not really clear. For example, the behaviour of the function abi.encode strongly depends on the types of its arguments, but those are not specified.


Any thoughts on CALLFROM / CALLAS? They would break the *CALL scheme, but are short and intuitive. Alternatively, SIGNEDCALL / SIGCALL?

Author: SamWilsn
Date: 2021-03-05T14:39:14.562Z

chriseth:


Can you please extend the description of the semantics of the opcode (it mostly focuses on the arguments and the return values)?



Sure thing! Is there something specific you’d like to see beyond just “it’s exactly like call, except…”?



 chriseth:


Why is so much data put into the arguments instead of using stack slots? I would assume almost everything to be taken from the stack apart from the actual payload.



I had separated it out so that signed parts of the message go in memory and the unsigned parts go on the stack. It also has the nice property that introducing a new type down the road is pretty flexible. I think but am not 100% sure that copying the TLP out of calldata into memory should be reasonably efficient.
Happy to change it though!



 chriseth:


It would be nice to improve the presentation a bit. It is a bit hard to keep track of 5 different addresses plus other data - is that really needed?



I wholeheartedly agree. Not sure how to avoid talking about them though. You’ve got the sponsor/sponsee and I don’t think you can avoid mentioning either of them. The invoker contract has to exist, and so does the call destination… Is there some other data I can trim out?



 chriseth:


There are many more points where this specification is not really clear. For example, the behaviour of the function abi.encode strongly depends on the types of its arguments, but those are not specified.



There should be types for all of the ABI encoded fields (eg. type: uint8), and if I missed any that’s a problem!
Were there any other unclear points I can tackle?
Thanks for the feedback, I appreciate it.

Author: SamWilsn
Date: 2021-03-05T15:08:58.492Z

Just want to note one other suggestion that I’ve received:

Instead of signing over the calldata, mingas, value, etc. only sign over keccak256(type || abi.encode(invoker, chainid, nextra))

This has a certain elegance to it, and since you already have to trust the invoker for replay protection, why not trust it for everything?
This would allow multiple calls with different calldata (ex. approving the Uniswap Router, then performing a swap, and finally doing the sponsee’s transaction) with a single signature.
The downside is that a broken/vulnerable/malicious invoker can have nearly total control over an EOA, and writing a safe invoker will take a significant amount of care.
(Thanks to @adietrichs and Chris Buckland for independently suggesting this change.)

Author: chriseth
Date: 2021-03-05T19:28:14.523Z

You could use abi.encode(uint8(...), uint8(...) and so on explicitly. Also - note that abi.encode always pads value types to 32 bytes, so v is padded - is that intentional?
With respect to presentation: Maybe it would help to say something like “functions like call to address x with value y and arguments arg, where x = … , y is subtracted from the balance of … and arg is …”
It would also be nice to clarify the call depth (it is not a call to the new sender and then a call to the actual destination, but just a single one) and that no nonce is incremented.

Author: holiman
Date: 2021-03-06T19:32:46.446Z

The current execution context is static (i.e. STATICCALL) and value is non-zero

I disagree here. Let’s say were at depth 5, which is a static context.
If I try to do a CALL(x, x, 1, ...), then I will drop back to depth 4, not get a “failed call” on the stack.
The same should apply here, doing a SPONSOREDCALL(x, 1, ..) should drop me back a level.
TLDR; the error should be in the earlier context, not the current context. The semantics of STATICCALL are clear, and this particular op should not have any particular relation with that operation.
I also maybe think the stack format should be g,a,v, ... where a is the sponsee. The gav-order is used by every other calltype.

Author: stonecoldpat
Date: 2021-03-06T19:58:31.700Z

I put together an example of an invoker that we may use for ITX (Infura Transaction Service):


gist.github.com


https://gist.github.com/stonecoldpat/e8ca408c7be8f6333f69df7fe833c03d
EIP3074 invoker
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Example implementation of an EIP-3074 relayer invoker contract.
 *
 * Allows a sponsor to send a transaction on behalf of a sponsoree. Assumes 
 * the sponsorsee has already paid for the transaction (pre-deposit, fiat, etc). 
 */
This file has been truncated. show original







Generally speaking, when going through the example, I feel the opcode needs an additional return value of returnedData to keep it consistent with the other calltypes.
We should rename calleeSuccess to opcodeCheck (or something better) and then change the meaning of success to mean the CALL was successful (e.g. the internal transaction) as that keeps it consistent with the other CALL opcodes.
In the EIP, it mentions that it is worth checking if sponsor != sponsee to protect currently deployed reentrancy guards msg.sender == tx.origin. I have implemented that as tx.origin != signer.

Author: holiman
Date: 2021-03-06T20:05:33.618Z

stonecoldpat:

In the EIP, it means that it is worth checking if sponsor != sponsee to protect currently deployed reentrancy guards msg.sender != tx.origin.


The current EIP does not say anything about that, but I understand it originally did. Could someone elaborate on what the problem is?

Author: holiman
Date: 2021-03-06T20:13:35.818Z

I would like to see some more fleshed-out usecases and examples. Like these:

A user A who holds XToken (but no eth) wants to send 10 of them to an exchange (and is willing to pay 1 XToken to the sponsor).

How is that accomplished ?
And how can A prevent that someone else, B replays his blob and sends 10 more to the exchange (if only for shits and giggles, while not making a profit).



Aside from that ^ usecase, what is a practical usecase where a sponsoredcall would be used?

Author: stonecoldpat
Date: 2021-03-06T20:16:06.074Z

Some contracts (I don’t have an example offhand) have deployed a reentrancy guard: tx.origin == msg.sender to force contract calls to only originate from an EOA.
In EIP-3074, the tx.origin and the signer can be the same address. This allows an attacker to bypass the re-entrancy check as the immediate caller is a contract and not an EOA.
(Sorry, previous post had != instead of ==).

Author: holiman
Date: 2021-03-06T20:18:25.754Z

stonecoldpat:

In EIP-3074, the tx.origin and the signer can be the same address. This allows an attacker to bypass the re-entrancy check as the immediate caller is a contract and not an EOA.


Ah. Not as currently written. The ORIGIN remains the EOA that paid the eth, and the SENDER becomes the one who signed the message. So the check remains functional (fwiw)
EDIT: Yes, I see. The current EIP does say, in the security section:

Checking msg.sender == tx.origin no longer prevents reentrancy. Adding the pre-condition that sponsor != sponsee would restore this property.

I somehow missed that part

Author: stonecoldpat
Date: 2021-03-06T20:27:41.905Z

It is useful whenever Alice (sponsor) wants to pay the network fee for Bob (sponsee).
There are several reasons why Alice may want to send it for Bob:


ERC20 fees. Alice pays the network fee in ETH and Bob refunds it with ERC20 tokens.

Stuck transactions. Alice wants to improve the user experience for Bob, so she takes of sending the transaction for him. He just hits “send” and the rest is taken care off.

Bidding in fee market. Alice can take care of sending the transaction and competing in the fee market for Bob. She optimises for paying the best price at any given time (whereas Bob may just hit “bump fee” and overpay).

Both wallet providers and dapps are the big benefactors for the EIP.


Wallet provders.  Better user-experience as the wallet takes care of sending transactions for their users. It also allows users to pay for the fee in an ERC20 token. Examples include Argent, Dharma, Gnosis, Staker.app, etc. All services require a wallet contract as that is the only way to make it work today. (Some providers need to pre-farm wallet contracts to make it affordable for their users)


Dapp websites. One of the most common complaints that dapps get is “stuck transactions” / “no eth to send”, etc. This type of EIP would let websites take care of sending transactions on behalf of their users.


There are some companies that offer transaction relay as a service. Notably Infura Transaction Service (that I work on) that would benefit for the introduction of the EIP. The biggest pain point is that we need to recommend users 1) use wallet contracts or 2) enjoy a janky experience due to ERC20 tokens not supporting meta-transactions.

Author: holiman
Date: 2021-03-06T20:31:14.172Z

stonecoldpat:

ERC20 fees. Alice pays the network fee in ETH and Bob refunds it with ERC20 tokens.


That one sounds a lot like that usecase I wrote above. And I can’t see how Bob is protected from replays?
For all of these cases, I’d like to understand the whole process, basically flow-graphs of what parties/contracts would have to exist, and what the whole UX would be.
EDIT:Ah, the invoker is what prevents the blob from being arbitrarily replayed in my example.

Author: SamWilsn
Date: 2021-03-06T20:43:14.652Z

You can see another example of replay protection in @adietrichs’ example: https://gist.github.com/adietrichs/ab69fa2e505341e3744114eda98a05ab#file-eip3074relayer-sol-L77

Author: SamWilsn
Date: 2021-03-06T20:49:07.317Z

I’d like to interject to get a temperature check on only signing over invoker and nextra instead of what’s currently in the EIP. I’m leaning towards that direction, and I don’t want to waste everyone’s time reviewing something that might change.

Author: stonecoldpat
Date: 2021-03-06T20:55:53.486Z

The problem for the sponsor (A in your example) is the bounty-reward problem:

If Alice is due to collect an on-chain bounty upon the successful execution of a transaction, then generally speaking there is always a risk that her transactions fails because the bounty was already claimed.

The classic example is that Bob simply spends the ERC20 tokens while Alice’s sponsored transaction is in-flight. Unless you have a special contract set up, then generally speaking, Alice will just waste some gas. Several wallets already offer DAI payment as a feature (Argent) and so far they just absorb the risk/cost of it.
For the use cases. It really depends on:

Payment mechanism. How is the sponsor being paid for sending the sponsees transaction?
On-chain authentication. How is the sponsee authenticating with the target contract?

I should stress that both payment and on-chain authentication are separate problems. The EIP is only focusing on on-chain authentication.
For a full picture, the payment mechanism can be pre-payment (ITX) or the bounty approach (on-chain refund).
How prepayment and receiving job may work.
Blank diagram (5)2560×993 97.5 KB Figure 1: Overview of Gas Tanks for ITX
In Figure 1, we only consider the pre-payment approach and we assume the clients have a pre-paid gas tank with ITX. They may have paid in ETH or FIAT, but in the end they will have an ETH-denominated gas tank with the service.
The client can simply send a signed transaction to the API:
{
"id": 0,
"jsonrpc": "2.0",
"method": "relay_sendTransaction",
"params": [
   {
      "to": "0x0000000000000000000000000000000000000000",
      "data": "0x123456",
      "gas": "100000"
   }, <signature here>
]
}

ITX takes the “to”, “data”, packs it into an Ethereum Transaction and then sends it to the network for them.
The next problem, which is really the focus of EIP-3074, is how the user authenticates with the target contract that will be executed:

Modified target contract. It authenticates the user with a signed message instead of msg.sender.
Wallet contract. An intermediary contract holds the user’s funds and verifies their signed message. It then .calls() in the target contract and acts as their identity on the network.

The former approach is pretty janky as it doesn’t work with most ERC20 tokens or most contracts for that matter. There is some work towards standards such as EIP-2771, EIP-2612 and EIP-3009   standards, but they all fall short due to lack of adoption.
As a result, most services need to deploy wallet contracts. An example of how to execute (and the refund via bounty) can be seen with Gnosis Safe, but asking users to both deploy expensive wallet contracts and move all their assets to it… is typically a blocker to adoption.
I hope the above example helped. Sorry, it was the quickest thing I could think to put together and I hope it isn’t too long!

Author: adietrichs
Date: 2021-03-07T12:09:05.540Z

From the rationale section:

Including sponsee in the arguments to TXCALL is a gas optimization. Without it, invokers would have to do their own ecrecover before calling into TXCALL to verify/adjust any state for replay protection.

While I think this is generally sensible, it does make invokers that don’t care about the sponsee address somewhat less efficient. I think the pattern of trusted invokers (think e.g. an exchange collecting user deposits, or a user with multiple EOAs - any time the sponsee fully trusts the sponsor) could reasonably become a significant one, so there might be a case for optimizing for it.
The simplest way to do so that I can see would be to also allow the 0 address as a valid sponsee opcode argument, to signal no requested address validation. Given that Solidity would likely abstract that logic away anyway, I don’t think there is a high risk of this leading to any confusion. The tradeoff seems to be that now Solidity would likely have to add a “not 0” check for cases where an address is being provided, but the cost of that would be small compared to the passing in of a sponsee address via calldata.

Author: adietrichs
Date: 2021-03-07T12:35:11.096Z

SamWilsn:

I’d like to interject to get a temperature check on only signing over invoker and nextra instead of what’s currently in the EIP. I’m leaning towards that direction, and I don’t want to waste everyone’s time reviewing something that might change.


My thoughts on this:


I very much think this is the right thing to do. The whole point of signing over the invoker address is that the sponsee has to trust the logic of the particular invoker contract. Given that this is already a requirement, we might as well make the most out of it and get as much flexibility out of it as possible.


One good example for this increased flexibility is the currently hard-coded mingas argument. I think it is not obvious whether it would be preferable to enforce a minimum (as mingas does) or an exact gas amount. For relayer use cases, the user might want a trusted upper limit of what he could have to pay for. If they would have to rely on the relayer logic for that upper limit anyway, why not also rely on it for the lower limit?


To me it becomes more and more clear that the nextra argument is much more than a simple replay protection facilitator. I think nextra stands for “nonce extra”, so I would propose a name change either simply to extra or to something more expressive like commit_hash. In addition to the existing chainid, value, mingas, to, data it could also be used for enforcing interesting other restrictions, e.g. for expiring sponsored calls or for a maximum gas price. To me this is one of the main things that make this EIP so exciting…


I assume this change would come together with moving most of the arguments from memory to the stack? I initially thought about this opcode from a “sub-transaction” perspective, where I preferred the memory / stack separation. Given that it seems clear that people prefer the “sponsored call” framing, I think this no longer applies and arguments should move to the stack. data obviously has to remain in memory.


The one memory / stack decision I am on the fence about is the signature - I think there is a case to be made for v, r, s to remain in memory (somewhat analogous to signatures before they are sent (via calldata) to the ecrecover precompile), instead of them becoming 3 stack elements. They could either be located together with the data, or could have their own memory pointer (no length argument required).

Author: adietrichs
Date: 2021-03-07T12:38:17.472Z

stonecoldpat:

We should rename calleeSuccess to opcodeCheck (or something better) and then change the meaning of success to mean the CALL was successful (e.g. the internal transaction) as that keeps it consistent with the other CALL opcodes.


I agree that the ideal framing would be something like valid for the opcode pre-check and success for the success of the actual sponsored call.

Author: SamWilsn
Date: 2021-03-08T20:47:57.905Z

New version published: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3074.md
Highlights:

Expanded the specification section (@chriseth)
Clarified the call depth (@chriseth)
Put everything on the stack (@chriseth / @MicahZoltu)
Corrected the behavior in static contexts (@holiman)
Rename success and calleeSuccess (@adietrichs)
Rename to CALLFROM (@matt / @MicahZoltu / @chriseth)

And most importantly:


Only sign over type, invoker, chainid, and extra (@adietrichs)

Thanks to everyone who has reviewed so far, and please don’t hesitate to let me know if I’ve missed some of your concerns (or made something else worse!)

Author: adietrichs
Date: 2021-03-09T00:00:10.578Z

I have spent today writing a rough first implementation in geth. It is not yet fully compliant with the EIP, I will list the differences & some small questions that came up during implementation tomorrow.
Link to the implementation (of course very much WIP, but I am currently able to successfully execute contracts that use CALLFROM on my little local testnet):
https://github.com/quilt/go-ethereum/pull/38

Author: SamWilsn
Date: 2021-03-09T00:04:35.208Z

New version published (again, sorry)
This time:

Removed type from the stack arguments since it’s a constant anyway (@adietrichs)
Added a depthLeft argument since exhausting the call stack is a griefing vector (me)
Re-added the balance check to the pre-conditions (me)
Expanded the invoker security considerations (me)

Author: adietrichs
Date: 2021-03-10T11:32:00.861Z

Before talking about my implementation details, there is one last somewhat substantial change that I have been thinking about, namely the separation of the signature verification and the call. My motivation:

The opcode doing both seems overloaded, with 13 arguments right now
It is non-trivial to implement gas pricing that only charges for the (outer part of the) call portion if the signature is correct
In its combined form there is no native support for multiple calls from the same sponsee - they each require an additional signature verification overhead
Passing in the sponsee address, while a sensible gas saving, feels like a bit of a hack
The opcode returning two stack elements is unusual

My alternative idea would be:


AUTHORIZE

takes in: extra, v, r, s

returns: sponsee or 0

validiates the signature
sets a new context variable authorizedSponsee




AUTHORIZEDCALL

takes in: gas, addr, value, in_offset, in_length, ret_offset, ret_length

returns: success

throws if authorizedSponsee is 0

otherwise, behaves exactly like CALL, just with msg.sender set to authorizedSponsee




This has several advantages:

Native bundled calls from the same sponsee (one AUTHORIZE, any number of AUTHORIZEDCALL)
Cleaner opcodes, AUTHORIZECALL almost identical to CALL

Sensible way to recover sponsee address without need to pass it in from the outside
It allows for clear separation of invoker logic, where calls are only attempted in the case of a valid signature

Note that extra can be used to commit to a specific list of transactions, so no functionality is lost.

Author: MicahZoltu
Date: 2021-03-11T05:09:31.366Z

This would effectively be saying, “this caller can do whatever it wants from my account” right?  I’m assuming the authorization would only be valid for the call frame where AUTHORIZE was called?  Presumably, any user doing this would essentially fully trust the contract it is giving permission to?
From a cleanliness and future capabilities perspective, I really like the idea.  However, it means that signing tools will have significantly less information available to present the user with as to what exactly they are signing.  From the signing tool’s perspective, the user is just giving blanket power to a particular address.

Note: The signature would need to be over invoker.

Author: adietrichs
Date: 2021-03-11T10:17:38.032Z

I think that is a correct summary. Regarding the implications, I think it is important to distinguish between the two main use cases I see for this EIP:


In a trusted context (for example for significantly reducing gas usage of centralized exchanges, or for users controlling multiple addresses from a smart contract wallet and/or without the need for ETH in every account), this invoker trust assumption is not an issue, as the sponsor and the sponsee are the same person. I would expect a multitude of implementations, that all only have to pass the usual smart contract security scrutiny.


In a trustless context (mainly transaction relaying), trust into the specific invoker implementation is important. However, I think this has already been true for all of the latest revisions of the EIP, once the signed fields became minimal. I would not expect wallets to expose functionality to sign over arbitrary invokers (or if they do, word it in a “delegate full account control to contract” way). Instead / in addtion, there can be a handful of community vetted ERCs for different flavors of relayer systems, with wallets implementing more precise native support for the specific extra hash used by the ERC. So for those ERC invokers, the wallet would not ask for full account control delegation, but instead would display the specific transaction (bundle) to be authorized, with specific information like expiry and other functionality.





 MicahZoltu:

I’m assuming the authorization would only be valid for the call frame where AUTHORIZE was called?


Correct. Discussing this with @SamWilsn and @matt we felt like this authorizedSponsee should also not be passed along for delegate calls, to enforce all authorization-related execution to be in one place.



 MicahZoltu:

Note: The signature would need to be over invoker.


Correct, the signed data would remain identical to the current EIP. No need for the invoker address to be an opcode argument to AUTHORIZE though, because it would be the address of the currently executing contract.

Author: poojaranjan
Date: 2021-03-12T15:18:18.579Z

Overview of the proposal with specs explained in PEEPanEIP with @SamWilsn

Author: MicahZoltu
Date: 2021-03-15T07:04:10.606Z

I think that require(tx.origin != signerAddress) should be removed. Without this limitation, this EIP provides significantly more value because it would allow people to do the “approve and call” flow with ERC20 tokens in a single transaction.  In such cases, they are paying for their own gas and they shouldn’t have to go out and find a relayer and pay them extra or fund/use a second account just to get around this limitation.
Also, I don’t see any meaningful value in enshrining the require(tx.origin == signerAddress) behavior because it was already a broken protection that can be bypassed today.

Author: MicahZoltu
Date: 2021-03-15T07:08:31.073Z

I think the value for the call should be deducted from the signer’s account, rather than the invoker’s account. This would allow users to use this functionality to do transaction batching (i.e., execute the following series of operations in sequence) where one or more of the transactions they want to batch attaches ETH.
If there is fear that such a change would delay the launch of this EIP, then I propose we launch with require(value == 0) and then after a more careful evaluation we can remove that constraint and deduct from the signer.

Author: matt
Date: 2021-03-15T16:09:37.433Z

Hi @jpitts, could we have this thread renamed to “EIP-3074: AUTH and AUTHCALL opcodes” to match the latest EIP title?

Author: SamWilsn
Date: 2021-03-15T19:50:17.378Z

From shemnon on GitHub:

I would want to see how this interacts with account abstraction before I would be comfortable moving forward with it. I concur with alexey and martin in that it is too early in the design to freeze it for implementation, which moves it out of London.

Pretty much the whole reason I started investigating this EIP was because EIP-2711 is not compatible with account abstraction. There’s an (admittedly small) section on compatibility in EIP-3074.
In a bit more detail:
With mempool rules, we ban using AUTHCALL before PAYGAS. AUTH should be fine, as far as I can tell. After PAYGAS, an account abstraction contract behaves the same as a regular contract, and would be able to AUTHCALL to its heart’s content.
There are certainly some concerns with creating an ungriefable abstract account sponsor. The AA sponsor wouldn’t be able to rely on external contracts for swapping, or token balances, or pretty much anything, but that’s no different than AA without EIP-3074.
That said, I don’t see anything that would preclude an AA contract that receives ETH or WETH deposits, and then lets you use that to pay for transactions from your EOA.

Author: SamWilsn
Date: 2021-03-15T20:05:46.656Z

From Alexey on Discord:

Sponsored Transaction Precompile - not to include to London - is there a way to do it without precompile (these are ugly things and should not be regarded as normal artefacts of EVM development), also consider who exactly will need it and what are the alternatives.

We’ve switched off the precompile (now two opcodes.)
As for interested parties, we have several! @stonecoldpat (who has been active on this thread) is from Infura Transactions/any.sender. I’ve had a bit of contact with OpenZeppelin about this EIP as well, though no strong endorsement (yet!)
The alternatives are:
Natively Set msg.sender

EIP-2711 - Sponsored, expiring and batch transactions
EIP-2733 - Transaction Package
EIP-2997 - IMPERSONATECALL opcode

Avoid msg.sender Entirely

EIP-2612 - permit – 712-signed approvals
EIP-3009 - Transfer with Authorization
EIP-2771 - Secure Protocol for Native Meta Transactions

Author: matt
Date: 2021-03-17T04:27:25.626Z

I posted a thread on twitter giving a high-level overview of how this EIP will be used in practice:  https://twitter.com/lightclients/status/1371911245561917441?s=20

Author: jpitts
Date: 2021-03-17T22:04:47.130Z

matt:

EIP-3074: AUTH and AUTHCALL opcodes


No problem, I’ll update it now…

Author: matt
Date: 2021-03-18T13:13:11.118Z

I’ve written a document to discuss some different threat models EIP-3074 should be considered under and how they compare to EOAs and smart contract wallets today: https://hackmd.io/@matt/BknnAnyNu

Author: Arachnid
Date: 2021-03-18T20:43:46.370Z

EIP-191 specifies a safe format for signed messages, which already contains a subformat for messages of the type (ID || validator || payload). Could you use that rather than reinventing the wheel?

Author: danfinlay
Date: 2021-03-18T21:01:06.199Z

Per @timbeiko’s request, here’s a link to a twitter thread I’ve written on this EIP.
Probably my most important comments from the thread are:
Okay, so top question this is going to provoke, especially for “should we commit to shipping this tomorrow?”: IS IT SECURE? I believe the answer is YES, and for a simple reason:
EIP-3074 signatures always have a 0x3 prefix, which currently no Ethereum wallet will sign (at least without a warning that you may be signing everything away). For this simple reason, we can already safely say “no user can become vulnerable to this without accepting the risk.”
Also:
Fun challenge: What other features could you implement for any account with this pattern? While these invokers all derive their power from a signature, they can have state, and are replay-strategy agnostic! You could have a cold wallet that delegates to an m-of-n multisig!

Author: MicahZoltu
Date: 2021-03-19T02:41:59.544Z

Arachnid:

EIP-191 specifies a safe format for signed messages, which already contains a subformat for messages of the type (ID || validator || payload). Could you use that rather than reinventing the wheel?


191 is just a draft while 2918 is in review and will almost certainly be included in Berlin (brining it to final).  Also (probably a better discussion for 191 discussion), it is unclear to me why 191 is so prescriptive about the layout of the bytes after the version, and why the first byte is wasted on always being 0x19 instead of just having the first byte be a version (constrained to not compatible with legacy transactions).

Author: matt
Date: 2021-03-19T04:13:10.338Z

To be fair EIP-191 has been in production for about 5 years now. I think EIP-191 is a more proper standard to use for non-tx signing and commonly supported by most wallets. We can introduce a version explicitly for this EIP so there is no change of signature collision and wallets must opt-in support. I don’t really see a downside to switching to EIP-191.

Author: MicahZoltu
Date: 2021-03-19T05:34:24.264Z

Assuming the authors of 191 decide to move forward with the standardization process, what benefits does it provide over 2718 transaction types?

Author: matt
Date: 2021-03-19T13:27:25.558Z

IMO 2718 = transaction types, where 191 = message signing format. This EIP is not a transaction, so 191 seems to be a better fit.

Author: aak-dev
Date: 2021-03-19T20:22:47.461Z

Assuming multiple protocol allow a similar invoker, it can open a gate for users to sign as many functions thereby spamming until one trx get successfully mined. Similar to opensea spam bots which keep bidding even if they dont have the equivalent assets in wallets

Author: SamWilsn
Date: 2021-03-19T21:31:47.547Z

Someone’s gotta pay for that gas, and if the gas price is too low, the transactions won’t propagate, so I don’t think this EIP introduces any more risk of spam than normal transactions.

Author: danfinlay
Date: 2021-04-02T16:40:36.450Z

Congrats to @SamWilsn on a great presentation of EIP-3074 today on the All-Core Devs call. I think you provided the correct answer to most challenges that were presented, and I hope you’re not discouraged by the sentiment to take more time to prove its safety. (1/x thread)
This call made me think of a theme that has become tragically common in my mind in the last few years, as Chip Morningstar says, “You can’t tell people anything” (we might need to demonstrate the value to get the actual buy-in)
http://habitatchronicles.com/2004/04/you-cant-tell-people-anything/
In violation of that advice, I’m now going to take a shot at explaining the safety again, in response to a repeated misunderstanding on the call.
I was pretty disappointed to see multiple smart people, (and every objector!) comparing this proposal to SUDO. It’s a catchy objection, but I think it’s pretty easy to demonstrate why that equivalence is dramatically off, and I think drilling into exactly why it’s different might help others build an intuition for how this EIP works.
This is Alice. She has lots of different valuable things in her account.
Screen Shot 2021-04-02 at 9.36.44 AM614×366 20.7 KB
In actuality, her account is just a metaphor for control, and each of these assets is defined by a different smart contract that obeys her account to control her assets. These arrows represent a flow of control from their fundamental source of truth to an intended recipient.
Screen Shot 2021-04-02 at 9.37.19 AM848×594 65.7 KB
Today, when interacting with a smart contract like an exchange that needs one of Alice’s coins, she has to first ask that contract for permission, and then inform the other contract (like BobDEX), she first needs to tell the token’s contract to grant an allowance to this new contract, and if this is granted to a malicious contract, guess what happens? (Follow the arrow!)
Screen Shot 2021-04-02 at 9.37.40 AM856×416 89.8 KB
As we can see from this new “allowance” arrow, Alice used the allowance function to symbolically delegate control of one of her tokens to this new dex. If Bob is evil, he can now steal all of her BlueCoin. People sometimes grant their whole token balance to an untrustworthy contract, and that’s a form of phishing that is real and people do it.
There are different approaches to solving that problem, and they are rooted in multiple problems that are at play:

The user got phished into wanting to use an exchange that was malicious.
For convenience the user delegated their whole token balance, when “just enough” would be safer.

Fundamentally, if a user wants to engage with a smart contract, they need to deposit assets into its trust. Even platforms that are prioritizing “offer safety” like Agoric’s Zoe (we guarantee you will receive at least X in exchange for Y) requires that you trust the offer-safety contract itself. Without that initial risk, there is no contract to be had.
This is the tension of a smart contracting platform: Squeezed between letting the user do whatever they want, and keeping them safe. It is natural to want to avoid introducing new insecurity, even at the benefit of new features, and so we should strive to prove that a new mechanism introduces no new insecurity to the platform, and I think this can be proven.
Coming back to EIP-3074. An invoker contract allows for a user to delegate FULL CONTROL OF THEIR ACCOUNT. The most concerned people say this sounds like SUDO, and probably imagine it looks like this to interact with an application:
Screen Shot 2021-04-02 at 9.37.59 AM638×754 135 KB
But actually, this new proposal never suggests delegating messages to new applications. It’s not a tool for that at all, and its “invokers” are better understood as part of the wallet’s own code.
Screen Shot 2021-04-02 at 9.38.37 AM852×530 55 KB
While the addition of an invoker is sensitive, and should be treated as carefully as an infinite allowance permission, this risk is not for regular interactions with new applications, and most wallets probably won’t even allow users to perform this delegation (and at least should never without extreme caution).
Once a wallet trusts an Invoker, it is able to perform batching operations with the user’s keys, or whatever other features the invokers offer and the wallets feel is worth the risk of adding. Exactly like the risks that wallet developers already take every day when evaluating and adding new features.
One of the reasons of infinite allowances today is that gas is expensive, and a user might want to avoid an increased-approval transaction later by approving a higher allowance now. If we had support for batching, wallets would actually have tools to facilitate fewer, cheaper user approvals that allow them to delegate LESS authority to outside parties.
Screen Shot 2021-04-02 at 9.39.15 AM848×478 75.9 KB
When invoking SUDO, a UNIX user grants the highest authority of the entire system to an application they are invoking. Heck, in UNIX, every invocation grants your full user account authority to any program you run.
In UNIX, every time you run a program you’re basically handing it your private key, and no one is more concerned about those kinds of unintentional delegation risks than wallet developers, and that’s why at MetaMask we’re building tools to allow running scripts with reduced system access:
https://github.com/LavaMoat/LavaMoat
Unlike the unix permissions model, A 3074 invoker adds a system for wallets to add new trusted modules that can allow for new ways of key-managed accounts to delegate authority.
Once delegated, the most those invokers can do is send messages from the user’s account, meaning if a contract is secure against current user behavior today, it should continue to be secure regardless of any delegation actions the user performs outside of that contract’s system. If another account’s behavior can put a contract you care about at risk, then that contract is not secure.

Author: AlexeyAkhunov
Date: 2021-04-03T09:22:04.016Z

danfinlay:

I was pretty disappointed to see multiple smart people, (and every objector!) comparing this proposal to SUDO


It was compared not to Unix sudo, but to SUDO opcode proposal, which was April fool’s joke, of course. I think comparison with SUDO opcode is actually quite useful to understand what EIP-3074 does. As I mentioned on the call, it does it with restrictions, and I also explained what these restrictions are, from my point of view.
I am sorry for not engaging into the discussion on this topic on the call (simply because I was engaging into discussion in the Discord channel, and I also I had to leave the call earlier), but I did want to voice my objection because, as it happens, objectors have to object on every single call for the objections to be heard (and this is unfortunate). I am Ok with you being disappointed, but I wanted to say that I was not trying to be difficult. I was willing to put work in understand what the EIP was, pretty early on, and go against the “community sentiment” to voice my concerns. Consider this as a contribution and not as trolling please.
I do understand that this may be necessary security compromise for better usability, but I think I correctly judge that most people don’t really understand what is being changed, and why this is a compromise.

Author: danfinlay
Date: 2021-04-03T17:05:43.334Z

AlexeyAkhunov:

It was compared not to Unix sudo, but to SUDO opcode proposal, which was April fool’s joke, of course.


For the record, the joke proposal is here, and allows anyone to send messages from any account without any proof:
https://github.com/ethereum/EIPs/pull/3455/files
I think comparing these is ludicrous, as one lets anyone do anything, and the other allows key holders to delegate their own powers, and no more.
I disagree that this proposal makes security compromises. If we assume two security properties, it is safe:

Users and wallets do not sign invoker messages without intending to delegate account powers.
Existing smart contracts are secure under unrestricted behavior of other accounts.

I was not disappointed that you expressed concerns (and I agree they should not need presenting on every call), but it’s pretty shocking to me that you’re still insisting 3074 is anything like SUDO.

Author: danfinlay
Date: 2021-04-03T17:12:14.292Z

On the All Core Devs Call, @vitalikbuterin mentioned that long term all accounts should be tending towards being contract accounts anyways, and I think this was maybe a point for why this EIP isn’t needed.
I think we all agree that from a feature perspective, this is a desirable future, but from an implementation perspective, this introduces lots of complexity related to the migration. EIP 3074 provides a concrete migration path from a private key controlled account to a contract account, so that existing EOAs can continue operating even if its original keys are no longer on hot wallets, and they are transitioned to a mostly contract-style use

Author: AlexeyAkhunov
Date: 2021-04-03T18:22:25.579Z

danfinlay:

I think comparing these is ludicrous, as one lets anyone do anything, and the other allows key holders to delegate their own powers, and no more.


I disagree that it is ludicrous. When I myself tried to understand what EIP-3074 actually does, one of the iterations of my understanding was the same functionality as SUDO opcode, a completely unrestricted version of AUTHCALL. Then, of course, I realised that such opcode is dangerous, and how exactly EIP-3074 restricts this.
I also insists that it does make security compromise, which needs to be acknowledged, if this EIP goes in (which, of course, may happen despite my opposition). The main problematic thing I see in this EIP is that it creates a possibility of a very lucrative scam, which does need to involve wallet providers, willingly or not, and which is not really possible with today’s meaning of signatures. If someone manages to inject code into wallet provider’s release in some way, and introduce a “sleeper bug”, which will not attack users straight away, but work as expected, but harvest signatures to an upgradeable invoker contract. Once the time is right (enough signatures are harvested, containing enough value to steal), the attacker upgrades the contract and sweeps the tokens, at the time of their choosing. I know you would say this is unlikely, but, given the reward, such scheme is not outside of realm of possibility. And, as far as I know, such scheme would not work today, because one signature cannot give access to arbitrary number of operations in the future, and also the signature can be made invalid by issuing a transaction with the same nonce. In the harvesting signatures scenario, the only revocation possible is to create new address and issue lots of transactions to move tokens over.
And to conclude, there is alternative to this, which I unfortunately could not put a lot of work in. It is through the new transaction type allowing multiple signatures. I do posit that transaction relay is not the use case where we HAVE to introduce the property that one signature authorises unlimited number of future actions. Such property may be required for other things, but not for sponsored transactions. From my point of view, it is overshooting, i.e., a more security-conservative solution would be enough.

Author: SamWilsn
Date: 2021-04-03T18:41:01.980Z

AlexeyAkhunov:

If someone manages to inject code into wallet provider’s release in some way, and introduce a “sleeper bug”, which will not attack users straight away, but work as expected, but harvest signatures to an upgradeable invoker contract. Once the time is right (enough signatures are harvested, containing enough value to steal), the attacker upgrades the contract and sweeps the tokens, at the time of their choosing.


Is the attack vector that you’re concerned about here that the wallet UI could be modified into allowing signatures to an untrusted invoker then the signatures could be reused later once the invoker is modified?
Regardless, once you can inject code into a wallet, you can encrypt and exfiltrate the account’s private key as extra bytes in calldata. Yes, I know hardware wallets exist, but they should prevent signing EIP-3074 messages anyway.

Author: AlexeyAkhunov
Date: 2021-04-03T19:02:43.636Z

SamWilsn:

Yes, I know hardware wallets exist, but they should prevent signing EIP-3074 messages anyway.


I always use hardware wallets for signing anything of value. But checking what you are signing is not easy, perhaps unless you have something like Grid lattice. That’s why I do not usually like working with tokens

Author: matt
Date: 2021-04-03T19:05:17.270Z

AlexeyAkhunov:

But checking what you are signing is not easy


This is exactly why wallets won’t leave it to users to hopefully review which EIP-3074 invokers they’re signing over. It will be hard coded that the wallet only supports these specific invokers that the wallet team has reviewed and that have community trust/support.

Author: danfinlay
Date: 2021-04-05T20:58:39.127Z

AlexeyAkhunov:

The main problematic thing I see in this EIP is that it creates a possibility of a very lucrative scam, which does need to involve wallet providers, willingly or not, and which is not really possible with today’s meaning of signatures. If someone manages to inject code into wallet provider’s release in some way, and introduce a “sleeper bug”, which will not attack users straight away, but work as expected, but harvest signatures to an upgradeable invoker contract. Once the time is right (enough signatures are harvested, containing enough value to steal), the attacker upgrades the contract and sweeps the tokens, at the time of their choosing.


Thanks for sharing a concrete example.
Thanks in part to CREATE2, I think you’re right that an invoker could be changed at the same address. There are simple ways to completely avoid this, like only trusting invokers that are published with CREATE, since their address generation cannot be reproduced.
This is a good example of a serious consideration that needs to be taken when delegating to an invoker, but I don’t think this is new. Wallets are effectively already constantly exposed to this kind of attack (new code could silently undermine user trust at a later date), it’s just that it’s client-side, not always on-chain (although contract-based wallets are basically already vulnerable to the exact scenario you describe). I don’t think this changes the threat model of wallet development in any way.
Fortunately, no one is exposed to these risks by 3074 without someone at a later date making a deliberate choice to integrate the invoker into a wallet, or to sign a delegation message, and even then, the risk is limited to the negligent parties (or that wallet’s users).
Fortunately, this conversation would not end at the inclusion of EIP-3074, instead it would represent the beginning of the design of secure invokers. I have no doubt that good invokers can be built that are widely vetted and easy to trust, and will leave this particular concern comfortably to rest.

Author: d10r
Date: 2021-04-20T16:43:46.309Z

I’m involved in the development of the Minerva Wallet and was pretty happy when reading about this EIP.
3074 reminds me of the Proxy pattern which separates state from logic.
In a way, it would provide all EOAs with the optionality of behaving like a proxy contract which can freely choose its implementation contract with every transaction. To me that sounds appealing both from a wallet provider and from a user perspective.
3074 vs contract wallets
I agree that in theory everybody should just use contract wallets.
In practice however they have their own set of tradeoffs:

they seem to still not be first class citizens in large parts of the ecosystem.
There’s (still) a lot of tooling and contracts out there assuming the sender to be an EOA. I don’t have any stats supporting that claim, just my subjective impression.
they can pose an entry barrier.
Creating an EOA is a trivial off-chain activity which can take place on any device, doesn’t require connectivity and doesn’t require any funds or sponsor. Creating an account with a contract wallet requires either a funded EOA to start from or a sponsor.
I guess however that disadvantage was at least partially mitigated with CREATE2.
contract wallets create a kind of vendor lock-in.
As a user, I was always hesitant to commit to a contract wallet. That’s because I know that migrating from a wallet using a contract account (often a contract specific to that wallet) to another wallet is a non-trivial operation.

Intuitively I’d say that 3074 kind of retrofits EOAs with optional contract wallet functionality.
Security
I’m probably not qualified enough to comment about the overall tradeoffs in terms of complexity/attack surface/security etc. on a protocol level. Just wanted to comment on the specific concern voiced by @akolotov about potential signature harvesting.
I hardly see a significant difference btw. a conventional EOA and an 3074 enabled EOA there. If I were a blackhat able to inject code into a wallet today which allowed me to sign arbitrary messages, I’d just harvest a lot of signatures, varying nonces, token addresses (most popular first), amounts (not knowing what the balance will be when I’m ready to steal). That may not allow me to steal and break everything, but would likely come pretty close in many cases.
That’s assuming that I couldn’t just steal the PK itself anyway (as was the case e.g. in the 2018 Copay incident).

Author: poojaranjan
Date: 2021-04-29T11:35:58.417Z

Follow the development update, Puxi testnet progress & a demo with other useful discussions from the EIP-3074 community call #2

Author: axic
Date: 2021-05-14T01:03:05.442Z

I’m sorry if these questions were asked already, but:


Why isn’t chainid part of the signed data for AUTH? i.e. keccak256(MAGIC || paddedChainId, paddedInvokerAddress || commit). yParity seems to be restricted to 0/1, so it is not utilising EIP-155-style chainid inclusion.


Is there a strong reason to keep retOffset/retLength in AUTHCALL? If the only reason is “being similar to other CALL*s”, then I would suggest to not have. If the reason is that contract developers would prefer using that as opposed to returndatacopy, then of course it makes a lot of sense to keep it.


Why is AUTH/AUTHCALL separated? Is it motivated by a) simplicity; b) allowing multiple AUTHCALLs; c) having the ability to check if a signature is valid without executing a call?


I believe the answer is mostly b) (and c) comes as a benefit), but it could be much better explained.

Author: MicahZoltu
Date: 2021-05-14T03:16:01.389Z

axic:

Why isn’t chainid part of the signed data for AUTH? i.e. keccak256(MAGIC || paddedChainId, paddedInvokerAddress || commit). yParity seems to be restricted to 0/1, so it is not utilising EIP-155-style chainid inclusion.


If the authorized contract wants to check chain ID, it can.  It is not up to the EVM to do all possible validations, and anywhere that validation can be delegated to the contract it is.



 axic:

Is there a strong reason to keep retOffset/retLength in AUTHCALL? If the only reason is “being similar to other CALL*s”, then I would suggest to not have. If the reason is that contract developers would prefer using that as opposed to returndatacopy, then of course it makes a lot of sense to keep it.


Is retOffset/retLength just a legacy holdover from before returndatacopy was introduced?  If so, then I think we should remove them.



 axic:

Why is AUTH/AUTHCALL separated? Is it motivated by a) simplicity; b) allowing multiple AUTHCALLs; c) having the ability to check if a signature is valid without executing a call?


There are a number of use cases where the signature may not sign over the calldata.  A few examples:

one auth, multiple calls (approve and transfer)
permanent auth (one signature that gives contract 100% perpetual control)
one auth with multiple code paths that lead to different calls

Author: geoknee
Date: 2021-06-09T21:35:07.075Z

We have come to be very excited about this EIP over at statechannels.org as it allows for a novel contract architecture we might call synthetic-EOA-per-channel. We believe this is likely to be the most elegant and efficient architecture for state channels, offering a large reduction in blockchain state usage as well as an improved user experience.
The EIP authors introduced us to the idea of a “synthetic, externally-owned” account. It is somewhat like a contract account in that the associated private key is not known or used, but very different to a contract account in that it cannot have any code or storage. The address of the account is found by recovering the public key from a fixed message digest. For example, using an EIP-3074 digest:
digest = keccak256(MAGIC || padTo32Bytes(Invoker) || padTo32Bytes(0))
and a “synthetic signature”, constructed without the use of a private key*. Using the EIP-3074 digest hands complete control of the synthetic EOA to the Invoker, as explained in the EIP.
State channels may then be executed by participants sending funds directly to a synthetic EOA of their choice — one derived from the channelId, for example (which is roughly speaking the hash of the participants’ accounts). The Invoker can then release funds from the synthetic EOA conditional on all of the usual checks defined by the state channel protocol (e.g. the channelId itself, signatures on off-chain states, etc).
This avoids the need to i) have an additional “layer 2 accounting system” for state channels (i.e. no need to use contract storage to record which channel has how many tokens because the ethereum accounting system suffices), or ii) deploy a contract per channel using CREATE2 (which is expensive and will shortly become more so as SELFDESTRUCT refunds are removed) and also avoids the need to iii) approve and transferFrom tokens into the state channel in two separate transactions.
The bottom line from a state channels point of view is: improved state hygiene by avoiding writes to storage and/or code deposits and improved UX. Both imply increased gas efficiency. Projects like Connext are executing a high volume of state channels in production, making these improvements all the more significant.
*We would like a deterministic, reliable algorithm for this: it seems somewhat nontrivial and worthy of some more research.

Author: matt
Date: 2021-06-15T17:02:19.941Z

I wanted to bubble up an interesting idea from Jeff Coleman on Twitter:


twitter.com



Jeff Coleman | Jeff.eth (@technocrypto) on X
@technocrypto

@0xMidnight @TCRPartyBot And if we design the invoker right, we can get secure ENS validation on hardware wallets. This would be this biggest practical gain in security for a ton of use cases. We could also use secure templates to make function calls/arguments user readable on HWs too!









To flesh out the idea just a bit more, we could write an invoker that takes the normal transaction inputs, but replace to: Address with to: ENS. This way, the signature of the AUTH msg would be over MAGIC || INVOKER || hash([nonce, to_ens, gas_limit, gas_price, value, data]).
Doing this binds the msg to the to_ens handle and allows the hardware wallet to actually show to: someperson.eth rather than 0x12..34. The invoker can then trustlessly resolve the Ethereum address associated with the ENS domain during execution and route the rest of the call to that address.
Resolving the ENS name on-chain is the only way to trustlessly interact with ENS. Even if you run your own node, there is nothing binding standard transactions to a certain ENS domain. If you secure your assets with the hardware wallet (instead of with a smart contract wallet), you won’t be able to interact with ENS address trustlessly. You’ll always need to verify the Ethereum address on the device against what the ENS name should resolve to in order to be certain no part of the stack was compromised.

Author: SamWilsn
Date: 2021-06-16T02:21:46.954Z

Dropping a link to a follow-up post:




A case for a simpler alternative to EIP 3074 EIPs


A case for a simpler alternative to EIP 3074
The AUTH/AUTHCALL mechanism is very appealing from a developer’s point of view.  It gives anyone the ability to come up with an invoker that can implement different batching strategies (e.g. supporting multiple nonces for better parallelism), gas abstraction models, complex account abstraction methods, etc. 
The flexibility comes from being completely unopinionated about how this mechanism is used.  Instead of requiring the developer to conform to a …

Author: k06a
Date: 2021-06-16T21:16:20.947Z

Am I right, that making one wrong signature would allow attacker to drain whole wallet: all tokens and ETH from the EOA balance?

Author: matt
Date: 2021-06-17T00:48:18.721Z

EIP-3074 cannot move ETH from EOA balances, but technically yes. However that’s only half the story. To even get to that point, your wallet would have to allow you to create a bad signature. We trust our wallets to not do this every time we send a transaction, why think about EIP-3074 differently?

Author: k06a
Date: 2021-06-17T11:36:31.663Z

@matt but you can’t spend all your ERC20 balances within 1 transaction now.

Author: matt
Date: 2021-06-17T14:30:02.440Z

Not today, but tx batching will come. EIP-3074 will expedite it, but it’s coming regardless, and at that point the risk profiles will be the same.

Author: ncitron
Date: 2021-06-22T14:53:37.218Z

A possibility to ease security concerns is to add an AUTHRELEASE opcode. This opcode could be called by any contract that had previously received an AUTH from an EOA and would relinquish the authorization (for a particular commit of course).
This allows for contracts to implement two new kinds of functionalities. First, they could create a batchExecuteThenRelease function, which would allow users to send a signed AUTH message for batch execution, but could call AUTHRELEASE at the end of the execution to ensure that the contract does not retain indefinite control of the EOA. The second feature that can be built with this is a revoke function for an invoker, which would simply call AUTHRELEASE for a particular commit, allowing a user to safely remove authorization from a contract that they no longer trust.
Of course, this system has many downsides. To start, these abilities can be created entirely at the smart contract level, so it does not necessarily require a new opcode, but form often fits function, and it is likely if we added this opcode that many invokers would chose to take advantage of it. An additional downside is it would require the precompile to access storage to store who has released an authorization, which I understand has never been done before.

Author: matt
Date: 2021-06-22T15:28:36.879Z

This sort of opcode would significantly increase the cost of AUTH, since there would need to be a state read to check if the EOA has been released or not.
Your proposal also doesn’t outline how the “release” function works. If you release the EOA itself, how do you “un-release”? If you release the signature, you’ll have to store the hash of the signature in the trie which costs ~22k gas.

Author: ncitron
Date: 2021-06-22T15:54:56.736Z

I was thinking that release would work exactly as you described, where you release the signature, which should be unique. This would mean that calling auth would only have the increased gas cost of reading state. I do agree though that the increased gas costs may make my proposed solution not worth it, especially since these features can be implemented at the smart contract level.

Author: safinbot
Date: 2021-06-25T14:10:54.802Z

an address is EOA,and someone uses  EIP-3074 for this address
can others create this address as a contract?
for example,hash collisions occur on binance chain and ethereum



Binance (BNB) Blockchain Explorer



Address 0x491604c0fdf08347dd1fa4ee062a822a5dd06b5d | BscScan
The Address 0x491604c0fdf08347dd1fa4ee062a822a5dd06b5d page allows users to view transactions, balances, token holdings and transfers of both BEP-20 and ERC-721 (NFT) tokens, and analytics.





https://etherscan.io/address/0x491604c0fdf08347dd1fa4ee062a822a5dd06b5d

Author: Dominator008
Date: 2021-06-30T18:38:06.519Z

This likely isn’t hash collision. Just someone sent the address some BNB and CTSI on BSC.

Author: david
Date: 2021-07-12T14:18:27.996Z

Hey, I thought I’d post this Twitter conversation that’s being had about ERC-3074 and composability, starting from this tweet:
https://twitter.com/dmihal/status/1414579442073194498
The concern is that if application developers begin using 3074 in their contracts, then those contracts basically become EOA-only.
You can take a look at this example from @fubuloubu:

transferFrom(msg.sender, this, amt) Can just be transfer(this, amt, auth=sig)

If applications use transfer{ auth: ... }() instead of transferFrom(), then contracts can no longer use this function, since contracts can’t sign messages (@gakonst pointed out that ERP-1271 could be used, but I think it would be difficult to get much adoption of that).
It seems that these issues can be avoided if application-level use of EIP-3074 is discouraged, and AUTH is only invoked from a handful of whitelisted “invoker” contracts.
https://twitter.com/lightclients/status/1414581676890419200
So my takeaways from this conversation is that usage of EIP-3074 should be limited at these levels:

Wallet layer: wallets should only allow signing 3074 messages for whitelisted invokers (and there should be a very scary warning before adding new invokers to the whitelist)
Language layer: Solidity & Vyper should not add support for 3074 opcodes, invokers should be built in Yul (or using inline Yul)
Social layer: discourage developers from using 3074 opcodes directly, instead encourage them to build for existing invokers.

Author: jaerith
Date: 2021-07-27T01:51:04.180Z

I’ve been under a rock for the past few months, but I was thrilled to learn about 3074 while watching the presentation at EthCC 4.  It’s refreshing to finally see more discussion with a focus on improving transaction efficiency and delegation, so that mainstream adoption (especially by enterprise) can happen in the near future.  Bravo!
I’m the author of EIP-2746, and so I definitely have an interest in this subject, especially in regard to batching and rules.  (I’ll admit that my EIP is definitely not as thought out as this one.  I’m absolutely an amateur in this space.)  I apologize for not yet being familiar with the implementation, but I was especially curious about the rules being encoded in these AUTHCALL requests (particularly in terms of their flexibility) and about the assumption that these new opcodes could be invoked within a L2.
Basically, I’m wondering what considerations have been made in terms of rule complexity and whether these rules can be other contract methods.  I could see an interest in the Invoker executing a standard, lengthy set of rules that are too complicated and too costly to be encoded as part of a transaction’s calldata.  In one example, a company might have a complicated validation algorithm that exists as a contract method and simply returns a boolean.  In another example, a government or accounting firm could post a contract method (or a EIP-2746 ruletree - shameless plug) that is the standard for calculating a VAT tax, one that could be used by any enterprise without fear, and returns a numeric value.  So, my question is this: could an AUTHCALL request result in the Invoker getting input from a contract method (using only a CALL, to be safe), to either evaluate in a rule or to pass along to the sponsored transaction?  If not, can the Invoker receive and then store these encoded rules (which are part of the calldata?) on behalf of the caller, so that they can be invoked again at a later time and without the cost of sending them once again?  That storage might be costly, but in the case of 3074 being deployed to a L2 (like Optimism), these storage costs could possibly be mitigated.  Assuming, of course, that storage might be cheaper on a L2 in the long run.
Very curious about what’s possible.  And great work so far!

Author: jaerith
Date: 2021-07-29T20:25:53.612Z

Whoops…I forgot one question: do you think that EIP-3074 could possibly be compatible with a batching implementation found in a L2, like the Optimism sequencer?

Author: matt
Date: 2021-07-29T21:22:57.322Z

L2s have more flexibility, so they can define their accounts to have arbitrary functionality. But yes, it would be compatible.
I still think there is different way of thinking about contract wallet accounts that benefits significantly from EIP-3074 and L2s could support something similar, even if EIP-3074 doesn’t reach mainnet.

Author: jaerith
Date: 2021-08-02T02:30:28.941Z

I agree wholeheartedly.  In addition to a new paradigm for account management, an Invoker instance from EIP-3074 could be a foundation for organizations and enterprises to build upon.  If the Invoker proved to be a stable, safe platform by itself that could control an account through a set of dispatched rules (which are predefined simple actions), then their investment into contract creation (of developing, of auditing, of deploying, etc.) becomes unnecessary as they would just deploy their strategies to the Invoker, accelerating the buy-in of the mainstream.
Unfortunately, mainnet acceptance will probably be difficult to achieve.  Do you think that Optimism would be curious to consider 3074 and test the new opcodes in the OVM?

Author: greg
Date: 2022-01-14T23:55:01.460Z

Created a small website that I’ll slowly add educational materials about how EIP-3074 can improve day-to-day lives. Currently just showcasing how much has been spent on approvals.
https://www.approvals.wtf/

Author: jochem-brouwer
Date: 2022-02-09T16:39:24.875Z

I have a question about this EIP, especially this line in the Behavior section:


If the gas available for the subcall would be less than gas, execution is invalid.


In Frontier, we had this rule also for CALL and CALLDATA but in EIP150 this was removed: the reason was that contracts (in most cases) used something like PUSH 23 GAS SUB CALL, where 23 here is the gas cost of CALL plus the cost of SUB (this thus relies all GAS to the call frame). The problem is, that if you increase the base cost of CALL, this mechanism breaks. This EIP is thus also subject to this case, if we ever change AUTHCALL costs then some contracts will break.
I don’t understand the rationale for it. The contract itself can check if there is enough gas left (can also be put in the commit, for instance). If there is not enough gas left, then revert the frame. I would suggest to use the rule from EIP150: if the GAS wants to send more GAS than currently is left, then send 63/64 of the available gas. Any safety checks can be handled by the contract implementation itself.

Author: axic
Date: 2022-02-10T12:46:49.963Z

An idea was posted to replace WETH with a mapping using EIP-3074:



Getting rid of WETH using EIP-3074 Core EIPs


    (Originally posted here.) 
While randomly looking at WETH I was wondering, 

Hmm, this was written such a long time ago, what would it look like with modern Solidity? 

WETH9 was written for 0.4.18 (2017!) and we are at 0.8.10 today. (@MrChico, what does 9 stands for?) 
So I started iteratively changing it, adding small improvements one-by-one: 

Turning those constants into actual constants
Upgrading the syntax of the fallback function
Adding the emit keyword to events
Fine-tuning public into e…
  

This would require the “Ether transfer” functionality to be enabled in EIP-3074.

Author: jochem-brouwer
Date: 2022-03-14T17:12:35.319Z

We are working on a draft implementation at EthereumJS/VM: Implement EIP3074: AUTHCALL by jochem-brouwer · Pull Request #1788 · ethereumjs/ethereumjs-monorepo · GitHub
The EIP is really well written, I have not yet encountered any edge cases which are not covered by the spec (but might do so when writing tests).

Author: jochem-brouwer
Date: 2022-03-14T18:01:16.860Z

Yes, a small thing:
Note that yParity is expected to be 0 or 1.
I think we should enforce this, so if yParity is not 0 and also not 1 then the operation is invalid, throw and consume all gas. (Maybe this is meant by this sentence already)

Author: jochem-brouwer
Date: 2022-03-26T09:59:46.190Z

We have implemented the EIP in EthereumJS/VM: Implement EIP3074: Authcall by jochem-brouwer · Pull Request #1789 · ethereumjs/ethereumjs-monorepo · GitHub (it is targeted towards a develop branch so it will take some time to start using it directly from npm).
There is one more question I have which is not stated in the EIP. In case we are in a STATICCALL frame, are we allowed to AUTHCALL? Following EIP-214 logic it should throw if either value or valueExt is nonzero, but if both are zero, it should be allowed. Can this be specified in the EIP?

Author: SamWilsn
Date: 2022-04-02T05:19:20.319Z

jochem-brouwer:

There is one more question I have which is not stated in the EIP. In case we are in a STATICCALL frame, are we allowed to AUTHCALL?


I believe it must throw the same way as CALL, since it’s defined as a list of changes:

AUTHCALL is interpreted the same as CALL, except […]

Author: SamWilsn
Date: 2022-04-02T05:20:24.942Z

Put up a change to auth to make it more future compatible. Comments welcome!


github.com/ethereum/EIPs








Finally add signer to auth [EIP-3074]


master ← SamWilsn:eip-3074-the-signing



          opened 05:14AM - 02 Apr 22 UTC




            SamWilsn
          



+53
-19

Author: SamWilsn
Date: 2022-04-05T16:26:27.753Z

Had an interesting discussion today where it might be theoretically possible to create a single “meta-invoker” that enforces replay protection/revocable signatures/etc, which then delegate calls into app-specific “sub-invokers”. If that ends up being possible, the whitelisting process would only need to approve the one “meta-invoker” to cover 90% of use cases.

Author: SamWilsn
Date: 2022-04-12T17:32:58.291Z

This is now merged. Instead of pushing everything on the stack, auth now takes an address and a memory range.
Currently the memory range contains the commit and signature, and the address from the stack must match the address recovered from the signature.
In the future, should EIP-3074 get merged, auth can be modified to work with EOAs and smart contract wallets!

Author: cyrus
Date: 2022-04-21T15:23:02.732Z

In the current EVM, tx.origin is the account from which the transaction originates (logically, the account “doing the thing”) as well as the account that pays the gas to execute the tx. They are synonymous.
With EIP-3074, this is no longer the case; these identities get split up: The logical originating account account “doing the thing” is the AUTH’d account, but the account paying the gas to initiate the transaction is the account making the AUTHCALL to remote control the AUTH’d account into “doing the thing”.
I think (correct me if I’m wrong), your implementation leaves tx.origin as the account paying the gas where I believe tx.origin should be the AUTH’d account performing, in spirit, the action.
I’m not sure if this is the proper venue to discuss, but what are your (and others’) thoughts on which account should be tx.origin… the account paying the gas or the account logically originating the action/“doing the thing”?
Edit: Way out of my depth, but what about a new “tx.gaspayer” identity to distinguish the two?

Author: SamWilsn
Date: 2022-04-21T16:05:21.440Z

cyrus:

I think (correct me if I’m wrong), your implementation leaves tx.origin as the account paying the gas


That is correct.



 cyrus:

I’m not sure if this is the proper venue to discuss, but what are your (and others’) thoughts on which account should be tx.origin… the account paying the gas or the account logically originating the action/“doing the thing”?


I’m mostly indifferent to what tx.origin represents. I think there are arguments for it to be the “gas payer”, or the “first actor”, or just an alias to msg.sender. If we set tx.origin to authorized when AUTHCALLing, it would certainly make it harder to distinguish smart contract wallets from EOAs, which I suppose I support.

Author: cyrus
Date: 2022-06-11T12:19:45.591Z

On balance, what msg.sender/tx.origin/gaspayer scheme do you (or anyone reading this) think makes the most sense in a post-merge, 3074-adopted world?
I’d love to see tx.origin aliased to msg.sender, personally. Elegant. Simple. Not sure how realistic.

Author: cyrus
Date: 2022-07-09T16:01:16.378Z

Seems like there are two implementations of this so far: quilt go-ethereum (adeitrichs) and ethereumjs (brouwer)
Are we aware of any others? Is there some common location (aside from this thread) for implementation writers to report their work on 3074?
Can my suggestion for setting tx.origin to the account being remote-controlled, not the gas payer, be added to the EIP?

Author: SamWilsn
Date: 2022-07-20T17:11:35.363Z

cyrus:

Can my suggestion for setting tx.origin to the account being remote-controlled, not the gas payer, be added to the EIP?


I’m worried that adding an even more controversial change to the EIP will make it even less likely to be adopted.
Once the merge is complete, I think we can reopen the discussion with core devs and see where we stand?

Author: cyrus
Date: 2022-07-20T17:27:38.949Z

But it sounds like such a change is not controversial; more that nobody really seems to have an opinion one way or the other.
In this way, it’s more controversial not to make the change, isn’t it? Because I do have a very strong opinion on it.

Once the merge is complete, I think we can reopen the discussion with core devs and see where we stand?

Yes, I plan to voice my concern with the core devs group whenever it’s appropriate. Thanks for the reply.

Author: axic
Date: 2022-09-09T18:22:24.691Z

From a perspective of secure contract design, I think having a shortcut for “remove authorisation” (= clear authorisation context) would be a nice addition, even at the expense of an extra opcode.
This can be current accomplished by sending “rubbish” to the AUTH instruction. Would auth(0, 0, 0) do the trick? The spec seems lenient at invalid input lengths.

Author: axic
Date: 2022-09-09T23:04:03.722Z

SamWilsn:




 chriseth:


Why is so much data put into the arguments instead of using stack slots? I would assume almost everything to be taken from the stack apart from the actual payload.



I had separated it out so that signed parts of the message go in memory and the unsigned parts go on the stack. It also has the nice property that introducing a new type down the road is pretty flexible. I think but am not 100% sure that copying the TLP out of calldata into memory should be reasonably efficient.


Since the data in memory is not “versioned” or distinguished in any manner I do not think this achieves the goal of extensibility. I did found the old stack version much more “user friendly” too.

Author: SamWilsn
Date: 2022-09-12T22:23:45.610Z

axic:

Would auth(0, 0, 0) do the trick?


Yes, I believe so:

If the signature is instead invalid or the signer address does not equal authority, authorized is reset to an unset value.




 axic:

Since the data in memory is not “versioned” or distinguished in any manner I do not think this achieves the goal of extensibility.


In a future extension of AUTH, the interpretation of the memory range would be defined by authority (from the stack.) If there is code at that address, that code could parse the signature and decide to authorize or not. This is somewhat similar to EIP-1271’s isValidSignature. If no code exists at authority, the behaviour would be the same as 3074 currently specifies.



 axic:

I did found the old stack version much more “user friendly” too.


Me too, honestly.

Author: greeegor
Date: 2022-09-15T14:15:36.226Z

I’d second this

Author: xinbenlv
Date: 2022-10-06T17:01:18.360Z

@SamWilsn  and authors, great EIP. I wonder if this could make Shanghai

Author: cyrus
Date: 2022-10-24T11:52:34.702Z

Now that the merge is complete, is now the right time to discuss how to handle tx.origin? The range of possibilities:

Alias to msg.sender
Set as “first actor”
Leave as “gas payer”

I’d love to see option 1 (what are the implications of going this route?), but between choices 2 and 3, I think you are correct that option 2 gets us closer to true account abstraction and is, also, what I’m advocating for.
(I’ve joined the wallet dev discord and we can discuss there, if you like.)

Author: MicahZoltu
Date: 2022-10-24T13:51:58.346Z

Just to restate my opinion which I suspect is somewhere above: tx.origin referring to the signer/account that initiated the transaction makes the most semantic sense with “transaction origin”.  However, this has caused much trouble because people use it to block “contracts” from interacting with dapps which includes contract wallets, and eventually could include account abstraction.  I would feel no remorse breaking apps that have depended on this behavior as we have been advising people against this for a long time.

Author: cyrus
Date: 2022-10-24T15:28:46.115Z

Respectfully but emphatically disagree.
3074 introduces something “new” - a rearward step in the transaction chain - and then moves something “old” (tx.origin) to this new first frame that never existed before. That really flies in the face of immutability and should be avoided at all costs, IMO.
I agree that we shouldn’t feel much remorse for those who were advised against tx.origin and then proceeded to use it anyway. But that’s not my case. The opposite, in fact. In 2015, I asked Chris Reitweissner about refunding the transaction sender and was told about tx.origin.
chriseth1171×565 88.5 KB
While he didn’t outright advise using tx.origin, you can see that it was floated as valid when I was previously on the msg.sender bandwagon. (The first two versions of Etheria correctly use msg.sender to determine token ownership. The last two use tx.origin, unfortunately, based on this gitter exchange.)
The danger of tx.origin wasn’t widely known until 9 months later in mid-2016 as shown here:

github.com/ethereum/solidity








Remove tx.origin



        opened 06:23PM - 24 Jun 16 UTC


          closed 11:28AM - 11 Aug 16 UTC




          PeterBorah
        







## Summary

`tx.origin` is a security vulnerability, breaks compatibility with o…ther contracts including security contracts, and is almost never useful. Removing it would make Solidity more user-friendly. If there are exceptional cases where access to the transaction origin is needed, a library using in-line assembly can provide it.
## The Problems

1) `tx.origin` is a security vulnerability. As we [recently saw with the Mist wallet](https://blog.ethereum.org/2016/06/24/security-alert-smart-contract-wallets-created-in-frontier-are-vulnerable-to-phishing-attacks/), using `tx.origin` makes you vulnerable to attacks comparable to phishing or cross-site scripting. Once a user has interacted with a malicious contract, that contract can then impersonate the user to any contract relying on `tx.origin`.

2) `tx.origin` breaks compatibility. Using `tx.origin` means that your contract cannot be used by another contract, because a contract can never be the `tx.origin`. This breaks the general composability of Ethereum contracts, and makes them less useful. In addition, this is another security vulnerability, because it makes security-based contracts like multisig wallets incompatible with your contract.

3) `tx.origin` is almost never useful. This is the most subjective point, but I have yet to come across a use of `tx.origin` that seemed legitimate to me. I welcome counter-examples, but I've written dozens or hundreds of smart contracts without needing it, and I have never heard of anyone else needing it either.
## Rationale for Removal

Solidity's design philosophy is to prioritize security and reliability over expressiveness. In other cases where behavior is unreliable, Solidity does not expose it. (For instance, there is no way to call an external contract and retrieve the return value if the signature is not known ahead of time.)

The "escape clause" is in-line assembly, which allows the creation of libraries to do anything expressible as EVM assembly. Behavior that is unsafe and unreliable is best kept in libraries, rather than given to all users as part of the core language.






Indeed, leaving the EIP-3074 spec with tx.origin as the gaspayer would open a potential vulnerability: If a tile holder sponsors a transaction, any other frame in the transaction chain would have the ability to hijack these tokens. (Of course, we can advise owners to never use such an account to sponsor transactions, but I shouldn’t have to teach this nor can I ever guarantee reaching owners with this warning/education.)
If we are otherwise fine with breaking tx.origin because “people should have known better since mid-2016”, then we can both get what we want by simply aliasing tx.origin to msg.sender and being done with it. Solves my problem and eliminates tx.origin issues forever. (That said, I don’t have the expertise to know how impactful this would be throughout the entire ecosystem.)
Failing this abrupt aliasing, I strongly insist that “tx.origin” means, in spirit, “the first actor” and should remain that way for immutability reasons. This new initial frame created by 3074 should then be called “tx.gaspayer” to appropriately add a new label to a new frame and leave the old label with the old frame. Doesn’t this move us to a more complete “account abstraction” anyway?

Author: dror
Date: 2022-10-24T19:23:12.333Z

Before thinking of altering the behaviour of tx.origin, please think about its current nice side-effect: it allows creating view-only transactions.
Assume that I want to simulate a specific code portion (either just to find if it runs at all, or some side-effects, such as creating contracts and query some data from them) - but WITHOUT really letting the user run this code on-chain.
The simple way we can use right now is to add require(tx.origin == address(0)) to the code (and document that this method has to be called only with “eth_call({from:'0x0' })”
Do you know of any other way of forcing a code to run in view-mode only?

Author: SamWilsn
Date: 2022-10-24T19:45:26.203Z

You’d need to somehow generate a valid signature from the zero address for that to be a problem. If someone can do that, we have bigger issues

Author: jochem-brouwer
Date: 2022-10-24T22:01:15.175Z

Creating a fake tx using an extremely high gas price or gas limit would most likely work (I do not think eth_call checks those things). And then thus check require(gasleft() > HIGH_VALUE) or require(tx.gasprice > HIGH_VALUE).

Author: jochem-brouwer
Date: 2022-12-11T16:16:55.864Z

I have a quick question about AUTHCALL not resetting AUTH. From a security point of view, I would argue that it should reset AUTH; the reason is that now it opens ways for “attacks” similar as to re-entrancy attacks. (First AUTHCALL into some contract, do some nasty stuff over there to trick the calling contract to invoke another AUTHCALL when it returns from the authcall frame later…?)

Author: MicahZoltu
Date: 2022-12-11T16:44:21.136Z

You should only be signing AUTH messages to contracts (invokers) you explicitly trust to have 100% control of all of your funds.  The idea here is that you can delegate control of your EOA to a contract, and you shouldn’t be AUTHing some random contract.  Wallets should be incredibly restrictive about allowing this opcode, likely only allowing it for their own contract wallet or community trusted ones.

Author: matt
Date: 2022-12-13T00:40:04.718Z

I think you mean to say you should only signing AUTH-messages to contracts (invokers) which you trust 100%. Once the AUTHCALL happens, it’s just the standard security model of interacting with smart contracts - e.g. they have control over only what you explicitly give them.

Author: MicahZoltu
Date: 2022-12-13T10:13:47.582Z

matt:

I think you mean to say you should only signing AUTH-messages to contracts (invokers) which you trust 100%.


Yes, fixed!  More words to satisfy spam bot.

Author: k06a
Date: 2023-02-28T22:11:42.253Z

I was always too skeptical about this EIP due it is introducing ability to steal all user tokens with 1 transaction, not only ETH as previously.
But today I realized that this EIP is effectively generalizing signature based calls as EIP-2612 (aka Permit) and others.
This EIP is also almost resolving EOA non-programmability.

Author: k06a
Date: 2023-02-28T22:26:27.651Z

It could even effectively deprecate ERC20 approves/allowances usage especially if AuthContract will be additionally introduced compatible with EIP-1271.
Wish we had unification among EOA and smart contract based authentications (aka signatures)

Author: k06a
Date: 2023-02-28T22:48:29.538Z

What do you think about introducing transaction format change allowing specifying DELEGATECALL for the top transaction trace?

Author: SamWilsn
Date: 2023-02-28T23:21:55.575Z

There are a few proposals that attempt to add bytecode execution to EOAs (eg. EIP-2803.) Not exactly the same, but similar idea.

Author: k06a
Date: 2023-03-03T09:03:26.988Z

Found exactly the same: EIP-5806: Delegate transaction
Discussion: EIP-5806 Delegate transaction - #2 by Amxx

Author: WangHallO
Date: 2023-03-14T03:11:32.324Z

I have a question about calculating the dynamic gas portion (dynamic_gas ), and the gas available for execution in the sub call (subcall_gas ) for AUTHCALL.
According to the provided pseudo-codes, if the value is not zero, the cost of gas should add 6700, it is not 9000 because no gas stipend even if the value is not zero. The value added to gas is CallValueTransferGas - CallStipend, which means stipend gas is included in 9000 value transfer gas.
if value > 0:
    dynamic_gas += 6700         # NB: Not 9000, like in `CALL`

But in go-ethereum, the stipend gas is not included in 9000.
When executing the opcode CALL, if value is not 0, firstly add 9000 gas in function gasCall() :

github.com


ethereum/go-ethereum/blob/94ff7219114540263c76d1895618041959fae1f9/core/vm/gas_table.go#L377-L379

      
          	if transfersValue {
          		gas += params.CallValueTransferGas
          	}
      
    






Then value will be checked in function opCall(), if it is not 0, 2300 stipend gas will be added :

github.com


ethereum/go-ethereum/blob/94ff7219114540263c76d1895618041959fae1f9/core/vm/instructions.go#L683-L686

      
          	if !value.IsZero() {
          		gas += params.CallStipend
          		bigVal = value.ToBig()
          	}
      
    





Therefore, I think the dynamic_gas should add 9000 not 6700 in provided pseudo-codes.

Author: SamWilsn
Date: 2023-03-14T15:53:52.598Z

It’s been a long while and I’m not extremely familiar with geth, but I think the first link (core/vm/gas_table.go) is where the gas is deducted from the parent, and the second link (core/vm/instructions.go) calculates how much is available to the child.

Author: etan-status
Date: 2023-08-28T21:24:45.442Z

Note that MAGIC would have to be changed to a different value, now that EIP-4844 uses 0x03 as its EIP-2718 transaction type.

Author: 0xnirlin
Date: 2023-10-07T06:06:04.167Z

@SamWilsn hey what is the progress on this eip and how many chances are there of it going through?

Author: SamWilsn
Date: 2023-10-07T07:00:36.650Z

There hasn’t been much movement on this. We’ve paused pushing for it on ACD for the time being.

Author: ArikG
Date: 2024-01-29T09:01:44.059Z

Is that still the case given the recent growing support in the ecosystem?

Author: SamWilsn
Date: 2024-02-07T21:07:03.793Z

Talks have opened up again. Still rather early to tell though.

Author: SamWilsn
Date: 2024-02-20T22:34:57.549Z

There is a breakout call on this subject tentatively scheduled for Feb. 28th: Future EOA/AA Breakout Room · Issue #962 · ethereum/pm · GitHub

Author: bumblefudge
Date: 2024-02-29T01:25:48.823Z

An hour wasn’t enough to both levelset AND advance too far towards decisioning, it seems, so the topic will be continued on tomorrow’s call, at 7am denver time:
https://github.com/ethereum/pm/issues/961

Author: SamWilsn
Date: 2024-03-26T16:44:00.862Z

Regarding the recent changes in this pull request, how sure are we that the worse case invalidation with 3074 is similar to a proposer invalidating transactions with a block?
Back of the napkin estimate looks like AUTH + AUTHCALL costs about 10,200 and a normal transaction is about 21,000. So this halves the price of a tx pool invalidation attack?

Author: jochem-brouwer
Date: 2024-03-27T23:49:59.416Z

There is something I would like to raise, we still have accounts where pkeys are stolen from (these are now public, so every time you send ETH there it is immediately drained). However, some of these accounts have other assets with more value than just a simple ETH transfer (e.g. ERC20 tokens). I think we can foresee that at the moment we launch this opcode, then we will see a huge influx of people spamming AUTHCALL on accounts which have almost zero eth left, but with significant ETH values (and we cannot determine if these are the original owners or the attackers (likely: the attackers)). Just wanted to raise this point here, not sure if this was raised before.
Stealing ERC20s was practically not possible from these accounts, since you need ETH to fund these accounts to send the txn. Since we pay 21k gas for one tx, and we pay more for an ERC20 transfer, then the gas bidding accounting will always be won by the ETH tx.

Author: MicahZoltu
Date: 2024-03-28T03:49:51.630Z

Getting ERC20 tokens out of such accounts can already be done via bundled transactions and a private relay.  In fact, there is a self-help tool (disclosure: I’m on the team that built it) that allows end-users to do this without needing any knowledge of scripting.  I think at this point, any well known tokens in public-private-key accounts that are trapped have already been liquidated.

Author: jochem-brouwer
Date: 2024-03-28T04:42:19.802Z

Ah right, good point, I should have been aware of this method of course. Thanks for the reply

Author: Amxx
Date: 2024-03-28T17:03:36.127Z

Given the important push for inclusion of this EIP in the next hardfork, I would like to formally express my concerns about the usage of the signer’s nonce for invalidation of the AUTH, and the inconsistencies that creates.
Lets says Alice has nonce 10, and signs an Auth with nonce 10. This signature is valid, and Bob can relay it to perform some operation in Alice’s name. After the operation is done, Alice’s nonce does not change, so it is essential that the forwarder (contract that uses the Auth and does AuthCall) includes some replay protection.
However, if Bob doesn’t relay the message, and Alice wants to do it herself (Alice might be using a “multicall” forwarder), then the nonce Alice used is invalid, because the transaction that Alice submits increases the nonce BEFORE the Auth is verified.
This means that if Alice plans to relay the Auth herself, she needs to sign something different (nonce 11) than if she plans to have Bob relay it (nonce 10).
I think this is really messed up, and I would like to propose that if authority is tx.origin, then the nonce that is used should be the one before the current transaction (ie. the current one minus one).
I believe this change would make signing a Auth agnostic of the relayer (which I believe is a good thing).

Author: matt
Date: 2024-03-28T17:20:01.728Z

Although I think the case where a user needs to manually relay a 3074 msg which isn’t getting picked up by a relayer is small, this seems like a reasonable modification to me.
It still doesn’t abdicate the invoker from performing replay protection. Now, if a user has an auth message relayed (nonce N), they may use that message again during self-relaying. This is reverse of the current situation.

Author: Amxx
Date: 2024-04-11T15:53:17.300Z

matt:

I think the case where a user needs to manually relay a 3074 msg which isn’t getting picked up by a relayer is small


One of the use case that was put forward is EOA multicall.
Wallets such as Metamask may expose a multicall endpoint that relies on a forwarder to execute a batch of operations signed by the wallet. If you are trying to replicate the current EOA UX, you don’t need to add in the extra cost of having to refund a relayer that pays the gas.
I’m expecting this usage, that requires minimal infrastructure beside basic wallet support, to be the first usage of 3074

Author: Philogy
Date: 2024-04-12T11:59:21.084Z

There seems to be some incongruence in the EIP, the section that defines what message AUTH validates seems to include replay protecting aspects such as a nonce and chain ID (^1):

The arguments (yParity , r , s ) are interpreted as an ECDSA signature on the secp256k1 curve over the message keccak256(MAGIC || chainId || nonce || invokerAddress || commit) , where: […]

While the security consideration section seems to imply that handling of replay protection is left up to the contracts and the only signed over is the magic, invoker address and commit?

Author: xinbenlv
Date: 2024-04-12T12:34:47.935Z

I wonder, if ERC-2098 Compact Signature proposed by @ricmoo has been considered in EIP-3074 which allows a signature to be represented by 64bytes instead of 65. It seems it has not been mentioned much in this thread. Bear with me if this has been answered already.

Author: middlemarch
Date: 2024-04-12T13:03:21.777Z

As @Amxx mentions above, the user’s nonce doesn’t increment when their tx is relayed by someone else. So absent replay protection on the invoker side, Bob could relay Alice’s message an unlimited amount of times.
Intense!

Author: Amxx
Date: 2024-04-12T13:08:29.635Z

That is a feature! Nothing wrong with this (if the invoker is properly designed and the user understands what he/she signs)

Author: irlfarmer
Date: 2024-04-12T13:20:37.127Z

Would be possible to have a variable for timestamp of creation and a timestamp for expiry on these signatures ?

Author: middlemarch
Date: 2024-04-12T13:39:55.182Z

I agree, but then why put the nonce in the signature at all? That protection is also unnecessary if users understand what they sign and only use well-designed invokers. Plus it creates the weird inconsistency you describe above!
In practice not being able to invalidate anything ever seems riskier, but in general you have to assume I think that one bad sig drains you in either case.
I think it’s an amazing EIP so not trying to be too critical, just wrapping my head around it.

Author: middlemarch
Date: 2024-04-12T13:40:27.017Z

It is possible but only if the invoker contract demands it. At the protocol level the signatures never expire.

Author: irlfarmer
Date: 2024-04-12T13:56:25.982Z

A couple contract already have this implemented, but if we getting a fork this big might as well add it on a protocol level

Author: SamWilsn
Date: 2024-04-12T14:09:19.226Z

middlemarch:

why put the nonce in the signature at all?


This proposal languished for quite some time because there was no in-protocol revocation. Adding nonce was @matt’s compromise to get something on mainnet.

Author: SamWilsn
Date: 2024-04-12T14:11:57.629Z

xinbenlv:

I wonder, if ERC-2098 Compact Signature  […] has been considered in EIP-3074[?]


We hadn’t thought about it, no. That is some clever packing!
An invoker contract could implement that to save calldata/storage, or we could extend the supported signature formats to allow it in a future EIP.
Unless there’s a significant gas overhead to doing the transformation in the invoker, I think I’d rather stay with the current signature encoding for now.

Author: SamWilsn
Date: 2024-04-12T14:14:11.758Z

irlfarmer:

A couple contract already have this implemented, but if we getting a fork this big might as well add it on a protocol level


Our philosophy has been to keep the in-protocol parts of 3074 as minimal as possible: if it can be implemented in the EVM, it should be implemented in the EVM. This gives as much power as possible to invoker implementers.

Author: irlfarmer
Date: 2024-04-12T14:31:27.347Z

Makes sense as to avoid most contacts becoming obsolete, but what happens if an invoker gets exploited

Author: frangio
Date: 2024-04-12T15:19:43.015Z

Signature validity and signer recovery is handled analogously to transaction signatures

Does this include reverting if the signer account has bytecode?

Author: Philogy
Date: 2024-04-12T15:50:18.552Z

My core question was more whether the nonce should be part of the top-level auth message but that’s a good point that either way it doesn’t provide native replay protection, merely the possibility of revoking an authorization but submitting an on-chain transaction.
To add to this I don’t think it’s a good idea to include the chain ID in the top-level message, this should be a design choice made by the contract to allow for chain agnostic / multi-chain use cases.

Author: marktoda
Date: 2024-04-13T15:00:22.201Z

I’d like to put in a case for leaving chainId replay protection up to the invoker with a tangible example where cross chain replay by design is quite useful
A powerful underexplored pattern with 3074 is to use an invoker as the primary source of authentication logic. This can be done by crafting a one-time AUTH message with no replay protection and generating a synthetic signature so there is no underlying private key. Now that 3074 supports native transfer this effectively allows for singleton SCW implementations and near-full SCW functionality without deployment required
Enforcing chainId severely limits this pattern as a given account generated this way must be chain-specific, causing horrible multichain wallet UX.

Author: derek
Date: 2024-04-13T17:52:35.570Z

@SamWilsn is the EIP already “finalized” to a point that you (the coauthors and the EIP reviewers) for sure won’t consider leaving chainId and nonce out of the signed message?
Personally I think it would be a huge missed opportunity to not give Invokers complete flexibility in implementing their own replay protection and revocation mechanisms.  Revocation in particular should be VERY easy to get right in terms of audit – if you want to be sure that your Invoker uses authorizations that can be revoked via nonce, just check if the nonce is part of the commit.
For those of us who didn’t follow 3074’s entire journey, can you share the main objections to leaving replay protection / revocation for Invokers to handle?

Author: SamWilsn
Date: 2024-04-13T18:14:22.433Z

You don’t need to convince us authors; we had originally spec’d this out without in-protocol chainId or nonce. We added them as concessions to get something into a fork.
You need to convince the core developers on AllCoreDevs that we don’t need in-protocol enforcement of these values. Many of them have commented in this thread with their reasoning.

Author: derek
Date: 2024-04-13T18:24:00.748Z

I guess there’s no shortcut to reading this entire thread 
The thing that kills me about including nonce is that now sending any EOA transaction invalids all outstanding authorizations.  Many people use many different wallets with the same EOA, and now if some of these wallets are 3074 and some of them are not, the non-3074 wallets will screw up the 3074 ones.  So you have to be all-in on 3074 wallets.
Anyways, will read the thread and try to understand the objections.

Author: derek
Date: 2024-04-13T19:21:14.411Z

Screenshot 2024-04-13 at 3.12.33 PM2576×542 99.9 KB
Actually I noticed that this section says that the only signed fields are invoker and commit, contrary to the actual spec.  Probably forgot to update this part?
To be clear, I am also in favor of only signing invoker and commit.

Author: SamWilsn
Date: 2024-04-14T00:52:19.625Z

Thanks! How’s this: Update eip-3074.md: explain `nonce` and `chainId` in rationale by SamWilsn · Pull Request #8428 · ethereum/EIPs · GitHub

Author: winsvega
Date: 2024-04-14T07:42:50.180Z

Did I get it right that now it will be possible:
With auth opcodes, imagine you just send eth to some address, but that address is a contract and your wallet won’t even tell you, you think it’s a regular token transfer, but not, the dest will ask your tx for this auth call. You won’t notice anything, but account will be compromised

Author: matt
Date: 2024-04-14T13:45:25.580Z

No, you have to sign a separate message (with the 3074 type byte) and relay it on-chain. Additionally, signing a 3074 auth doesn’t mean your account is compromised. If the invoker is well implemented, it’s just as safe as a transaction from a smart contract wallet.

Author: antoncoding
Date: 2024-04-15T16:03:26.240Z

Hey guys! excited to see this EIP being included in the upcoming fork.
I do have one questions around impact of this EIP that i saw someone discussing and wanna confirm here: Will this EIP be able to enable “permanent” delegation to a invoker contract? I saw someone mentioned an uescase where users can use their EOA to “delegate once” to a multisig and use that to send daily txs on behalf of the EOA.
My understanding is that AUTHCALL can only happen after AUTH within the single call frame, so every time a contract needs to make AUTHCALL, it needs a (new) signature by the original EOA owner. This would mean the usecase above is impossible. Am i correct or is there other ways to bypass this?

Author: 335767028Tian
Date: 2024-04-16T02:17:43.863Z

when an invoker use an authcall opcode, does the nonce must be the same as auth included? Or the nonce is the value which is from tx.original

Author: CalabashSquash
Date: 2024-04-16T09:43:18.248Z

Determining if msg.sender is an EOA without tx.origin is difficult (if not impossible.)

Can’t you also check the codesize at that address?

Author: CalabashSquash
Date: 2024-04-16T10:19:44.645Z

Replay protection (ex. a nonce) should be implemented by the invoker, and included in commit. Without it, a malicious actor can reuse a signature, repeating its effects.

But the invoker contract can not see an EOA’s nonce. The invoker can’t determine whether the authority has the correct nonce at the time of AUTHCALL.
Therefore, I am assuming that the invoker contract maintains its own contract-specific nonce tracking. However, I am not sure how the invoker contract can figure out what the nonce is that was provided in the signed message.
But then it mentions that commit is actually what is used to check these things. For example, commit might be something like keccak256(nonce || "dataAboutSpecificCallToInvoke()"). Therefore, what would the nonce field in the signed message be used for? It seems that this field is optional anyway.
Thank you

Author: charles-cooper
Date: 2024-04-16T13:20:44.872Z

I have looked into this EIP and implemented a POC for vyper language support in POC feat[lang]: add EIP-3074 support by charles-cooper · Pull Request #3958 · vyperlang/vyper · GitHub. One thing that bothers me about the EIP is it seems actually like incomplete support for AA. If you think about all the ways to create call context in the EVM, there are at least 5 in regular usage - CALL, STATICCALL, DELEGATECALL, CREATE, CREATE2. However, this EIP only provides a single “authorized counterpart” opcode, AUTHCALL being the counterpart to CALL. This means that you cannot change msg.sender for the other four. While these maybe don’t seem like “super common” use cases, they also are valid use cases! (Otherwise, call contexts created by those other four opcodes would not allow access to msg.sender).
The current proposed spec is also not sympatico with proposals like EIP-7069, which propose upgrades to the existing *CALL opcodes (but there is no analogous EXTAUTHCALL opcode, which would require extra work to spec out, implement and test).
I think an improvement to the spec would be as follows:

Remove AUTHCALL opcode entirely(!)
AUTH sets an “authorization context” for all following instructions which create call context, not just CALL. For instance, STATICCALL following an AUTH invocation will use the msg.sender specified by the current authorized value. If you want to go back to the “regular” behavior, invoke AUTH again with an invalid signature to clear the current authorization.
The following details to make this pattern economic:

Update the gas schedule so that re-running AUTH for an (address, signature) pair which has already been called in this calling context is very cheap (<100 gas).
Ending the authorization scope can be done by revocation - providing an invalid (address, signature) pair. (This is already enabled in the current spec.)
Revocation is very cheap (<15 gas)
By convention, revocation can be done by providing the zero address and a zero-length buffer.

Or, revocation can be done by convention by providing ADDRESS. I don’t think it matters much.


Update the gas schedule to be very cheap for revocations (address does not match signature)
Update the gas schedule to respect warm/cold access for the authorized parameter.



I think this pattern is also just much more intuitive for developers. It is similar to dapptools/foundry/titanoboa prank intrinsic, which overrides msg.sender for all calls/creates within the prank scope (not just the specific CALL opcode).

Author: nlordell
Date: 2024-04-16T13:29:12.595Z

I have a question about the choice of the signature format of this EIP.
In particular, it is defined to expect a signature with recovery information (yParity). Then the authentication process of the opcode essentially boils down to:
success := authority == ecrecover(msg, r, s, yParity)

However, based on my understanding of ECDSA, it would be possible to just use signature verification instead of recovery here and implement AUTH as:
success := ecverify(authority, msg, r, s)

Allowing you to completely drop the yParity from the signature. While this doesn’t save much (although, to my understanding EC verification is slightly less computation), it does make the opcode function with a nice round 96 byte signature (3 x 32-byte words).

Edit: Oh, silly me, only the address is known and not the public key. Oops!

Author: SamWilsn
Date: 2024-04-16T16:12:39.720Z

antoncoding:

Will this EIP be able to enable “permanent” delegation to a invoker contract?


Permanent-until-revoked, yes. As long as you don’t send a regular transaction from the EOA, authorizations remain valid forever.



 antoncoding:

My understanding is that AUTHCALL can only happen after AUTH within the single call frame, so every time a contract needs to make AUTHCALL, it needs a (new) signature by the original EOA owner.


Using AUTH does not burn the nonce. You can re-use the same authorization as many times as the invoker allows, until the EOA’s nonce is incremented.

Author: SamWilsn
Date: 2024-04-16T16:13:32.481Z

CalabashSquash:

Can’t you also check the codesize at that address?


No, because contracts have zero codesize while running the initcode (aka constructor.)

Author: SamWilsn
Date: 2024-04-16T16:20:22.037Z

charles-cooper:

AUTH sets an “authorization context” for all following instructions which create call context, not just CALL. For instance, STATICCALL following an AUTH invocation will use the msg.sender specified by the current authorized value. If you want to go back to the “regular” behavior, invoke AUTH again with an invalid signature to clear the current authorization.


I already replied in a chat, but repeating here for visibility:


This feels very unsafe. Convince me it isn’t? With authcall, you’re explicitly asking to change sender. If all calls become authcalls, it’s easy to accidentally make a call with the wrong sender.
Like from an auditor perspective, for example, it’s easy to tell if an authcall changes sender (always).
In your suggestion, the auditor has to consider the entire callstack for every call to see if it’s possible an auth happened previously.

Author: clemlaflemme
Date: 2024-04-16T16:23:04.770Z

I was reviewing our open PR for AUTH/AUTHCALL in Kakarot and had exactly the same question: why AUTHCALL while AUTH + checking in system operation opcodes if the message is authorized would be enough?

Author: clemlaflemme
Date: 2024-04-16T16:28:49.490Z

I wouldn’t classify this as very unsafe. Like other opcode making state changes, you need to keep track of it when you consider the safety of a contract.
To me, as soon as a contrat consumes an AUTH somewhere, it means in any case that it is understood that somehow everything can be done on behalf of the signing EOA.

Author: SamWilsn
Date: 2024-04-16T16:29:33.022Z

Changing the behaviour of *call functions makes this really weird:
function foo() public {
    this.someErc20.approve(...)
}

function sudo(...) public {
    assembly {
        auth(...)
    }
    this.foo();
}

Author: clemlaflemme
Date: 2024-04-16T16:31:36.765Z

you mean
function foo() public {
    this.someErc20.approve(...)
}

function sudo(...) public {
    assembly {
        auth(...)
    }
    this.foo();
}

? (changed authcall to auth)
I kinda like this tbh, what’s wrong with this snippet?

Author: SamWilsn
Date: 2024-04-16T16:34:53.536Z

clemlaflemme:

(changed authcall to auth)


Oops, edited. Thanks!



 clemlaflemme:

I kinda like this tbh, what’s wrong with this snippet?


As an auditor, you now have to trace the entire possible callstack to ensure that someErc20.approve is never called while authorized.

Author: clemlaflemme
Date: 2024-04-16T16:40:22.735Z

I’d say the same as @charles-cooper



 charles-cooper:

I think this pattern is also just much more intuitive for developers. It is similar to dapptools/foundry/titanoboa prank intrinsic, which overrides msg.sender for all calls/creates within the prank scope (not just the specific CALL opcode).


ie “much more intuitive for developers, similar to existing tools”
The argument in favor of AUTHCALL on the other hand is also that there already 4 CALLs, almost the same with some variations for who is sender, so why not a dedicated 5th CALL for when using the authorized sender

Author: SamWilsn
Date: 2024-04-16T16:48:21.912Z

I like to follow both fail-safe design and the principle of least astonishment. It’s objectively safer to explicitly request changing msg.sender, and much more surprising if some nested subcall gets msg.sender changed.

Author: charles-cooper
Date: 2024-04-16T17:18:42.424Z

I don’t find the example you created to have low astonishment actually, since sometimes explicitness conflicts with composability.
it might easier to see if the language exposes authorization using syntactic scope:
def approve_erc20():
    extcall erc20.approve(...)

def sudo(...):
    with authorized(msg.sender, sig):
        approve_erc20()  # this looks like it should call erc20.approve(...) with authorized=msg.sender!

In this example, at least to me, the call inside sudo() to approve_erc20() reads like it should be authorized to msg.sender.

Author: SamWilsn
Date: 2024-04-16T19:05:03.707Z

charles-cooper:

In this example, at least to me, the call inside sudo() to approve_erc20() reads like it should be authorized to msg.sender.


Yes, for sure. When you’re looking at sudo, it makes sense.
What is surprising is that approve_erc20 can ever approve for an account other than the contract itself. You cannot look at just approve_erc20 and know that. You have to read the entirety of the contract.

I don’t know what exactly to call what I’m objecting to. Maybe “non-locality”?
Consider the following “complete” contract:
contract SamContract {
    ERC20 myToken;

    function withdraw() public {
        myToken.transfer(msg.sender, 100);
    }
}

Clearly this contract allows the caller to withdraw 100 units of myToken.
Now consider this contract:
contract EvilContract {
    ERC20 myToken;

    function withdraw() public {
        myToken.transfer(msg.sender, 100);
    }

    function sudo(...) public {
        assembly {
            auth(...);
        }
        withdraw();
    }
}

Without changing the code of withdraw at all, the meaning of the function has changed. Now it takes tokens from the authority.
This non-local effect is completely invisible. That’s dangerous.

Author: charles-cooper
Date: 2024-04-16T21:01:53.667Z

Sorry, this is just a strawman, as most useful programs have so-called non-local effects.
For example, this function also does something different depending on how it’s called
contract EvilContract {
    ERC20 myToken;

    function withdraw() public {
        myToken.transfer(msg.sender, 100);
    }

    function sudo(...) public {
        myToken = someOtherToken
        withdraw()
    }

Just to deconstruct the strawman now, I can now find/replace “authority” with “someOtherToken” in your objection:

Without changing the code of withdraw at all, the meaning of the function has changed. Now it takes someOtherToken instead of myToken.
This non-local effect is completely invisible. That’s dangerous.

Of course, I don’t think this means that we should get rid of all non-local effects from programming :). If anything, we should choose abstractions which encapsulate effect management, and there are tools in the modern programmers toolkit for dealing with these, ex. RAII and context managers are relevant here.

Author: SamWilsn
Date: 2024-04-16T21:10:33.282Z

You can clearly see that the behaviour of withdraw depends on the value of myToken without reading the rest of the contract. That isn’t true in my example.

Author: CalabashSquash
Date: 2024-04-16T22:48:55.248Z

As originally written, this proposal specified a precompile with storage to track nonces. Since a precompile with storage is unprecedented, a revision moved replay protection into the invoker contract, necessitating a certain level of user trust in the invoker. Expanding on this idea of trusted invokers, the other signed fields were eventually eliminated, one by one, until only invoker and commit remained. To appease concerns about cross-chain replay attacks and irrevocable signatures, the chainId and nonce fields returned to the signed message.

followed by (later in the doc)

For this reason, AUTH requires the nonce in the message to be equal to the signer’s current nonce. This way, a single tx from the EOA will cause the nonce to increase, invalidating all outstanding authorizations.

So is it correct to say that nonce does get checked by the AUTH opcode now? I’m finding it difficult to pin-point what the current state of nonces is.
While writing this, I found another confusing sentence

If an invoker has implemented replay protection, as per the authors’ recommendation…

So does the invoker do replay protection, or the AUTH opcode?

Author: antoncoding
Date: 2024-04-17T03:45:21.471Z

CalabashSquash:

So does the invoker do replay protection, or the AUTH opcode?


The invoker has to implement it, AUTH doesn’t invalidate the nonce.
(Invokers can also not invalidate the nonce, so it can intentionally reuse your signature to do multiple AUTHCALLs base on other logic)

Author: CalabashSquash
Date: 2024-04-17T04:53:49.222Z

That’s what it seems like to me.
But how do we explain this part?

For this reason, AUTH requires the nonce in the message to be equal to the signer’s current nonce. This way, a single tx from the EOA will cause the nonce to increase, invalidating all outstanding authorizations.

Specifically “AUTH requires the nonce in the message to be equal to…” implies that AUTH does invalidate the nonce, contrary to what you said. I think I might be misunderstanding something.

Author: antoncoding
Date: 2024-04-17T05:30:53.730Z

I second this strongly. I think removing chainId and nonce can unlock lots of opportunities for wallet UX, and these 2 factors are considered “easy” in contract implementations:


chainId: All EIP712 has chainId, devs and auditors are very aware of the cross chain signature reuse attacks. The OpenZeppelin ERC712 template even consider rarer scenarios like chainId changes after hardfork. This is a well-studied area where we won’t make simple mistakes unless it’s intentional.


nonce: I understand the rationale is to make sure users can “always revoke delegation”. But similar to chainId, the chance of a team “forget” the function to invalidate nonce is very very low. Famous contracts like Uniswap’s Permit2 also have very efficient and flexible nonce system that people started to adopt widely and use as a template.


I think adding these restrictions because “it could have bugs”, is the same as arguing “let’s ban smart wallets cause it COULD also allow replay attack, or forget the signature validation so anyone can steal your money”.
So, these restrictions are more for restricting “what’s the worst case a malicious invoker can do”, but IMO the protection doesn’t save users a lot from the absolute worst case, and not worth sacrificing the best UX we can achieve with this EIP.

Author: antoncoding
Date: 2024-04-17T05:38:12.512Z

@CalabashSquash See the author’s comment here, I had the similar confusion!



 SamWilsn:

Using AUTH does not burn the nonce. You can re-use the same authorization as many times as the invoker allows, until the EOA’s nonce is incremented.


AUTH does check the nonce, but it doesn’t invalidate the nonce: the purpose of having the nonce check is to make sure users can always send a “normal tx” and invalidate all outstanding EIP3074 signatures.

Author: CalabashSquash
Date: 2024-04-17T06:01:43.148Z

Right, I think I get it now, thanks!
So this means there is an EOA nonce check, but also potential for the SC to handle its own, application-specific, nonce management on top of this?

Author: antoncoding
Date: 2024-04-17T06:10:37.184Z

yes, how i understand it is that nonce mentioned here is not used for replay protection as we usually think of when we see the word “nonce”, it is more like a circuit breaker to make sure EOA owners can always revoke, so the absolute worst case of permanently losing EOA control is mitigated.
It’s up for the invoker to implement replay protection, allowing more flexibility for a signature more than once with invokers’ logic.

Author: hritzdorf
Date: 2024-04-17T11:47:00.118Z

I have a stupid question:
For AUTH, why is the commit in the memory and not taken from the stack?
I envision a typical use case like:

The signature is passed in as an argument and can be easily copied to memory with CALLDATACOPY (e.g. that is what happens when using a bytes memory in solidity)
The commit is computed based on the desired parameters (application nonce, gas, application calldata …)
Now the commit is on the stack and the signature is in memory
Now in many cases an unnecessary memory copying and packing needs to take place. In solidity developers will presumably do something like abi.encodePacked(signature, commit) so that they can have them consecutively in memory
If instead the commit was simply taken from the stack, it would be a lot easier

Sorry, if I missed this argument previously.

Author: charles-cooper
Date: 2024-04-17T16:15:55.533Z

It’s fairly easy to construct an example where the behavior isn’t obviously dependent on the literal text of the withdraw() function. For example, calling from a nonreentrant-protected function vs not-protected, or modifying the value of myToken using pointer aliasing (e.g. sstore in assembly).

Author: SamWilsn
Date: 2024-04-17T16:26:33.567Z

charles-cooper:

calling from a nonreentrant-protected function vs not-protected


You’re absolutely right, and this is a constant source of bugs.



 charles-cooper:

modifying the value of myToken using pointer aliasing (e.g. sstore in assembly).


And you want to introduce more edge cases like this?

Author: SamWilsn
Date: 2024-04-17T16:31:55.255Z

It might be more productive, @charles-cooper, to come up with something that’s mutually acceptable?
I don’t know if vyper has decorators, but annotating the function in some way to show that it can be called from within an auth might make me happy.
This snippet should compile fine:
@impersonates
def approve_erc20():
    extcall erc20.approve(...)

def sudo(...):
    with authorized(msg.sender, sig):
        approve_erc20()

While functions without the @impersonates decorator would generate an error if used inside an authorized block or function annotated with @impersonates.

Author: charles-cooper
Date: 2024-04-17T17:21:33.425Z

I mean these are things I have of course thought about and are indeed potential ways to expose AUTH to the user in Vyper. I guess the point I’m driving towards is that context managers and correct abstraction of scope can be addressed in the language or library design. The lack of “authorized” staticcall on the other hand, cannot.

Author: ankurdubey521
Date: 2024-04-17T22:40:14.086Z

As a workaround to depending on the authorising EOAs nonce, what if during AUTH we instead allow users to specific another “management” key owned by the same user and depend on the nonce of this management key for AUTH validation?
Let’s say we modify the AUTH message to the following:
keccak256(MAGIC || chainId || managementEoa || managementEoaNonce || invokerAddress || commit)
And the assumption is that the management EOA is owned by the same user, and is not used for doing general transactions and only to invalidate AUTH if the user wishes to.
This allows the main authorising EOA to continue doing transactions without invalidating AUTH, and still allow users to invalidate it by doing a transaction with the management EOA.

Author: derek
Date: 2024-04-18T03:23:03.946Z

This is a very promising idea!  I think the managementEoa can be a smart contract as well, since smart contracts have nonces too.  So I would change it to:
keccak256(MAGIC || chainId || nonceManagerAddress || nonceManagerNonce || invokerAddress || commit)

In fact, I’d imagine that the nonceManagerAddress being a smart contract would be more useful, since then the EOA can just “own” the smart contract as opposed to having to guard a separate key.
The nonce manager can even be deployed lazily — its address can be computed deterministically from a well-known factory.  That way, EOA users can use nonce managers without paying for the cost of deployment, and a lot of EOA users probably won’t ever deploy any nonce managers if they don’t ever have to resort to global revocation.

Author: ankurdubey521
Date: 2024-04-18T03:32:00.540Z

derek:

In fact, I’d imagine that the nonceManagerAddress being a smart contract would be more useful, since then the EOA can just “own” the smart contract as opposed to having to guard a separate key.


Agreed, owning a Smart Contract to manage this would be much easier.

Author: oren
Date: 2024-04-18T03:57:56.199Z

One significant tradeoff of having nonceManagerAddress be a smart contract is it makes the implementation of this opcode more complicated.
How about nonceManagerAddress being able to be either an EOA or a smart contract, in both cases it checks the nonce of the account like today’s implementation. And when it’s a smart contract, it’ll use the CREATE opcode in order to increase its nonce?
More thoughts:

It can also be used by smart contracts as a “nonce oracle” - till now contracts did not have access to the nonce of accounts. Not sure what are the implications of this.
It will change the gas pricing of the opcode because it will be accessing another address which might be cold.

Author: ankurdubey521
Date: 2024-04-18T04:08:23.271Z

oren:

How about nonceManagerAddress being able to be either an EOA or a smart contract, in both cases it checks the nonce of the account like today’s implementation. And when it’s a smart contract, it’ll use the CREATE opcode in order to increase its nonce


Yup, that is what we’re proposing above.


t can also be used by smart contracts as a “nonce oracle” - till now contracts did not have access to the nonce of accounts. Not sure what are the implications of this.


Isn’t this possible (for EOAs) with the current 3074 standard as well?

Author: oren
Date: 2024-04-18T04:40:10.097Z

Oh okay cool.
Kind of: it’s currently only possible to get an oracle for your own EOA’s nonce, and with this, you can use the oracle for any address.

Author: ankurdubey521
Date: 2024-04-18T04:42:27.364Z

Good point, didn’t consider the fact this allows you to verify the nonce of arbitrary contracts on-chain.
Although I’m unsure what the implications of this are.

Author: MrSilly
Date: 2024-04-18T08:58:00.960Z

matt:

If the invoker is well implemented, it’s just as safe as a transaction from a smart contract wallet.


Actually a lot of assumptions have to hold. The user also has to understand what it means to sign an EIP 3074 transaction. Wallets either don’t let you authorize any invoker not on their whitelist (e.g., Metamask will only let you use the Metamask invoker) or they open users to scams and poorly written invokers. Incidents are bound to happen so strict whitelists will be the standard and they’ll be justified as a sad but necessary trade off of permissionless innovation in favor of “security”. Developers having full control over the account allows them to do a bunch of interesting things like intents, but in practice only developers that work for a large wallet company like Metamask will be able to access that power.
The root problem is EIP 3074’s all or nothing security model. It’s the old sudo/setuid model, which produced an endless stream of security breaches on Unix. Modern systems have moved to a capability based design. EIP 3074 forces us to choose between restricting innovation to a handful of players  and endless scamming.
EIP 3074 is just a bad idea on so many levels. The campaign’s modus operandi was bait and switch. Appeal to developer’s desire for EOA programmability and don’t mention the whitelisting that will be necessary. Appease the security experts by adding nonce and chainID, and then once it passes ACD you start campaigning to remove those “concessions”.
EIP 3074 would never have gotten this far on technical merit. The only reason we seem to be seriously considering it for inclusion now is the some of the people involved seem to be quite adept at using social engineering techniques to play backroom politics.

Author: matt
Date: 2024-04-18T14:59:10.421Z

MrSilly:

they’ll [wallet whitelists] be justified as a sad but necessary trade off of permissionless innovation in favor of “security”


I think we have very different definitions of permissionless. Anyone can create a wallet with whatever whitelist they want / no whitelist at all. If a wallet decides to gatekeep a feature, that is their choice. They could already do so today. The protocol has no concept of permissions. That is permissionless.



 MrSilly:

The root problem is EIP 3074’s all or nothing security model.


This is an oversimplification of the security model. 3074 allows you develop arbitrary capabilities. When you sign to an invoker, you are signing only to a certain capability implemented by that invoker. The correctness of this can be determined by auditing the contract. This is far more powerful than implementing such features directly in the protocol.
It’s also the same type of security model as a smart contract wallet. When you’re executing in the context of the wallet, it has “sudo” capabilities. It is the implementation of the wallet which enforces the security model. In both cases, you can be certain of the safety by reviewing the code.
This isn’t Linux. There aren’t RCEs in smart contracts. We can formally verify an invoker and be certain it implements only the defined capability.



 MrSilly:

EIP 3074 would never have gotten this far on technical merit. The only reason we seem to be seriously considering it for inclusion now is the some of the people involved seem to be quite adept at using social engineering techniques to play backroom politics.


ACD doesn’t accept EIPs w/o merit. And no EIP makes it without a champion. I have spent a lot of time discussing the EIP with many different members of the community, sometimes in non public discussions. Each has had the opportunity to decide the merit of the proposal themselves. Of course, many EOA wallets and their users are excited about the proposal because it finally breaks the monopoly of UX improvements held by smart contract wallets.
This isn’t social engineering. 3074 is extremely beneficial to a lot of Ethereum users and they voiced their support.

Author: MicahZoltu
Date: 2024-04-18T19:02:58.517Z

MrSilly:

Appease the security experts by adding nonce and chainID


The security experts are not the ones demanding nonce and chainID.

Author: MicahZoltu
Date: 2024-04-18T19:06:29.540Z

SamWilsn:

It might be more productive, @charles-cooper, to come up with something that’s mutually acceptable?
I don’t know if vyper has decorators, but annotating the function in some way to show that it can be called from within an auth might make me happy.
This snippet should compile fine:
@impersonates
def approve_erc20():
    extcall erc20.approve(...)

def sudo(...):
    with authorized(msg.sender, sig):
        approve_erc20()

While functions without the @impersonates decorator would generate an error if used inside an authorized block or function annotated with @impersonates.


This would need to be constrained to within a single EVM call frame.  Otherwise you could call some third party contract and change its internal behavior by setting the authorized flag.
Being able to AUTH_STATIC_CALL would definitely be nice, it does feel like it is “missing”, though it could be added later in theory.

Author: shemnon
Date: 2024-04-18T19:31:59.023Z

hritzdorf:

For AUTH, why is the commit in the memory and not taken from the stack?


It’s not just the commit, it’s the entire signature to.  The stack is limited to 256 bits.  Taking the commit and signature from memory preserves design space so that AUTH could use different signature schemes (such as BLS) or more divergent mechanisms such as SNARKS or quantum  safe lattice signatures.  Given yParity is 1 or 0 the first byte can still easily be used to signal type.

Author: shemnon
Date: 2024-04-18T19:37:17.411Z

MicahZoltu:

The security experts are not the ones demanding nonce and chainID.


I didn’t ask for nonce, I demanded single-action-revocation.  Nonce was the EIPs authors solution to that request.  If you can hand over total control of your account with a single action, you should be able to revoke it with a single action too.

Author: xinbenlv
Date: 2024-04-19T02:10:26.580Z

shemnon:

I didn’t ask for nonce, I demanded single-action-revocation. Nonce was the EIPs authors solution to that request. If you can hand over total control of your account with a single action, you should be able to revoke it with a single action too.


Agreed
I also like to second the concern about introducing nonce and chainId. Introducing these values alone doesn’t guarantee protection of replay attack, while makes it hard to handle other situations such as more than one outstanding TX.
Editorial suggestion
Invoker is first introduced in this EIP and was not a common terminology prior. Can we give a definition of invoker at the first time when the word invoker appear? (Especially to clarify relationship with signer)

Author: matt
Date: 2024-04-19T03:05:16.118Z

xinbenlv:

Invoker is first introduced in this EIP and was not a common terminology prior. Can we give a definition of invoker at the first time when the word invoker appear? (Especially to clarify relationship with signer)


It’s defined immediately after it appears. Read the third bullet of this section. It’s discussed in even more detail later on.

Author: MicahZoltu
Date: 2024-04-19T10:46:43.892Z

shemnon:

If you can hand over total control of your account with a single action, you should be able to revoke it with a single action too.


You can already hand over total control of your account with a single action: Give your private key to someone.  An invoker is strictly less bad than giving up your private key because the actions the invoker can take are constrained by its code, while a private key hand-over is truly unlimited.

Author: shemnon
Date: 2024-04-19T13:40:11.916Z

MicahZoltu:

You can already hand over total control of your account with a single action: Give your private key to someone.


In the normal course of operations for a wallet a dApp cannot cause the wallet to raise a prompt that will cause you to share your secret phrase.  An AUTH request, however, will raise that dialog.
So unless the industry standard is going to be keep dApps from being able to raise these requests, then bury the UI three screens deep below a blurred out section with multiple warnings in bright red saying “don’t do this unless you really know what you are doing” then an only then can we equivocate sharing private keys to an eternal AUTH request.  I don’t think that’s what MetaMask is planning, a whitelist is far from this.

Author: hritzdorf
Date: 2024-04-19T14:51:43.618Z

Thank you for your feedback. Sorry, What I meant was:

commit on the stack
signature in the memory

As I assume that the commit will stay 32 bytes for now and as the keccak output lands on the stack.
So overall:
Stack:




Slot
Value




top - 0
authority


top - 1
commit


top - 2
offset


top - 3
length



Memory:

memory[offset : offset+1 ] - yParity
memory[offset+1 : offset+33] - r
memory[offset+33 : offset+65] - s

Author: shemnon
Date: 2024-04-19T17:29:35.751Z

Commit isn’t on the stack.  I think it changed because of the concerns you are raising…


Ethereum Improvement Proposals


EIP-3074: AUTH and AUTHCALL opcodes
Allow externally owned accounts to delegate control to a contract.

Author: MicahZoltu
Date: 2024-04-20T05:49:39.025Z

shemnon:

In the normal course of operations for a wallet a dApp cannot cause the wallet to raise a prompt that will cause you to share your secret phrase. An AUTH request, however, will raise that dialog.


This is absolutely not true.  Wallets should not expose any RPC that allows an app to prompt a user to add an invoker, just as they should not expose any RPC that prompts a wallet to provide the dapp with the private key.  If people believe the same as you, this may explain why there is so much backlash against this proposal.
To be explicitly clear, wallets MUST NOT allow dapps to prompt users to add arbitrary invokers.
Wallets MAY allow dapps to prompt the user to add an invoker that the wallet provider has explicitly whitelisted.  Getting an invoker onto such a whitelist should involve massive amounts of independent auditing work, validation, testing, and possibly some amount of lindy.
Adding an invoker is a similar trust model as giving your private key to a new wallet provider.  It is a bit safer, but not nearly safe enough that dapps should have any mechanism for prompting users to add arbitrary invokers.

Author: marc
Date: 2024-04-22T19:32:15.479Z

An essential aspect that deserves attention, yet doesn’t often get its weight, is the continuing mindset among developers on what constitutes an account on Ethereum. I will repeat a sentiment frequently echoed: “Smart contract wallets are regarded as second-class citizens on Ethereum”. An EVM developer typically perceives an account solely as an EOA, and when they do think of testing their application with more than one wallet, it’s often with another EOA. It’s not their fault; the protocol is designed in a way that still, and and continue to favors this perspective.
I will mention two oversights frequently disregarded by EVM dapp developers:


Support for ERC-1271 or ERC-6492, which provide standard signature validation methods for contracts. Again, it’s not their fault. We should not expect developers to know every ERC to launch their dapp.


Multichain dapps (pretty much every EVM dapp) often assume an account’s availability across every network, a presumption that does not hold true for smart contract wallets. The result: a SCW can’t create an initial connection with the dapp. More in details:

Frequently, this results in dapps requiring a connection to a specific network (typically L1 by default), and then asking for a switch to an L2 after the initial wallet connection. While this issue can partly be attributed to initial design releases of walletconnect modals, it underscores the oversight of accommodating smart contract wallets even by well-intentioned companies such as WalletConnect.



Being incompatible with the dapp ecosystem effectively renders a Smart Contract Wallet obsolete on Ethereum.
The EVM is witnessing the departure of some of its most skilled wallet developers due to this very issue. Numerous teams launched smart contract wallets, only to discover their incompatibility and lack of support across the EVM’s array of dapps. One prominent example is Argent, which ultimately gave up on EVM, and transitioned to Cairo’s Starknet. Their reasoning: on Sarknet, every account is a SCW, aligning with the expectations of EVERY dapp over there.
With ERC-4337 and RIP-7560, SCWs have finally captured some, if not little, attention of dapp developers, who now consider testing their dapps with a wallet that is not an EOA. Just recently, Uniswap removed an unjustified warning that  prevented smart wallets from interacting with their interface. Without the highlight that ERC-4337 gave to SCWs, this issue would never have been fixed. If a prominent company like Uniswap had this issue, imagine other dapps, particularly those with limited resources. Will they ever test their dapps with more than one wallet?
If our objective is to cater to future users with full AA, then pursuing EIP-3074 distracts both wallet and dapp developers from this goal. The underlying message conveyed here is that we will continue supporting EOAs enshrinement and development, and the adoption of smart accounts will continue to be optional.
EIP-3074 has garnered favorable responses from both EOA wallets and some SCW tooling providers, despite EIP-3074 only addressing execution abstraction alone. Why? Quite simply, for wallets, it already integrates seamlessly with the present dapp ecosystem, and that’s where the profit lies. For some SCW infra providers, it expands their market to the current userbase of EOA wallets with gas sponsorship relaying.
Achieving full account abstraction on Ethereum relies on our capacity to focus efforts, rather than splitting the already limited attention span within our ecosystem.

Author: matt
Date: 2024-04-22T20:16:07.311Z

shemnon:

In the normal course of operations for a wallet a dApp cannot cause the wallet to raise a prompt that will cause you to share your secret phrase. An AUTH request, however, will raise that dialog.





 MicahZoltu:

Wallets should not expose any RPC that allows an app to prompt a user to add an invoker, just as they should not expose any RPC that prompts a wallet to provide the dapp with the private key.


This is really the key misunderstanding that people have with 3074. Just because it is permissible to do so doesn’t mean this is how it should be utilized.
It’s like saying we should have protocol nonces for smart accounts because “a dapp might ask you swap the implementation of your smart account for their specially extended one”. Yes, you could imagine a design where this is possible. It just doesn’t make sense though because it’s totally insecure.

Author: thogard
Date: 2024-04-23T08:56:30.556Z

To be crystal clear:

I do not have a problem with metamask, specifically.
I do have a problem with white lists maintained by large, private companies.
I understand that the Ethereum codebase is permissionless.
I understand that anyone can build a wallet and market their wallet to users.

But what I don’t understand is why people think “If you don’t like it, just make your own wallet company!” is a reasonable response to my concern as an app dev about not having feature-parity with the apps made by wallet companies.  That approach might be viable for unicorns like Coinbase and Uniswap, but it isn’t for me.
3074 white lists are wallet-specific. The invoker contracts are chain specific.  If I want to make a smart contract that uses AUTH or AUTHCALL on ten different chains with the ten largest wallets then I will need to go through one hundred wait lists and audits. Many of those white lists will be managed by wallet companies building their own applications, some of which may be competing with mine.
The debate seems to have missed one critically important fact: a white listed invoker that is generalized enough for the use cases of all apps would be so generalized that maintaining a white list would no longer serve a purpose, as any hostile app could fully drain the user via the generalized invoker.
An example:

A lending protocol similar to AAVE, but with a ‘hook’ that executes prior to the liquidation of a borrower’s collateral. The hook would use 3074 to deposit more of the user’s collateral tokens into the lending protocol to avoid the liquidation.

An app-specific version of this invoker would:

Ensure that AUTHCALL is only used during the liquidation.
Ensure that the AUTHCALL is only called explicitly by the lending protocol.
Only transfer the specific token that matches the user’s collateral token.
Only deposit up to a pre-approved amount set by the user when they opted into the hook.
Can continue ‘topping off’ multiple collateralized positions to protect the user from liquidations while keeping the user capital efficient.
Can be opted-out at any time.
Fully immutable, etc

Now if we set up this hook to access the 3074 op codes through a generalized invoker, this is what it would look like from the perspective of the generalized invoker:
(assume prices are crashing)

The invoker would be called by a contract (the invoker is not used as an entrypoint)
The contract would then transfer some of one of the user’s tokens to itself
It would then transfer some of another one of the user’s tokens to itself
And it would keep doing this until the user is fully drained.

The generalized invoker has no sense of the lending protocol. It doesn’t know that the user had deposited multiple different ERC20 tokens into it, it also doesn’t know that each of these transfers is a deposit that is protecting the user.
From its POV, all it sees is some contract transferring all of the users’ tokens to itself.  Without apriori knowledge of the lending protocol, this would be indistinguishable from an attack.
If a white listed invoker allows the calling contract to take all of the users’ tokens then there’s no point in maintaining a white list. Importantly, the app-specific version of the invoker would be significantly safer than any invoker that is generalized enough to perform this feature.
Although this design, specifically, isn’t something I’m planning to build, this app-specific invoker design is a genuinely useful feature. It’s a feature that helps users. It’s a feature that provides value to users - both by freeing up a portion of their collateralized capital and by mitigating the losses that a user suffers upon liquidation. This type of app doesn’t even use intents; with intents, the advantages of in-app 3074 are even more pronounced.
I do not want to have to “build my own wallet company” in order to build an app like this.  I do not want to have to “build my own wallet company” to have feature parity with the wallet companies building apps like this.
As an app dev, my perspective is:

I would strongly prefer for the permissioning of smart contract usage of 3074 to be managed by users in a similar way (but more pronounced, perhaps) to how users currently manage token approvals.
If that isn’t possible, I would prefer for smart contract usage of 3074 to be handled solely by an enshrined invoker contract.
If that isn’t possible, then I do not believe that 3074 is secure enough for production.

I do not believe that invoker interactions should be heterogenous between wallets. Handling the permissioning offchain doesn’t make a system permissionless, especially when that permissioning is explicitly assumed to be occuring and is factored into the security assumptions of the proposal.  If the EIP is too unsafe to function without strict permissioning from offchain actors then, in my opinion, it is too unsafe for production in a permissionless system.

Author: MicahZoltu
Date: 2024-04-23T12:10:29.874Z

I think the concern of centralizing apps into wallets because wallets have more capabilities is a legitimate concern.  However, wallets already have privileges for doing what any invoker could do today, but they choose (for whatever reason) not to leverage that.  Invokers make it so there is a path somewhere between “giving your keys to a new entity” to “only your wallet can do these things”.
My hope is that we see a small number of high profile individuals within the community (ideally not just big name platforms financial platforms, but people building public goods) write some useful general purpose invokers and then all wallets add them.  I also hope that this doesn’t just turn into “Uniswap can write invokers and no one else can”.

Author: MrSilly
Date: 2024-04-24T07:08:31.795Z

matt:

I think we have very different definitions of permissionless. Anyone can create a wallet with whatever whitelist they want / no whitelist at all. If a wallet decides to gatekeep a feature, that is their choice. They could already do so today. The protocol has no concept of permissions. That is permissionless.


EIP 3074’s all or nothing, trust-maximizing security model pulls towards permissioned innovation because it requires a tremendous amount of trust capital to play. Permissioned innovation is the consequence we should expect, because in practice, devs outside a very limited set of players won’t be able to use this. It’s great for Metamask’s ability to innovate, not so great for dapp devs. Should we pretend the protocol exists in a vacuum? You yourself are now advocating whitelisting invokers, losing some vocal supporters in the process. I agree that nothing else makes sense. If whitelisting isn’t the standard best practice straight out the gate it soon will be after an onslaught of scams. Trust minimized security models (eg 4337 paymasters)  level the playing field for a much wider range of devs.



 matt:

This is far more powerful than implementing such features directly in the protocol.


I don’t think anyone is seriously advocating implementing complex accounting features in the protocol. 4337 already works without ANY protocol changes. Having some protocol changes will help in the future with efficiency, but even without them full 4337 style account abstraction is already more powerful than EIP 3074 EOAs. What is more relevant is that enshrining EOAs will likely delay Ethereum’s full account abstraction roadmap by creating a less powerful half measure. This will reduce the sense of urgency in developing account abstraction. We’re more likely to get stuck on a local maxima.



 matt:

This isn’t Linux. There aren’t RCEs in smart contracts.


Apologies if I am misunderstanding you, but you seriously suggesting that the environment in which the EVM operates is less adversarial than Linux’s? Every bit code on the EVM is transparent. All of its attack surface, every method is immediately exposed. No firewalls. If you exploit it, there’s money at stake. Sudo on Unix systems gave us an endless parade of security headaches even when Unix was still running inside friendly academic networks. As soon as the environment got more adversarial we had to throw it out “all or nothing” as a reasonable security design and replace it with capabilities and mandatory access control mechanisms like RBAC. If sudo isn’t good enough for a Linux server on the Internet, how can it be good enough for EVM account security?



 matt:

We can formally verify an invoker and be certain it implements only the defined capability.


It is much safer to rely on a good trust-minimized security design than rely on a vaporware ecosystem of formally verified contracts. If formal verification were so easy, all the major on-chains contracts would be formally verified. That doesn’t seem to be the case. Besides, formal verification is no panacea. Even if you formally verify the implementation, there’s no way to formally verify the spec for the formal verification process. In practice, EIP 3074’s trust maximized model is going to get us a very limited set of very powerful, non formally verified invokers that support features as as intents.

Author: MrSilly
Date: 2024-04-24T07:13:00.678Z

MicahZoltu:

Give your private key to someone.


Wouldn’t you expect the implications of handing over your private key to be much more commonly understood than the implications of authorizing an EIP 3074 invoker? If you agree that’s true, how long until we reach parity? What happens in the meantime?

Author: rafiers
Date: 2024-04-24T09:42:20.307Z

As someone deeply invested in the vision of Ethereum’s smart contract wallet, advocating 4337, I’m not entirely sure about my stance on the long-awaited 3074 change. It’s not because 3074 is a bad development, but rather because of the differences between the state of its proposal vs where we are at today.
I believe there are some fundamental questions we need to address regarding 3074 to further discuss the implementation:

Is 3074 being implemented to expedite and streamline the transition to 4337? If so, do we have an updated roadmap on this matter? What roadmap exists for EOA wallets implementing AUTHCALL to evolve into fully smart contract wallets?
Is 3074 being accepted to ensure that EOA wallets don’t fall behind in features and user experience compared to smart contract wallets emerging with 4337?

Within this framework, I think it’s essential for all parties to discuss 3074 more openly.

Author: MicahZoltu
Date: 2024-04-24T14:38:56.314Z

MrSilly:

Wouldn’t you expect the implications of handing over your private key to be much more commonly understood than the implications of authorizing an EIP 3074 invoker?


I would expect a wallet developer looking to add support for EIP-3074 will understand the implications.  I would not expect an end-user to understand the implication.

Author: danfinlay
Date: 2024-04-24T16:33:18.068Z

Hi all, scanning some of the recent discussion.



 marc:

If our objective is to cater to future users with full AA, then pursuing EIP-3074 distracts both wallet and dapp developers from this goal. The underlying message conveyed here is that we will continue supporting EOAs enshrinement and development, and the adoption of smart accounts will continue to be optional.


I really agreed with your post up until this point. It’s true that dapps want simple compatibility with all wallets, but if EOAs can suddenly add the same interfaces that SCAs can add, then it provides a platform for all wallets/dapps to align around interfaces that can be generalized across both account types. If we can agree on those interfaces (and I think we should be able to agree this interface is not exposing the AUTH opcode directly to dapps), then 3074 creates a path for dapp devs to more easily support all wallets.
This unseats the EOA interface as the “maximum supportable interface” for dapps to rely on, and opens the space for SCAs to participate competitively.



 MrSilly:

The root problem is EIP 3074’s all or nothing security model. It’s the old sudo/setuid model, which produced an endless stream of security breaches on Unix. Modern systems have moved to a capability based design. EIP 3074 forces us to choose between restricting innovation to a handful of players and endless scamming.


I completely agree that we would be better off with an object-capability security model, like Google’s Fuchsia. The question: How do we migrate there? By adding 3074, we create developer-space for iterating on what a better security model would look like. Yes, it’s a hot wire, but it’s not one intended to be exposed to every site. Instead, it enables iterating on better/safer interfaces.
I’ve been working on one proposal (sure to be replaced by a better one) for a better and more secure interface that 3074 would allow both EOAs and SCAs to expose. It’s an interface that can be agnostic to implementation but also opinionated enough that it provides more coherent guarantees during site connection.



 thogard:

The debate seems to have missed one critically important fact: a white listed invoker that is generalized enough for the use cases of all apps would be so generalized that maintaining a white list would no longer serve a purpose, as any hostile app could fully drain the user via the generalized invoker.


This makes the assumption that any generalized interface is insecure. I think we can agree that exposing AUTH directly to strangers is insecure, but by allowing open-ended community development around wallet-dapp interfaces, we will be able to explore exactly how secure an interface can be made. Can it be fully general? We’ll be able to ask that, and wallets will be free to permissionlessly explore that design space in a standards-driven way.
Without 3074, the mere existence of EOAs will continue to ensure that dapps build for them first (as to not exclude anyone). 3074 is a path to building better interaction patterns.

Author: thogard
Date: 2024-04-24T19:31:19.480Z

danfinlay:

This makes the assumption that any generalized interface is insecure. I think we can agree that exposing AUTH directly to strangers is insecure, but by allowing open-ended community development around wallet-dapp interfaces, we will be able to explore exactly how secure an interface can be made.


Can you elaborate on what you mean by this? I’m trying very hard not to straw man you here but I’m interpreting it to mean that not only will your company maintain a white list of which contracts can use AUTH but you’ll also maintain a white list of which dapps can access the white listed invoker contracts. I can’t think of another pattern in which you have a white listed general invoker that not all dapps have access to.

Author: danfinlay
Date: 2024-04-24T20:25:03.676Z

thogard:

Can you elaborate on what you mean by this? I’m trying very hard not to straw man you here but I’m interpreting it to mean that not only will your company maintain a white list of which contracts can use AUTH but you’ll also maintain a white list of which dapps can access the white listed invoker contracts. I can’t think of another pattern in which you have a white listed general invoker that not all dapps have access to.


I am saying that invokers enable design of new interaction patterns. I’m not suggesting and have no plans of creating a list of what dapps can connect to wallets, and I don’t know how you got there. A sample elaboration can be found in the permissions standard doc I linked to.

Author: thogard
Date: 2024-04-24T21:08:04.254Z

danfinlay:

I am saying that invokers enable design of new interaction patterns. I’m not suggesting and have no plans of creating a list of what dapps can connect to wallets, and I don’t know how you got there. A sample elaboration can be found in the permissions standard doc I linked to.


Ah - apologies for the ambiguity of terminology. I believe the confusion is because when you say dapp you’re referring to the frontend, whereas when I say dapp I’m referring to the smart contract.
In my previous post, I described a useful app-contract-embedded invoker pattern:

A lending protocol similar to AAVE, but with a ‘hook’ that executes prior to the liquidation of a borrower’s collateral. The hook would use 3074 to deposit more of the user’s collateral tokens into the lending protocol to avoid the liquidation.

But, as mentioned above, if this app’s smart contract handled the AUTHCALL via a generalized invoker it would look malicious:



 thogard:


The invoker would be called by a contract (the invoker is not used as an entrypoint)
The contract would then transfer some of one of the user’s tokens to itself
It would then transfer some of another one of the user’s tokens to itself
And it would keep doing this until the user is fully drained.



That lead me to conclude that a sufficiently generalized invoker is insecure, as using it would be indistinguishable from an attack.
You disagreed:



 danfinlay:

This makes the assumption that any generalized interface is insecure. I think we can agree that exposing AUTH directly to strangers is insecure


So my interpretation of your comments came from:

Strangers can use a generalized invoker to do anything that they could do with an app-specific invoker.
You do think a generalized invoker can be secure
You don’t want to expose AUTH directly to strangers
Ergo, you plan to limit which app’s smart contracts can integrate with your generalized invoker

If that interpretation is incorrect, can you help me reconcile why that’s the case? It would help me understand more clearly if you used the specific app/invoker pattern I’ve described here - examples always help add context and clear up ambiguous terminology.

Author: danfinlay
Date: 2024-04-24T21:51:24.959Z

thogard:

You do think a generalized invoker can be secure


I think the core of this discontinuity is here. I do think so, or maybe I hope so, but I haven’t seen proof that this is true for all people yet. So I build with the goal of allowing us to build out that security, even if we don’t have it yet, in a way that allows staying safe along the way.
As I said to you before, I eagerly welcome any pattern that would make any permission granted safe, but until then, starting from “no invoker”, and gradually expanding and improving the approval/integration process, I think we can make meaningful progress expanding from “cannot do any invoker things” quickly to “can do most desired invoker things”, and we can then gradually chip at “can do any invoker things”.
Like I said to you then, at MetaMask we are also building a wallet plugin system called Snaps, and we’ve been on a basically equivalent journey to make that system permissionless (should be no surprise, since 3074 is basically an onchain EOA plugin system). In fact, I personally intend to use the Snaps system to prototype invoker/sca interfaces that aren’t standards-ready because it’s the easiest way to do it, and any developer with a copy of MetaMask Flask can already do the same, and build their own invoker enabled wallet.
So today, the “developer edition” lets you do whatever, and the consumer edition doesn’t. It’s a pretty common pattern, but again, I’m eagerly searching for better/safer ways of verifying user consent, I’d love to dissolve the distinction and have one safe pattern.

Author: thogard
Date: 2024-04-24T22:06:46.117Z

danfinlay:

I think the core of this discontinuity is here. I do think so, or maybe I hope so, but I haven’t seen proof that this is true for all people yet. So I build with the goal of allowing us to build out that security, even if we don’t have it yet, in a way that allows staying safe along the way.


OK I think I see the distinction. Your current plan is not for metamask to whitelist which apps can use a metamask generalized invoker, it’s for metamask to build an extremely limited invoker that all apps can use and then gradually expand that invoker’s feature set while maintaining the ‘all apps can use our invoker’ mindset.  Is that correct?

Author: cejay
Date: 2024-04-25T11:08:08.176Z

As an “AA” practitioner, I’d like to share my perspective.
Firstly, if " full account abstraction" is the ultimate goal, then we should assess the EIP-3074 standard based on whether it contributes to achieving this goal:
 Adoption of EIP-3074 would incentivize DApp developers to immediately start supporting features like batch transactions and gas sponsorship. (Minor benefit)
 It would encourage EOA wallets to immediately support some features of contract wallets, allowing users to immediately benefit from partial account abstraction, thereby aiding the transition to full account abstraction. (Moderate benefit)
 EIP-3074 may divert the community’s attention away from full account abstraction. (Moderate issue)
 The scattered Invoker in EIP-3074 could potentially increase systemic security risks, requiring wallets to make corresponding security improvements. This may necessitate a series of ERCs to enhance security, such as standards for Invoker signatures and wallet interactions. (Severe issue)
 Currently, there’s no smooth upgrade path from EIP-3074 to full account abstraction. (Severe issue)
Based on these points, while I do believe EIP-3074 may be exciting for current users, I hope we can discuss clearly how to progress towards the goal of full account abstraction before its implementation.
Thanks

Author: marc
Date: 2024-04-25T13:15:15.680Z

danfinlay:

This unseats the EOA interface as the “maximum supportable interface” for dapps to rely on, and opens the space for SCAs to participate competitively.


I agree that this holds true for certain AA features, such as batch transactions, where ERC- 5792 can now be applied and used on a dapp interface with any account. I agree as well for sponsored gas, where a dapp no longer presupposes that an account must have a balance of ETH to transact.
However, this isn’t true for the two examples I mentioned above. Support for EIP-1271 will continue to lack and the assumption that an account can exists on every network will continue exist.
So EIP-3074 can partially help, but at what cost?
When EIP-3074 was first introduced, there was no unified consensus on how we will reach full Account Abstraction. ERC-4337 hadn’t yet been introduced, and this proposal was aimed to enhance the user experience for EOAs in the short term as we figure out a good way for full AA. I tackles some important promises of account abstraction, without fully supporting it.
Fast forward to today, we’ve seen monumental shift in both the development of SCAs and the mindset of developers. We actually have hope for achieving full account abstraction. Wallets that already support EOAs can now offer full SCA functionality without requiring consensus changes, and with a clear path to native account abstraction for networks that opt to implement RIP-7560. Trust Wallet, for example, is already offering users full AA functionality.
So, the question arises: Is EIP-3074 worth the risk of initiating a parallel fragmentation among both users and developers? Are we willing to prolong the use of EOAs indefinitely with only execution abstraction? And perhaps most importantly, should we risk Ethereum’s goal of full account abstraction in exchange for short-term gains in current EOA functionality?

Author: danfinlay
Date: 2024-04-25T19:08:35.696Z

I agree



 ankurdubey521:

Let’s say we modify the AUTH message to the following:
keccak256(MAGIC || chainId || managementEoa || managementEoaNonce || invokerAddress || commit)


I can see this being a pretty simple improvement that alleviates some of the risks of inadvertent AUTH revocation that could weaken the reliability/“hardness” of commitments that are made using an AUTH message, like what @haydenadams raised.
It sounds like it wouldn’t affect implementation complexity much since it reuses existing state, so I’d suspect if authors agree, that implementers would follow. For that reason, I’m supportive of this change.
I understand this will be raised on ACDs tomorrow, and welcome anyone to name me as a supporter.

Author: danfinlay
Date: 2024-04-25T19:17:16.861Z

marc:

Is EIP-3074 worth the risk of initiating a parallel fragmentation among both users and developers?


It won’t initiate that fragmentation. The fragmentation already clearly exists, as you’ve documented very well.



 marc:

Are we willing to prolong the use of EOAs indefinitely with only execution abstraction?


If there is ever a design for fully converting EOAs to SCAs, I think we’d all support it! I think what we’re seeing with 3074 (and the minor tweaks that can be made on it to somewhat increase the hardness of the delegation) is that we will never be able to perfectly revoke the meaning of a secret number that someone knows out there. Someone else might honor it.
What I’m saying is: While I would never prolong the usage of EOAs, I am not certain that they can be made anything less than semi-immortal, and so I suggest we augment them as well as we can, while not holding back how well we augment the journey for new users.



 marc:

perhaps most importantly, should we risk Ethereum’s goal of full account abstraction in exchange for short-term gains in current EOA functionality?


I’ve seen this either-or/zero-sum argument again and again in the anti-3074 debate, but I haven’t seen any substance to these claims. Obviously everything has to be weighed beside other things, but 3074 is an incredibly simple change to implement, so I really don’t think it should be treated as blocked by titanically more complicated moon-shots.

Author: MrSilly
Date: 2024-04-27T13:18:37.780Z

MicahZoltu:

I would expect a wallet developer looking to add support for EIP-3074 will understand the implications. I would not expect an end-user to understand the implication


I agree that could work out OK if we only have trustworthy invokers. In the real world shouldn’t we expect more grey area? Doesn’t the user need some mental representation of EIP 3074 to understand what a wallet is proposing? We have that problem even with the simpler EOA model. A family member of mine let a scammer create a wallet for them, not realising they’d be able to steal the funds deposited months later.

Author: MrSilly
Date: 2024-04-27T13:23:57.227Z

danfinlay:

It won’t initiate that fragmentation. The fragmentation already clearly exists, as you’ve documented very well.


That seems like splitting hairs. If we generally agree fragmentation is bad, the question should be how to minimise it, not how much worse we can make it. Isn’t there a meaningful difference between fragmentation at the alternative implementation level and fragmentation of the whole stack?

Author: MicahZoltu
Date: 2024-04-27T17:04:06.615Z

MrSilly:

I agree that could work out OK if we only have trustworthy invokers. In the real world shouldn’t we expect more grey area? Doesn’t the user need some mental representation of EIP 3074 to understand what a wallet is proposing? We have that problem even with the simpler EOA model. A family member of mine let a scammer create a wallet for them, not realising they’d be able to steal the funds deposited months later.


We definitely should not assume everyone who writes invokers are trustworthy!  The argument I’m making here is that the threat surface area of wallets doesn’t get worse with invokers.  It is a primitive that, like any primitive, can be used for good or bad.  Wallets already have 100% control over user funds, and them being able to authorize invokers means that they can enable features for their users that don’t currently exist and delegate a very controlled set of responsibilities to a contract.  The act of enabling an invoker must be carefully controlled by wallets (the current defense for users against bad actors).

Author: danfinlay
Date: 2024-04-28T18:39:06.742Z

MrSilly:

the question should be how to minimise it, not how much worse we can make it.


I obviously wasn’t suggesting we aim to make it worse, and in the post you quoted, suggested a way to remedy it via 3074. This looks like bad faith arguing to me.

Author: SamWilsn
Date: 2024-05-05T02:51:07.874Z

On another note, someone raised a few interesting contracts that may be affected by this EIP:

Two rather recent ones from the last few months I see on grep.app is scroll/contracts/src/L1/gateways/EnforcedTxGateway.sol at develop · scroll-tech/scroll · GitHub and pancake-smart-contracts/projects/vecake/contracts/test/VECakeTest.sol at master · pancakeswap/pancake-smart-contracts · GitHub.
Another from within the last year is contract-core/contracts/governance/ChessSubSchedule.sol at main · tranchess/contract-core · GitHub which may very well be an exploit waiting to happen with this EIP.
There is also curve-dao-contracts/contracts/PoolProxy.vy at master · curvefi/curve-dao-contracts · GitHub and a couple others sprinkled throughout the repo

Author: MicahZoltu
Date: 2024-05-05T04:14:11.071Z

Someone (but only one person) should create an issue on each of those repositories letting them know that those are each potentially critical security vulnerabilities.  As long as the EVM continues to be mutable, there is no long term guarantee that msg.sender == tx.origin means first call frame.

Author: marc
Date: 2024-05-06T15:53:47.018Z

danfinlay:

It won’t initiate that fragmentation. The fragmentation already clearly exists, as you’ve documented very well.


The fragmentation I’ve outlined primarily relates to dapps rather than wallets. What I mean by “initiate fragmentation” is that 3074 will set in motion a parallel track of smart wallet development that does not seamlessly align with the roadmap for full account abstraction.



 danfinlay:

While I would never prolong the usage of EOAs, I am not certain that they can be made anything less than semi-immortal, and so I suggest we augment them as well as we can, while not holding back how well we augment the journey for new users.


I acknowledge the importance of additional functionalities to EOAs. Infinite approval scams have hunted the ecosystem for too long, and batch transactions is the solution. Gas sponsorship is crucial for usability beyond today’s users. I do agree that upgrading EOAs isn’t a trivial task, as you’ve rightly pointed out. It poses risks because someone will inevitably honor the key.
Although 3074 seems straightforward to implement, its implications on wallet ecosystem development are profound if integrated into L1. It further encourages EOA development. It slows down users and developers from transitioning to to a better model where it protects users with key rotation and different signature schemes.
EOAs will eventually be deprecated, not by choice, but due to quantum advancement. Further enshrinement encourages not only its continued spread and adoption, but also it’s gets us away further from the end goal of full native AA.

Author: SamWilsn
Date: 2024-05-06T16:28:11.398Z

marc:

EOAs will eventually be decrypted, not by choice, but due to quantum advancement. Further enshrinement encourages not only its continued spread and adoption, but also it’s gets us away further from the end goal of full native AA.


Not to sound too much like a broken record, but EIP-3074 was designed to allow changing the signature format/algorithm. Whatever approach is adopted by EOA and ecrecover signatures, EIP-3074 can adopt too.

Author: SamWilsn
Date: 2024-05-06T16:29:57.121Z

A post by @yoavw: Implications of EIP-3074 inclusion - HackMD
My reply: Sam's Reply to Implications of EIP-3074 inclusion - HackMD

Author: yoavw
Date: 2024-05-06T19:35:11.765Z

My reply to Sam’s reply: Yoav's Reply to Sam’s Reply to Implications of EIP-3074 inclusion - HackMD

Author: jeffchen006
Date: 2024-06-05T19:26:08.436Z

Can we check both codesize at that address and tx.origin vs. msg.sender to determine if msg.sender is an EOA?
For example,
uint256 codeSize;
assembly {
    codeSize := extcodesize(msg.sender)
}
require(msg.sender == tx.origin && codeSize == 0, "not an EOA")

I believe EIP-3074 can possibly bypass the first check msg.sender == tx.origin, contracts have zero codesize can bypass the second check codeSize == 0, but they can never be bypassed together? You have to authorize an existing contract to AUTHCALL, right?
Correct me if I made a mistake, thanks.

Author: SamWilsn
Date: 2024-06-10T21:25:21.342Z

Just FYI, EIP-3074 has mostly been replaced by EIP-7702.
To answer your question directly:
msg.sender will be the EOA, so codeSize will be zero.

Author: adietrichs
Date: 2025-05-07T08:21:40.734Z

gm to all 3074 fans out there, what a beautiful day today