-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update EIP-7702: Add system contract for revocations #8631
Conversation
File
|
Interesting direction with account based revocability!
|
I don't have a strong opinion as to where the revocations should be stored, as long as smart contract account code is not able to undo a revocation. It would be nice to put them somewhere that didn't increase the cost of using EIP-7702 as much, but I don't know if that's possible. Are namespaced storage slots something that already exists in clients? What would be the mechanism for an EOA to revoke an address in that design?
I find it strange that the validation would be postponed until during execution. It feels like a more significant change to the EVM. I think there is already a deterrent to send revoked signatures because each signature carries a cost, and in the case of revoked signatures it will not be possible to collect payment from the account. |
| ------------------------- | ------ | | ||
| `SET_CODE_TX_TYPE` | `0x04` | | ||
| `MAGIC` | `0x05` | | ||
| `PER_AUTH_BASE_COST` | `4600` | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically the cost increase should include the access to AUTH_REVOCATION_ADDRESS
(2600 while cold, and 100 on subsequent authorizations in the same transaction) rather than just the cold SLOAD. But since it's a singleton that won't be loaded from the db more than once per block, I guess it's safe to waive it and only consider the cold SLOAD.
push1 0x20 | ||
mstore | ||
|
||
push1 0x01 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand correctly it can only be set to 1, so once an authorization to a contract has been revoked it can never be used again by the same EOA. E.g. switching from impl1
to impl2
and then back to impl1
is impossible.
Would it make sense to make it an arg so that users can reset it to 0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the current version of the proposal the revocation can be made by account code (so not necessarily made by the EOA directly). Since we are working under a threat model where this code can become malicious, I thought it best to make revocation permanent so that a template that turns malicious is not able to undo past revocations.
It seems easier to reason about the security properties in this way.
2. Verify the chain id is either 0 or the chain's current ID. | ||
3. Verify that the code of `authority` is empty. | ||
4. If nonce list item is length one, verify the nonce of `authority` is equal to `nonce`. | ||
4. Verify that the storage slot `keccak(authority || address)` of account `AUTH_REVOCATION_ADDRESS` is empty. (`authority` and `address` should be padded to 32 bytes each.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One downside of revoking a specific authority instead of bumping a nonce is that the user needs to know about the authority. A common flow may be that the user switches to a new wallet, which revokes all authorizations made by the old wallet. But the new wallet doesn't know anything about the old one so it doesn't know which authorities to revoke.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Just for clarity, according to the spec "authority" is the signer. For the authorized address the only term that I see other than "address" is "template" so I'll use that.)
The new wallet could scan the chain for previously published authorizations (in EIP-7702 txs) and offer the user to revoke the templates it finds that have been authorized and not revoked.
It's possible that the old wallet could have generated a signature and stored it somewhere else (a server) without ever publishing it. However, I don't think this is a particularly new attack vector, as without EIP-7702 the wallet could generate a signed transaction to steal user assets with a nonce far in the future and just wait until the right moment to abuse it. With never-revocable signatures as allowed by the current version of the EIP-7702 spec, the wallet wouldn't even have to guess a future nonce.
Part of my motivation for writing this proposal is that I believe current-nonce-revocable signatures do not address the ecosystem's needs and wallets will predominantly use never-revocable signatures. This would leave the majority of users with the worst outcome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe current-nonce-revocable signatures do not address the ecosystem's needs and wallets will predominantly use never-revocable signatures. This would leave the majority of users with the worst outcome.
I share that concern. I don't think most wallets will use fixed nonce revocation.
the new wallet could scan the chain for past authorizations published on chain
- No way to tell if all past authorizations were published on chain. E.g. maybe the old wallet signed a social recovery contract but it was never used.
- Not easy to scan since the transactions that used the auth could come from any EOA. Requires scanning all 7702 transactions from all EOAs.
However, I don't think this is a particularly new attack vector, as without EIP-7702 the wallet could generate a signed transaction with a nonce far in the future to steal user assets and just wait until the right moment to abuse it.
Right - if we're thinking about an attack by a malicious wallet. But it could be an off-chain signature for a legitimate reason, e.g. social recovery contract. When you switch to a new contract you probably also want to revoke whatever recovery contract the old wallet used.
But I agree with you that users are better off with this revocation mechanism than with fixed nonce. I just think something equivalent to maxNonce
would mitigate the issues above. With maxNonce
the new wallet can revoke all past auths, whether they were published or not. I wonder if we could do the same with a system contract like the one you're proposing. E.g. storing an authNonce
in the system contract (keccak(authNonce || address)
) and replacing the current nonce
in the authority
with authNonce
. The user can then bump authNonce
in the system contract to revoke all past auths.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it could be an off-chain signature for a legitimate reason, e.g. social recovery contract.
Yes this is true and a good use case!
I wonder if we could do the same with a system contract like the one you're proposing. E.g. storing an
authNonce
in the system contract (keccak(authNonce || address)
) and replacing the currentnonce
in theauthority
withauthNonce
. The user can then bumpauthNonce
in the system contract to revoke all past auths.
Ah, this could work too. Are you proposing to combine that with template-based revocation or to just use nonces?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, this could work too. Are you proposing to combine that with template-based revocation or to just use nonces?
We could do both but it adds complexity. The mechanism I suggested is basically the maxNonce
system, except that instead of using the account's nonce it uses a storage slot and the bumping part is implemented as EVM code.
In the future (after verkle) we can stop using the system contract and store authNonce
in the account itself along with its regular nonce
, as I think @adietrichs suggested. But then we'll need a way to bump it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we go with an independent nonce for authorizations, I think "current nonce" is a better option than "max nonce". Otherwise I don't see a good way to choose the nonce increment for an authorization or for a revocation.
With
maxNonce
the new wallet can revoke all past auths, whether they were published or not.
I.e., I don't understand how you can be sure your revoked nonce range covers everything you've signed before.
With "current nonce", revoking would be a nuclear option that gets rid of all previously signed authorizations. This is not ideal but it makes some sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My trust assumptions have changed a bit: We have to trust our wallets (not forever, but till a certain point we choose to). The same trust assumption can be applied in relation to revocations -- Every smart wallet should have option to list down the authorizations it has captured, and provide option to revoke it. Furthermore, if you use only hardware wallets to generate authorizations, hardware wallet can list/revoke the authorizations that went out, and that is considered safer.
Even if it comes down to wallets having to harvest all 7702 txs for authorizations (coming from a particular EOA account), it seems okay to me -- wallets do index data or use data providers which index data in particular ways for them, and a "get all authorizations from this account". This can then be used in the new wallet to revoke previous authorizations. The caveat is that it doesn't cover authorizations that weren't published on chain (but this is solved with hardware wallet).
I'm much more skeptical of the template ecosystem (which is regulated with wallet whitelisting, but users will ignore the wallet's warning and sign non-whitelisted templates). With templates, we're entering into the wild west of general smart contracts, of which the smart wallets are a much-scrutinized, higher-ecosystem-trust subset.
For example, If users unwittingly authorize something like an upgradeable proxy, that becomes lucrative opportunity for the template provider (by swapping underlying implementation and using authorization to execute arbitrary calls in authority context).
There's desire for having previous wallet authorizations continue to work in a new wallet (as indicated in the 7702 proxy recommendation). Also, Blanket revocation (off previous wallet) is not possible only if i) hardware wallet was not used, and ii) previous wallet maintained offchain authorizations, and iii) previous wallet has gone rogue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we go with an independent nonce for authorizations, I think "current nonce" is a better option than "max nonce". Otherwise I don't see a good way to choose the nonce increment for an authorization or for a revocation.
With
maxNonce
the new wallet can revoke all past auths, whether they were published or not.I.e., I don't understand how you can be sure your revoked nonce range covers everything you've signed before.
With "current nonce", revoking would be a nuclear option that gets rid of all previously signed authorizations. This is not ideal but it makes some sense.
Just to answer this, the proposal was to divide nonce in two parts: the lower bits represent standard EOA tx counter. While the higher bits are "current operational authentication range". Say the split is 32-32 bits. Then nonce bump (revocation, possibly done by a flag in 7702 tx itself) adds 2^32 to the current nonce. 7702 pre-execution checks if the higher bits of account's current nonce
== higher bits of authentication's nonce
. This doesn't need anyone to choose nonce increment.
For namespaced storage slot, I was referring to the discussion in solidity, to which I see you are already a part of. I agree that there should be a way for account code to not be able to edit such a namespace where revocations are stored. Perhaps edit (adding revocations is the only edit option) can be done only when EOA has no code set. For revocation, there can be a "shouldRevoke" flag in 7702 tx which revokes everything in the passed authorization list. The EVM doesn't even need to execute in a revoking 7702 tx. Adding revocations to the account storage is all it does. |
This proposes to replace optional nonce-based revocability with address-based revocability via a new system contract.
The cost per auth tuple is updated with an additional unit of
COLD_SLOAD_COST
from 2500 to 4600.