EIP7702

EIP7702 允许扩展 EOA 地。

  • 升级后的核心有点由于支持批量交易,允许 EOA 地址像合约一样执行底层 call
  • 允许 gas 代付,通过签名校验允许任意地址提交自身交易(只需要给自己转账,附加上 calldata
  • 由于升级成合约,可以扩展更加灵活性的功能

EOA 地址扩展的合约 Code(0xef0100 || address),因为根据EIP3541不允许部署 0xef 开头的合约。

GetCodes

0xef0100 开头的 bytecodes 表示当前地址是扩展的 EOA 地址

func AccountCodes(address common.Address) string {
	res, err := client.CodeAt(context.Background(), address, nil)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("codes: %s", hexutil.Encode(res))
	//0xef010080296ff8d1ed46f8e3c7992664d13b833504c2bb
	return hexutil.Encode(res)
}

因此,通过下面代码能够判断出当前地址是否是扩展的 EOA 地址

bytes3 internal constant _DELEGATION_PREFIX = 0xef0100;
function isEOA(address target) internal view returns (bool) {
    bytes memory code = target.code;
    // Add here a comment addressing the normal disclaimers around
    // construction-time issues and zero-length contracts.
    return (code.length == 0 || bytes3(code) == _DELEGATION_PREFIX);
}

/**
 * @dev Returns the address of the delegate if `account` as an EIP-7702 delegation setup, or address(0) otherwise.
     */
function fetchDelegate(address account) internal view returns (address) {
    bytes23 delegation = bytes23(account.code);
    return bytes3(delegation) == EIP7702_PREFIX ? address(bytes20(delegation << 24)) : address(0);
}

合约验签:

abstract contract SignerERC7702 is AbstractSigner {
    /**
     * @dev Validates the signature using the EOA's address (i.e. `address(this)`).
     */
    function _rawSignatureValidation(
        bytes32 hash,
        bytes calldata signature
    ) internal view virtual override returns (bool) {
        (address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(hash, signature);
        return address(this) == recovered && err == ECDSA.RecoverError.NoError;
    }
}

OKX WalletCore

OKX 钱包升级升级 7702 后,和该钱包交互只需要执行 calldata 不为空的 transfer 交易, calldata 自动匹配代理合约的函数执行功能函数

代理合约主要存在三种类型交易:

executeFromSelf

只能 EOA 地址自己执行,在 transfer_To_Self 交易的同时附加上 calldata,底层逻辑会自动匹配合约函数执行

    modifier onlySelf() {
        if (msg.sender != address(this)) revert Errors.NotFromSelf();
        _;
    }
    
    function executeFromSelf(Call[] calldata calls) external onlySelf {
        _batchCall(calls);
    }

executeWithValidator

任意地址拿着有效签名都可以发送交易,其中签名的 Validator 可以是 EOA 本身或者是 EOA 指定的白名单地址

这个函数就允许外部地址代付 Gas,任意外部地址只要拿着有效签名就能执行升级 7702_EOA 钱包的批量操作

升级后的 EOA 地址会成为一个 Storage 合约的 Owner

  • Storage 内部存储自增的 nonce 保证签名单次使用
  • Storage 中能够管理 Validator 白名单

在发送交易时,根据 Validator 类型有不同的验签流程:

  • Validator == address(1),
    • 表示 ValidatorEOA Self,要求 signer == EOA
  • Validator 是其余白名单地址时,要求签名满足 Validator 合约的内部逻辑
    • try IValidator(validator).validate(typedDataHash, validationData)
    • 如果 Validator 被设置成纯 EOA 地址的话,底层 call 调用将永远会返回 true,也就是将会绕过签名校验的流程
    • 这就需要 EOA-7702 谨慎设置 validator 白名单
    function executeWithValidator(
        Call[] calldata calls,
        address validator,
        bytes calldata validationData
    ) external onlyValidator(calls, validator, validationData) {
        _batchCall(calls);
    }

executeFromExecutor

executeWithValidator 基础功能上继续扩展数据结构,增加 Session 结构体限制:

struct Session {
    uint256 id;
    address executor;
    address validator;
    uint256 validUntil;
    uint256 validAfter;
    bytes preHook;
    bytes postHook;
    bytes signature;
}
  • 限制交易只能由 Executor 执行
  • 整个 Session 结构和批量转账数据必须通过 Validator 的验签流程
  • 交易还能设置有效期、Hook 功能校验
    function validateSession(Session calldata session) public view {
        // Check executor authorization
        if (msg.sender != session.executor) revert Errors.InvalidExecutor();

        // Check time bounds
        if (
            session.validAfter > block.timestamp ||
            block.timestamp > session.validUntil
        ) revert Errors.InvalidSession();

        // Check invalidSessionId & validValidator in storage
        getMainStorage().validateSession(session.id, session.validator);

        // Validate signature
        bytes32 hash = getSessionTypedHash(session);
        bool isValid = WalletCoreLib.validate(
            session.validator,
            hash,
            session.signature
        );
        if (!isValid) revert Errors.InvalidSignature();
    }

Preference

https://github.com/okx/wallet-core

https://ethereum.org/roadmap/pectra/7702

https://eips.ethereum.org/EIPS/eip-7702

https://etherscan.io/tx/0xebc6f503d3c7cf9560308c8efef69a6c4a993a29224d7a4a4f13ca98d6ae0621

https://www.certik.com/zh-CN/resources/blog/pectras-eip-7702-redefining-trust-assumptions-of-externally-owned-accounts