一个以太坊帐户是一个具有以太币 (ETH) 余额的实体,可以在以太坊上发送交易。 帐户可以由用户控制,也可以作为智能合约部署。
目前以太坊上有两种账户:第一种地址是外部拥有账户(EOA),通常被称为钱包账户,由私钥和公钥组成,常用的 Metamask(小狐狸)钱包就是基于 EOA 设计的,它需要自己为每一笔交易授权并支付 gas。另一种是智能合约账户,各种部署在以太坊上的 DApp 就是以智能合约的方式运行着。
但是这样的账户(地址)设计存在很多问题,一方面会阻碍 EOA 和 CA 相互实现对方能够实现的功能,组合了链上应用创新;另一方面,EOA 要求用户掌握私钥,造成了极大的用户进入门槛和安全隐患。
而账户抽象就是让 EOA(理解为metamask) 和 Contract Account(理解为dapp)可以做只有对方可以做的事,要么让 EOA 可以实现 CA 功能,要么反过来。
简而言之,账户抽象就是账户统一。
实现账户抽象(Account Abstract/AA)的钱包叫做智能合约钱包,目前可以实现如 ECDSA 以外的签名验证方式、多签管理、社会恢复、聚合签名、交易限制、隐私保护、gas 优化、gas 代付、异币 gas、应用聚合、自动收益等多种功能,长远来看有利于降低 Web3 进入门槛,并使得链上行为更加可编程。
长久以来有非常多基于 AA 的智能合约钱包的方案, Vitalik Buterin、Yoav Weiss、Kristof Gazso、Namra Patel 和 Dror Tirosh 在 2021 年通过入口点合约规范提出了 EIP-4337。
EIP-4337 是以太坊上基于 AA 的智能合约钱包最为先进的方案之一(或者没有之一),下面我将介绍 4337 的工作流、优点、缺点。
EIP-4337 完全避免共识层协议更改的帐户抽象提案。该提案没有添加新的协议特性和更改底层事务类型,而是引入了一个更高层的伪事务对象,称为 UserOperation
。用户将 UserOperation
对象发送到单独的内存池中。一类特殊的行为者被称为 Bundler(捆绑器)(要么是矿工,要么是可以通过捆绑市场向矿工发送交易的用户),他们将这些对象打包成一个交易,对一个特殊的合约进行 handleOps
调用,然后该交易就被纳入一个区块中。
做一个奇怪的比喻🎃,男孩子只能做男孩子能做的事,女孩子只能做女孩子能做的事,为了让男孩子和女孩子能做对方才能做的事,引入一个喇叭和中间人,喇叭传播信号,中间人协调执行。当男孩子需要做只能女孩子做的事,男孩子给自己的授权和具体的需求拜托中间人让女孩子来做。
初始设定,在一个 4337 钱包中,该钱包由一个 Enternal Ownered Account(EOA) 和一个 Contract Account(CA)组成。
在钱包端,当 EOA 或者任何其他签名方案(在以太坊之外的公链)发起交易时,EOA 签名生成 UserOperation
(一种伪事务类型,提供所有交易信息,包括calldata、sender, gas, maxFeePerGas, maxPriorityFee,signature, nonce等)。
钱包将 UserOperation
传到专用的 UserOperation mempool,Bundler(矿工或可以通过bundle市场向矿工发送交易的用户)可以监听该 menpool,并创建 bundle transactions,一个bundle transactions 可以包含多个 UserOperation
传到 Entry Point 合约的 handleOps
接口。
Miner 将 bundle transaction 打包出块。
Entry Point 有以下两个验证和执行的循环阶段。
在验证循环,对 handleOps
接口的调用必须为每个 UserOperation
遵循以下步骤:
5.1 CA创建。
如果没有钱包就创建一个,通过 UserOperation
中提供的 initcode
来创建。如果钱包不存在,并且 initcode
为空,或者没有在 sender
地址部署合约,该调用则失败。
5.2 验证签名。在钱包中调用 validateUserOp
,传入 UserOperation
需要的 gas 和聚合器(如果有)。让 CA (sender
)验证操作签名有效,则支付 gas。如果validateUserOp
调用失败,handleOps
必须至少跳过这个执行,并且能够完全 revert(恢复)。
5.3 检查 gas。验证钱包在 Entry Point 中的存款足够覆盖最大可能的花费。 EP 发起请求,发送 UserOperation
给 CA,CA 验证完,返回给 EP,然后 EP 继续。
执行循环,handleOps 调用必须为每个UserOperation 遵循以下步骤
5.4 CA执行。通过 UserOperation
的 calldata 来调用钱包。钱包决定如何解析 calldata。钱包的预期工作流是,钱包自己有一个 execute
函数解析剩余的 calldata ,就像钱包应该发起的一次或多次系列调用(make a series of one or more),然后执行逻辑。
5.5 在接受一个 UserOperation
之前,捆绑器应该使用 RPC 方式来本地调用入口点的 simulateValidation
函数,来验证签名是正确的并且操作已经付费。一个节点/捆绑器应该跳过(或者不添加到内存池)验证失败的 UserOperation
。
非共识。EIP-4337 可在无需更新以太坊核心协议的情况下实现较大程度的账户抽象,推进难度相对 EIP-2938、EIP-3074 等共识提案更低。
可升级。钱包可更改自己的 public keys,如果使用了代理调用,则可升级整体代码。
去中心。没有一个实体可以影响整个流程的运转,一切都是通过点对点内存池完成的。
高度可编程。基本实现账户抽象的目的,可以对钱包进行丰富的自定义。a)签名自定义,可以支持 ECDSA 之外的签名算法,聚合签名;b)验证自定义,如黑白名单;c)执行自定义,可以支持如 gas 代付、多签、交易管理、社会恢复、隐私保护等在内的多种功能。任何新加的功能理论上在这个 4337 流程中加一个模块就可以实现。
更多 gas。比常规交易有更多链上操作,产生额外的 gas
模块堆积。随着功能不断增加,可能存在安全漏洞。
协议兼容。与既有的合约钱包协议/工作流不兼容,既有的钱包开发商动力不够。
钱包通过合约复制 mempool 对交易的处理,用户不再进行交易。相反,用户的钱包将 UserOperations
发送到更高级别的内存池。矿工或 Bundler(捆绑器)可以将一组 UserOperation
打包成捆绑交易,发送到 EntryPoint 合约并协调钱包 CA 执行,并确保矿工/捆绑者得到适当的交易费用补偿。
钱包可以通过 require(msg.sender == ENTRY_POINT)
,即只相信通过一个特定网关来发起,然后钱包再执行指令、支付 gas 以及成功后的 nonce increment 等。Entry Point本质上完成对钱包的安全保障。通过受信任的 entry point 发起,合约钱包可以完成任何指令动作、gas支付。