Ethereum is about to welcome the Pectra upgrade: an in-depth discussion on EIP-7702 and best practices.

CN
PANews
Follow
5 days ago

Author: Kong

Editor: Sherry

Introduction

Ethereum is about to welcome the Pectra upgrade, which is undoubtedly a significant update, introducing numerous important Ethereum Improvement Proposals (EIPs). Among them, EIP-7702 brings transformative changes to Ethereum External Accounts (EOA). This proposal blurs the lines between EOA and Contract Accounts (CA), marking a key step towards native account abstraction following EIP-4337, and bringing a new interaction model to the Ethereum ecosystem.

Currently, Pectra has been deployed on the test network and is expected to go live on the mainnet soon. This article will delve into the implementation mechanism of EIP-7702, explore the opportunities and challenges it may bring, and provide practical operational guidelines for different participants.

Protocol Analysis

Overview

EIP-7702 introduces a brand new transaction type that allows EOA to specify a smart contract address, thereby setting code for it. This enables EOA to execute code like a smart contract while retaining the ability to initiate transactions. This feature endows EOA with programmability and composability, allowing users to implement functionalities such as social recovery, permission control, multi-signature management, zk verification, subscription payments, transaction sponsorship, and transaction batching within EOA. Notably, EIP-7702 is fully compatible with the smart contract wallets enabled by EIP-4337, and the seamless integration of the two greatly simplifies the development and application process of new features.

The specific implementation of EIP-7702 introduces a transaction type called SETCODETX_TYPE (0x04), with the following data structure defined:

rlp([chainid, nonce, maxpriorityfeepergas, maxfeepergas, gaslimit, destination, value, data, accesslist, authorizationlist, signatureyparity, signaturer, signature_s])

The authorization_list field is defined as:

authorizationlist = [[chainid, address, nonce, y_parity, r, s], …]

In the new transaction structure, all fields except for authorization_list follow the same semantics as EIP-4844. This field is of list type and can contain multiple authorization entries, where each authorization entry includes:

  • chain_id field indicates the chain on which this authorization is effective
  • address field indicates the target address of the delegation
  • nonce field must match the current nonce of the authorized account
  • y_parity, r, s fields are the signature data signed by the authorized account

The authorization_list field within a transaction can contain authorization entries signed by different authorized accounts (EOA), meaning the transaction initiator can differ from the authorizer, allowing for gas payment on behalf of the authorizer.

Implementation

When the authorizer signs the authorization data, they first need to RLP encode chain_id, address, and nonce. Then, the encoded data is hashed with the MAGIC number using keccak256 to obtain the data to be signed[1]. Finally, the authorizer uses their private key to sign the hashed data, resulting in y_parity, r, and s data. Here, MAGIC (0x05) is used as a domain separator to ensure that the results of different types of signatures do not conflict.

// Go-ethereum/core/types/tx_setcode.go#L109-L113
func (a *SetCodeAuthorization) sigHash() common.Hash {
    return prefixedRlpHash(0x05, \[\]any{ a.ChainID, a.Address, a.Nonce, })
}

It is important to note that when the chain_id authorized by the authorizer is 0, it indicates that the authorizer allows[2] the authorization to be replayed on all EVM-compatible chains that support EIP-7702 (provided that the nonce also matches).

// Go-ethereum/core/state_transition.go#L562
if !auth.ChainID.IsZero() && auth.ChainID.CmpBig(st.evm.ChainConfig().ChainID) != 0 {
    return authority, ErrAuthorizationWrongChainID
}

After the authorizer signs the authorization data, the transaction initiator will aggregate it in the authorization_list field for signing and broadcast the transaction via RPC. Before the transaction is included in a block for execution, the Proposer will first perform a pre-check[3], which includes a mandatory check on the to address to ensure that this transaction is not a contract creation transaction. In other words, when sending a transaction of type EIP-7702, the to address cannot be empty[4].

// Go-ethereum/core/state_transition.go#L388-L390
if msg.To == nil {
    return fmt.Errorf("%w (sender %v)", ErrSetCodeTxCreate, msg.From)
}

Additionally, such transactions will strictly require that the authorization_list field must contain at least one authorization entry. If multiple authorization entries are signed by the same authorizer, only the last authorization entry will take effect.

// Go-ethereum/core/state_transition.go#L391-L393
if len(msg.SetCodeAuthorizations) == 0 {
    return fmt.Errorf("%w (sender %v)", ErrEmptyAuthList, msg.From)
}

Subsequently, during the transaction execution process, the node will first increment the nonce value of the transaction initiator, and then apply the applyAuthorization operation for each authorization entry in the authorization_list. In the applyAuthorization operation, the node will first check the nonce of the authorizer and then increment the authorizer's nonce. This means that if the transaction initiator and the authorizer are the same user (EOA), the nonce value should be incremented by 1 when signing the authorization transaction.

// Go-ethereum/core/state_transition.go#L489-L497
func (st *stateTransition) execute() (\*ExecutionResult, error) {
    ...
    st.state.SetNonce(msg.From, st.state.GetNonce(msg.From)+1, tracing.NonceChangeEoACall)

    // Apply EIP-7702 authorizations.
    if msg.SetCodeAuthorizations != nil {
        for _, auth := range msg.SetCodeAuthorizations {
            // Note errors are ignored, we simply skip invalid authorizations here.
            st.applyAuthorization(&auth)
        }
    }
    ...
}

// Go-ethereum/core/state_transition.go#L604
func (st *stateTransition) applyAuthorization(auth \*types.SetCodeAuthorization) error {
    authority, err := st.validateAuthorization(auth)
    ...
    st.state.SetNonce(authority, auth.Nonce+1, tracing.NonceChangeAuthorization)
    ...
}

// Go-ethereum/core/state_transition.go#L566
func (st *stateTransition) validateAuthorization(auth \*types.SetCodeAuthorization) (authority common.Address, err error) {
    ...
    if auth.Nonce+1 != auth.Nonce {
        return authority, ErrAuthorizationNonceOverflow
    }
    ...
}

When the node applies a specific authorization entry, if any errors are encountered, that authorization entry will be skipped, and the transaction will not fail; other authorization entries will continue to be applied, ensuring that there is no DoS risk in batch authorization scenarios.

// Go-ethereum/core/state_transition.go#L494
for _, auth := range msg.SetCodeAuthorizations {
    // Note errors are ignored, we simply skip invalid authorizations here.
    st.applyAuthorization(&auth)
}

After the authorization application is completed, the code field of the authorizer's address will be set to 0xef0100 || address, where 0xef0100 is a fixed identifier, and address is the target address of the delegation. Due to the restrictions of EIP-3541, users cannot deploy contract code starting with the 0xef byte through conventional means, ensuring that such identifiers can only be deployed by transactions of type SETCODETX_TYPE (0x04).

// Go-ethereum/core/state_transition.go#L612
st.state.SetCode(authority, types.AddressToDelegation(auth.Address))

// Go-ethereum/core/types/tx_setcode.go#L45
var DelegationPrefix = \[\]byte{0xef, 0x01, 0x00}

func AddressToDelegation(addr common.Address) \[\]byte { return append(DelegationPrefix, addr.Bytes()...) }

After the authorization is completed, if the authorizer wants to remove the authorization, they simply need to set the target delegated address to the 0 address.

The new transaction type introduced by EIP-7702 allows the authorizer (EOA) to execute code like a smart contract while retaining the ability to initiate transactions. Compared to EIP-4337, this provides users with an experience closer to native account abstraction (Native AA), significantly lowering the usage threshold for users.

Best Practices

Although EIP-7702 injects new vitality into the Ethereum ecosystem, new application scenarios also bring new risks. Here are aspects that ecosystem participants need to be vigilant about during practice:

Private Key Storage

Even though EOA can utilize built-in social recovery methods in smart contracts to address issues of fund loss due to private key loss after delegation, it still cannot avoid the risk of EOA private key leakage. It is important to clarify that after executing delegation, the EOA private key still holds the highest control over the account, and possessing the private key allows one to freely dispose of the assets in the account. Users or wallet service providers, after completing the delegation for EOA, cannot completely eliminate the risk of private key leakage, especially in scenarios where supply chain attack risks exist.

For users, when using accounts after delegation, they should still prioritize private key protection and always remember: Not your keys, not your coins.

Multi-Chain Replay

When users sign delegation authorizations, they can choose the chain on which the delegation can take effect through chainId. Of course, users can also choose to use chainId as 0 for delegation, allowing the delegation to be replayed across multiple chains, enabling users to delegate with a single signature across multiple chains. However, it is important to note that the same contract address on multiple chains may have different implementation codes.

For wallet service providers, when users delegate, they should check whether the effective chain of the delegation matches the currently connected network and remind users of the risks that may arise from signing delegations with chainId as 0.

Users should also be aware that the same contract address on different chains does not always have the same contract code and should understand the target of the delegation clearly.

Unable to Initialize

Most mainstream smart contract wallets currently adopt a proxy model. When deploying the wallet proxy, it calls the initialization function of the implementation contract through DELEGATECALL, achieving atomic operations for wallet initialization and proxy wallet deployment, thus avoiding the issue of being initialized first. However, when users use EIP-7702 for delegation, it will only update the code field of their address and cannot initialize by calling the delegated address. This means that EIP-7702 cannot call the initialization function in the contract deployment transaction like common ERC-1967 proxy contracts for wallet initialization.

For developers, when combining EIP-7702 with existing EIP-4337 wallets, they should ensure to perform permission checks during the wallet initialization operation (e.g., by recovering the signature address through ecrecover for permission checks) to avoid the risk of wallet initialization being preempted.

Storage Management

When users utilize the EIP-7702 delegation feature, they may need to re-delegate to different contract addresses due to changes in functional requirements, wallet upgrades, etc. However, the storage structures of different contracts may differ (for example, the slot0 slot of different contracts may represent different types of data), and in the case of re-delegation, there is a possibility that the new contract may inadvertently reuse data from the old contract, leading to adverse consequences such as account locking and fund loss.

For users, they should handle re-delegation situations with caution.

For developers, during the development process, they should follow the Namespace Formula proposed by ERC-7201, allocating variables to designated independent storage locations to mitigate the risk of storage conflicts. Additionally, ERC-7779 (draft) provides a standard process for re-delegation specifically for EIP-7702: including using ERC-7201 to prevent storage conflicts, verifying storage compatibility before re-delegation, and calling the old delegation interface to clean up old data in storage.

Fake Recharge

After delegation, EOA can also be used as a smart contract, which means centralized exchanges (CEX) may face the situation of widespread smart contract recharges.

CEX should check the status of each recharge transaction through trace to prevent the risk of fake recharges from smart contracts.

Account Conversion

After implementing EIP-7702 delegation, users' account types can freely convert between EOA and SC, allowing accounts to both initiate transactions and be called. This means that when an account calls itself and performs external calls, its msg.sender will also be tx.origin, which breaks some security assumptions that limit project participation to EOA only.

For contract developers, assuming that tx.origin is always EOA will no longer be feasible. Similarly, using msg.sender == tx.origin checks to defend against reentrancy attacks will also fail.

Developers should assume that future participants may all be smart contracts during the development process.

Contract Compatibility

Existing ERC-721 and ERC-777 tokens have hook functionality when transferring to contracts, meaning that the recipient must implement the corresponding callback function to successfully receive tokens.

For developers, the target contract of the user's delegation should implement the corresponding callback function to ensure compatibility with mainstream tokens.

Phishing Checks

After implementing EIP-7702 delegation, the assets in the user's account may be controlled by smart contracts. If the user delegates their account to a malicious contract, it will become easy for attackers to steal funds.

For wallet service providers, it is particularly important to quickly support EIP-7702 type transactions, and when users perform delegation signatures, they should prominently display the target contract of the delegation to mitigate the risk of users falling victim to phishing attacks.

Additionally, conducting deeper automated analysis of the target contract for account delegation (open-source checks, permission checks, etc.) can better help users avoid such risks.

Conclusion

This article discusses the upcoming Pectra upgrade in Ethereum, focusing on the EIP-7702 proposal. EIP-7702 introduces a new transaction type that endows EOA with programmability and composability, blurring the lines between EOA and contract accounts. As there is currently no battle-tested standard for smart contracts compatible with EIP-7702, various ecosystem participants, such as users, wallet service providers, developers, and CEX, face numerous challenges and opportunities in practical applications. The best practices outlined in this article cannot cover all potential risks but are still worth referencing and applying in actual operations.

Examples

[Set EOA Account Code]

https://holesky.etherscan.io/tx/0x29252bf527155a29fc0df3a2eb7f5259564f5ee7a15792ba4e2ca59318080182

[Unset EOA Account Code]

https://holesky.etherscan.io/tx/0xd410d2d2a2ad19dc82a19435faa9c19279fa5b96985988daad5d40d1a8ee2269

Related Links

[1] https://github.com/ethereum/go-ethereum/blob/7fed9584b5426be5db6d7b0198acdec6515d9c81/core/types/tx_setcode.go#L109-L113

[2] https://github.com/ethereum/go-ethereum/blob/7fed9584b5426be5db6d7b0198acdec6515d9c81/core/state_transition.go#L562

[3] https://github.com/ethereum/go-ethereum/blob/7fed9584b5426be5db6d7b0198acdec6515d9c81/core/state_transition.go#L304

[4] https://github.com/ethereum/go-ethereum/blob/7fed9584b5426be5db6d7b0198acdec6515d9c81/core/state_transition.go#L388-L390

References

[EIP-7702] https://eips.ethereum.org/EIPS/eip-7702

[EIP-4844] https://eips.ethereum.org/EIPS/eip-4844

[Go-ethereum] https://github.com/ethereum/go-ethereum/tree/7fed9584b5426be5db6d7b0198acdec6515d9c81

[EIP-3541] https://eips.ethereum.org/EIPS/eip-3541#backwards-compatibility

[Cobo: EIP-7702 Practical Guide]

https://mp.weixin.qq.com/s/ojh9uLw-sJNArQe-U73lHQ

[Viem] https://viem.sh/experimental/eip7702/signAuthorization

[ERC-7210] https://eips.ethereum.org/EIPS/eip-7201

[ERC-7779] https://eips.ethereum.org/EIPS/eip-7779

免责声明:本文章仅代表作者个人观点,不代表本平台的立场和观点。本文章仅供信息分享,不构成对任何人的任何投资建议。用户与作者之间的任何争议,与本平台无关。如网页中刊载的文章或图片涉及侵权,请提供相关的权利证明和身份证明发送邮件到support@aicoin.com,本平台相关工作人员将会进行核查。

ad
币安:注册返10%、领$600
链接:https://accounts.suitechsui.blue/zh-CN/register?ref=FRV6ZPAF&return_to=aHR0cHM6Ly93d3cuc3VpdGVjaHN1aS5hY2FkZW15L3poLUNOL2pvaW4_cmVmPUZSVjZaUEFG
Ad
Share To
APP

X

Telegram

Facebook

Reddit

CopyLink