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
.
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
.
Thanks! Howâs this: Update eip-3074.md: explain `nonce` and `chainId` in rationale by SamWilsn ¡ Pull Request #8428 ¡ ethereum/EIPs ¡ GitHub
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
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.
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?
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
Determining if
msg.sender
is an EOA withouttx.origin
is difficult (if not impossible.)
Canât you also check the codesize at that address?
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
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:
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.AUTH
for an (address, signature)
pair which has already been called in this calling context is very cheap (<100 gas).(address, signature)
pair. (This is already enabled in the current spec.)ADDRESS
. I donât think it matters much.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).
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!
Permanent-until-revoked, yes. As long as you donât send a regular transaction from the EOA, authorizations remain valid forever.
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.
No, because contracts have zero codesize while running the initcode (aka constructor.)
I already replied in a chat, but repeating here for visibility:
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?
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.
Changing the behaviour of *call functions makes this really weird:
function foo() public {
this.someErc20.approve(...)
}
function sudo(...) public {
assembly {
auth(...)
}
this.foo();
}
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?
Oops, edited. Thanks!
As an auditor, you now have to trace the entire possible callstack to ensure that someErc20.approve
is never called while authorized.
Iâd say the same as @charles-cooper
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
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.