虽然许多现有的文章很好地解释了账户抽象,但是大多偏科普向,也有少数十分深入于技术细节。本文旨在融合两者:既提供关于账户抽象概念的全面技术解读,也分类剖析现有应用和基础设施的案例。
作者:Steve Wang 万物研究院研究员,沃顿商学院在读,前端&合约工程师 推特:@SteveIsEmployed
以太坊改进提案4337(EIP 4337)定义的账户抽象是一组协议层的接口。它不仅集成了web2用户熟悉的交互形式,如多因素认证(multi-factor authentication),还给web3特有的用户痛点提出了解决方案,如无需手续费(gasless)的交易。作为引入下十亿用户的协议接口,用户体验是账户抽象最关注的重点。
虽然许多现有的文章很好地解释了账户抽象,但是大多偏科普向,也有少数十分深入于技术细节。本文旨在融合两者:既提供关于账户抽象概念的全面技术解读,也分类剖析现有应用和基础设施的案例。 因此本文分为三部分:在第一部分,我们将探讨EIP 4337的起源,并深入了解其技术细节,包括用户操作(UserOperation)、打包器(Bundler)、入口点合约(Entry Point Contract)、代付合约(Paymaster)、钱包工厂(Wallet Factory)和签名聚合器(Signature Aggregator)。在第二部分,我们将分析现有的市场玩家,包括智能合约钱包和第三方基础设施提供商。在第三部分,我们将讨论账户抽象的发展方向,包括该领域的创新展望和预测。
本文篇幅较长,第一部分主要为账户抽象的技术解读,只对账户抽象的应用场景感兴趣的读者可以直接跳到第二部分。
首先来简要回顾一下基础知识,以太坊有两种类型的账户:外部拥有的账户(externally owned accounts,即EOA)和合约账户。
图:EOA与合约账户(来源:Bitcoin Insider)
智能合约钱包早在EIP 4337之前就已存在。EIP 4337的提出是为了标准化设计智能合约钱包及其相关基础设施的通用功能。EIP 4337遵循以下几个设计原则:
EIP 4337为标准化智能合约钱包定义了六个合约接口:
下面我将详细介绍用户操作(UserOperation)和上述的六个合约接口,是对官方EIP 4337文档和David Philipson@Alchemy账户抽象系列的解读。
除了需要额外的参数以外,UserOperation的工作流程与普通交易类似:它们都被广播到mempool中进行验证、执行并最终完成出块。UserOperation的验证和执行由打包器(Bundlers)触发,我将在下文中解释。
图:官方EIP 4337文档对UserOperation参数的定义
Bundler是一个外部账户(EOA),代表用户在智能合约钱包上验证和执行UserOperation交易,因为在以太坊上,所有交易都必须由EOA触发。Bundler使用户不用创建和记忆EOA的私钥就可以触发智能合约钱包交易,这也是智能合约钱包存在的初衷。
虽然Bundler具有很强的公共物品(public goods)属性,他们也可以获得经济上的利益,因为:
尽管用户付出了成本,但Bundlers对于节省gas是有好处的,因为每执行一笔交易都需要21,000 gas的固定成本,而执行捆绑交易可以把一笔交易的固定成本分摊给捆绑交易里的多UserOperation,从而节省gas成本。此外,在同一笔交易中多次修改storage,每次额外操作的gas费都会边际递减。
需要注意的是,尽管以太坊上的交易是线性执行(非并行)以避免状态冲突(state conflict),多个UserOperations可以放在一个捆绑交易里执行,因为Bundlers可以设置同一智能合约钱包地址最多包含一个UserOperation,这样捆绑交易在修改状态时不会相互冲突。
除了这些差异之外,Bundlers与区块构建者(Block Builder)类似,因为它们都将经过验证的UserOperation广播到公共或私有的mempool中。接下来,我们将介绍入口点合约(Entry Point Contract),Bundler需要与之交互来执行UserOperation。
入口点合约是一个全局单例(global singleton)合约,所有Bundlers都需要调用它来执行UserOperation。它充当了Bundler与智能合约钱包之间的中间人:
一方面,Bundlers调用入口点合约的handleOp函数,该函数接受一个UserOperation作为输入参数。handleOp负责根据UserOperation的calldata验证并执行智能合约钱包的函数
另一方面,智能合约钱包需要向入口点合约存入代币用于支付gas费用给Bundlers。当Bundler使用EOA触发handleOp函数时,会产生gas费用。
图:官方EIP 4337文档中的入口点合约工作流程
智能合约钱包主合约将UserOperation的验证和执行步骤分开:
通过分离UserOperation的验证和执行,Bundler可以在链下验证UserOperation,从而不需支付gas就可以过滤掉恶意交易。 因此validateOp函数也起到了链下debug API的作用。
代付合约(Paymaster)定义了智能合约钱包的gas抽象的逻辑。Gas抽象的形式包括用ERC20同质化代币支付以太坊gas和无需gas的交易,两者都可以由Paymaster来实现。ERC-4337的模块化设计允许UserOperation通过paymasterAndData参数指定任意的Paymaster地址和输入参数。Paymaster具有以下功能和要求:
Paymaster(至少在官方的愿景中)是一个充满竞争的开放市场。虽然官方没有定义Paymaster的链上信誉系统,Bundlers可以在链下记录Paymaster的服务质量并停止使用质量较低的Paymaster,从而激励Paymaster为UserOperation提供可靠的服务。
Paymaster接口定义了两个函数:
图:官方EIP 4337文档中的Paymaster工作流程
图:官方EIP 4337文档中的Paymaster接口
Wallet Factory是一个创建智能合约钱包的合约。 回顾一下,UserOperation有一个可选的initCode字段。当initCode为空时,UserOperation只是触发智能合约钱包的功能。当initCode填充了Wallet Factory地址和新智能合约钱包的参数时,Bundler将触发相应的Wallet Factory使用指定参数创建智能合约。
Wallet Factory在以下方面有助于实现账户抽象:
Wallet Factory还有其他职责。与Paymaster类似,它们需要在入口点合约上抵押ETH并持续性地为UserOperations提供良好的服务,以便从Bundler那里获得更多流量。
因为不同的智能合约钱包使用不同的签名算法,所以需要先将使用相同签名算法的UserOperations聚合起来,然后分别进行验证。此外,由于链上密码学计算会消耗大量gas,支持聚合的签名方案(如BLS)可以在链上验证过程中节省gas。 因此我们需要一个名为签名聚合器(Signature Aggregator)的EIP 4337智能合约接口。它可以通过实现以下两个函数来支持特定的签名算法:
与其一次验证一个UserOperation,Bundler首先会使用多个签名聚合器合约(每个签名算法使用一个)生成多个聚合签名(每个签名算法生成一个)。之后,Bundler将UserOperation数组、聚合签名和聚合器地址传递给入口点合约,每个UserOperation数组会调用其对应的签名聚合器的validateSignature函数。验证通过后,Bundler就会在智能合约钱包上执行这组UserOperations。
与Paymaster和Wallet Factory类似,聚合器也需要在入口点合约上质押以太坊并保持为UserOperations提供良好服务的记录。
图:官方EIP 4337文档中的签名聚合器接口
EIP 4337的模块化设计将智能合约钱包的账户抽象功能分为多个接口。这些接口的功能合在一起可以总结为如下的工作流程:
图:没有签名聚合器的账户抽象工作流程(Alchemy提供)
图:带签名聚合器的账户抽象工作流程(Alchemy提供)
UserOperation在链下和链上都会触发validateOp等函数进行交易验证。为了防止智能钱包合约外部的状态变化(state change)导致链下和链上的验证结果不一致,EIP 4337禁止验证函数使用读取合约外部storage和读取全局状态(如时间戳)的OpCodes。这种禁止适用于validateOp、validatePaymasterOp和validateSignatures这些验证函数。
智能合约钱包是账户抽象市场中最大的参与者。为了与EIP 4337兼容,它们通常会实现自己的打包器(Bundler)、代付合约(Paymaster)、钱包工厂(Wallet Factory)和签名聚合器(Signature Aggregator)。这些钱包还配备了方便dApp集成钱包的SDK。智能合约钱包市场比较拥挤,既有老牌大玩家如多签钱包Gnosis Safe在原有产品基础上实现账户抽象功能,也有市场新人如Candide专注于构建完全兼容EIP 4337的智能合约钱包。本节将介绍这些钱包的共同特点以及每个特点中的差异化。
社交登录为智能合约钱包提供了Web2用户非常熟悉的交互体验,例如使用已有的Google帐户创建和登录钱包。同样的逻辑也可以延伸到社交恢复上,例如使用邮箱重置智能合约钱包的密码。社交登录和社交恢复的逻辑一般在钱包的主合约中定义。
这里我们引入守护者(Guardian)的概念。 守护者是指可以授权用户访问某账户或帮助用户重制恢复某帐户的实体。守护者可以是Web2账号也可以是邮箱地址。 这个概念在Web2中已经有了很广泛的应用,现在也可以通过账户抽象的概念在智能合约钱包中实现。
一个智能合约钱包可以有多个守护者。用户需要在创建钱包过程中或之后设置守护者,并达到一定的守护者验证阈值,例如3个守护者中的2个,以登录或恢复钱包。这个过程通常被称为多因素认证(multi factor authentication)。以下是常见的智能合约钱包守护者类型:
让我们看看一些市场上玩家对此功能的实现:
图:Web3Auth社交登录和社交恢复,此案例中有三个守护者
Gas abstraction包含无gas交易和使用任意ERC20代币支付gas。 这些逻辑可以在代付合约(Paymaster)中实现,也可以通过中继器(Relayer)实现。
许多智能合约钱包自己实现了与EIP 4337兼容的Paymaster合约,并在入口点合约上质押代币,帮助用户支付gas。
Relayer是在EIP 4337之前就存在的另一个gas abstraction的解决方案。 Relayer是用户信任的交易转发者,执行一种称为“元交易”(meta-transaction)的特殊类型的无gas交易。元交易是一种以太坊交易,它在原始交易中插入另一个交易。用户使用私钥对元交易进行签名,并将其发送给Relayer,后者对其进行验证,将其提交给区块链,并代付gas。Relayer只是执行交易,而不改变交易本身。 Relayer会获取经济上的利益,因为它们会向执行交易的合约收取gas费用加上一小笔利润。例如,Relayer可以向支持无gas交易的去中心化应用(dApp)收费。Relayer可以是中心化的可信第三方,也可以是去中心化的网络。Relayer与代付合约(Paymasters)的区别在于以下几点:
让我们看看一些市场上玩家对此功能的实现:
到目前为止,大多数ERC20支付gas的解决方案(如Candide和Soul Wallet)仅支持非常有限的代币类型,主要是稳定币,尽管我预见这在未来会发生变化。
图:Biconomy 使用Paymaster支持无gas交易(基于EIP 4337的技术实现)
图:Biconomy 通过Relayer使用任意ERC20支付gas(并非基于EIP 4337的技术实现)
许多现有的钱包,如MetaMask,已经通过和第三方供应商合作的方式把法币出入金通道和跨链桥集合在钱包中。这些出入金通道和跨链桥可以进一步与gas abstraction中的代付合约(Paymaster)进行集合。 让我们看看一些市场上玩家对此功能的实现:
交易批处理是智能合约钱包独有的功能,允许钱包用户在一个链上交易中执行多个交易。一种实现方法是调用一个multiCall函数,它接受两个参数:一个calldata数组(每个calldata定义一个函数调用)和一个合约地址数组(每个函数调用的合约地址)。multiCall函数中有一个循环(loop)并在每次循环里执行一个函数调用。交易批处理可以使多个交易分摊一个以太坊交易的固定gas费,从而减少成本。
请注意,交易批处理不同于签名聚合(signature aggregation),后者接受一个UserOperations数组作为输入参数并输出一个聚合签名字节以加快多个签名验证的速度。而这个数组中的每个UserOperation都可以调用一个multiCall来执行交易批处理。
在EIP 4337中实现交易批处理的方式如下:入口点合约调用handleOp函数,然后该函数再调用智能合约钱包主合约内定义的multiCall函数。
让我们看看一些市场上玩家对此功能的实现:
图:示例 MultiCall 合约(Solidity by Example提供)
智能合约钱包相对于EOA的一个主要优势是其模块化设计。钱包的功能可以通过钱包提供商开发的合约模块进行扩展。这些模块提供了EIP 4337接口中未定义的功能,并可以由用户自定义。模块化设计下,智能合约钱包是可升级的。这种做法在EIP 4337发布之前就已经是行业标准,由诸如Gnosis Safe之类的产品率先推出。Gnosis Safe是一款主要针对商业用户的多签名钱包,提供一系列EIP 4337没有定义的功能:
同样的模块化设计也被EIP 4337兼容的钱包继承,包括Argent、Candide、Soul Wallet和zeroDev。 另一种扩展智能合约钱包功能的方法是在钱包里原生地集成去中心化应用(dApps)。例如,Gnosis Safe为dApps提供了一个SDK。使用此SDK的dApp可以直接出现在钱包界面中,等同于为钱包提供了一个内置的应用商店。其他类似解决方案包括WalletConnect。然而,这些前端解决方案并不是协议层的设计,因此超出了本文讨论的范围。
图:Candide钱包的模块化设计与Safe(即Gnosis Safe)类似(Candide钱包官网提供)
下面将讨论各种Layer 2对账户抽象的支持以及打包器(Bundlers)和代付合约(Paymasters)的第三方基础设施提供商。
鉴于最近L2的爆炸式增长,许多智能合约钱包已将开发重点转向L2。许多L2都原生地支持与EIP 4337非常相似的账户抽象合约标准,本节将对此进行探讨。
Optimism
Optimism的第一版通过引入三个EVM不支持的OVM OpCodes来实现账户抽象。在Optimism的技术实现中,智能合约是唯一的账户类型(不存在EOAs),因此所有用户钱包都是智能合约钱包。智能合约钱包还可以通过调用upgrade函数升级合约代码。 不幸的是,为了与EVM保持完全一致和出于安全方面的考虑,Optimism的第二版移除了这三个OVM Opcodes和对账户抽象的支持。 虽然目前有少数智能合约钱包正在Optimism上构建,但是尚无关于支持账户抽象的官方声明。
Arbitrum
虽然目前有少数智能合约钱包正在Arbitrum上构建,但是尚无关于支持账户抽象的官方声明。
Starknet
与以太坊不同,Starknet不区分EOA和合约账户。因此,所有Starknet账户都是智能合约账户。Starknet的账户模型受到EIP 4337的很大影响,具体表现在以下方面:
Starknet对账户抽象的实现和以太坊相比依旧存在显著的差异:
如果通过验证的交易在执行步骤失败,Starknet的序列器将无法抽取任何gas费,而以太坊没有这个问题。
图:Starknet没有EOA账户类型,只有合约账户(Starknet官网提供)
zkSync
zkSync也不区分EOA和合约账户,因此原生地支持账户抽象。zkSync的账户模型与EIP 4337十分类似,具体表现在以下方面:
然而,zkSync实现的账户抽象和以太坊也存在显著差异:
如上所述,账户抽象基础设施包括可以发送UserOperations的客户端SDK、打包器(Bundlers)、代付合约(Paymasters)和签名聚合器(Signature Aggregator)。这些基础设施通常由智能合约钱包自身实现,从而更好地整合产业上下游,但是大多数都不是为第三方使用而设计的。因此市场上需要第三方基础设施提供商来提供模块化和可定制的Bundler和Paymaster服务。一些知名的基础设施玩家比如Alchemy也进入了这个市场。本节会深入探讨这些第三方基础设施提供商。
Stackup
Stackup是一个Bundler和Paymaster的提供商。其Bundler采用Go语言实现,通过了所有EIP 4377测试套件的要求,完全开源且免费使用。Stackup Bundler支持不同的模式:
Stackup还支持两种类型的Paymaster:
图:Stackup的基础设施产品套件
Blocknative
Blocknative主要是一个内存池浏览器和可视化工具提供商。得益于其对于内存池较强的理解,Blocknative提供了具有独特功能的打包器(Bundler)服务,例如:
Alchemy
Alchemy目前正在开发其Bundler和Paymaster服务,潜在用户可以加入waitlist。
图:Alchemy的EIP 4337基础设施服务还在开发中
eth-infinitism eth-infinitism是以太坊基金会的官方团队,目前已经实现了EIP 4337标准定义的Bundler和Paymaster。关于该团队的文档很少,但是根据Stackup的一篇文章,截至2023年2月,eth-infinitism是通过EIP 4337官方测试套件的唯一两个Bundler之一(另一个是Stackup)。
根据Web3Caff Research最近的一篇研报,以太坊中所有交易的发起地址(from参数)去重后的总数约为1.5亿。然而,智能合约钱包的总数,以Gnosis Safe和Argent账户的总和来估算(这两个产品的用户最多),仅为15万。
假设在终局,EOA和智能合约钱包的数量相等,我们可以预测智能合约钱包的市场规模有1000倍的潜力。 尽管如此,生态对智能合约钱包的采用并不会一帆风顺。像MetaMask这样的EOA钱包巨头仍未宣布采用EIP 4337的计划。尽管我们不知道他们的意图,但也不难推断,主流EOA钱包的巨大利润并不足以支持其团队内部采用一个基础设施都不完善的新标准。UserOperation仍然不是dApps广泛使用的主流交易类型。虽然如此,我依旧对智能合约钱包市场保持乐观态度,也可以预见到智能合约钱包对用户体验的大幅改善会为账户抽象市场带来的指数级的增长,尽管这种爆发可能还需要一两年才发生。
尽管EIP 4337定义了诸如打包器(Bundler)、代付合约(Paymaster)和签名聚合器(Signature Aggregator)等基础设施的合约接口,以太坊官方并没有给出很多重要技术问题的解决方案,而这些问题需要项目方反复尝试不同的技术实现,比如:
尽管zkSync和Starknet已经原生地支持账户抽象, 但它们仍未实现所有的EIP 4337接口,并且在技术实现上与以太坊存在差异。 尽管许多项目团队正在为Optimism和Arbitrum构建智能合约钱包、打包器(Bundlers)和代付合约(Paymasters),但这些L2尚未宣布官方支持EIP 4337的计划,账户抽象也并非他们的开发重点。
从纯技术的角度来看,L2账户抽象基础设施的实现比L1更为复杂。例如,在验证步骤中,一个L2智能合约钱包需要同时估算L1和L2的gas费,并分摊给捆绑交易(bundle)里的每个UserOperation。
尽管钱包市场上有许多创新的功能(如gas抽象、社交恢复、MPC等),大多数智能合约钱包都支持所有上述功能,因为这些功能的技术实现并不困难。因此,智能合约钱包的商业层面与用户体验层面同样重要。 重要的商业因素包括:
无需许可(permissionless)且模块化(modular)的Bundler服务是一种公共物品(public good)。 绝大多数Bundler的开源性质决定它们是非排他性和非竞争性的。任何RPC端点都可以通过复制开源代码来运行一个Bundler。即使运行Bundler的RPC端点通过API密钥来收取服务使用费,Bundler服务也比其他基础设施(如代付合约Paymaster)更难盈利,因为后者可以通过与第三方出入金或DeFi协议聚合器提供商合作轻松赚取费用差价。虽然更难商业化,但是Bundler是一种重要的公共物品,因为UserOperation的验证和执行需要尽可能多的Bundler参与从而更好地去中心化。因为Stackup和eth-infinitism是目前唯二可用的第三方Bundler服务提供商,所以我们肯定需要更多这样的Bundler服务提供商。
Bundler服务提供商需要克服许多技术难点:
Bundler服务提供商的差异化在于:
Bundler服务是专为钱包构建的,还是第三方基础设施提供商构建的?
类似于以太坊节点,Bundler服务采用不同的语言实现。这种语言多样性可以防止单点故障,对以太坊生态有益。
对私有和公共内存池的支持以及对私有内存池进行定制的选项。
对L1和不同L2链的支持,每个链在接口实现上略有不同。
本节将列举智能合约钱包和账户抽象基础设施中最需要的创新。
无需许可和模块化的EIP 4337基础设施
让我们首先设想一下EIP 4337基础设施的终局:
在当前市场状态下,许多智能合约钱包已经构建了自己的基础设施,但是这些基础设施并未针对第三方的不同使用场景。 诸如Stackup之类的第三方基础设施提供商正在开发模块化的Bundler和Paymaster,但是它们的部署过程仍然远未达到无需许可。因为EIP 4337尚未完成,这些基础设施的模块化功能还没有被全部定义。此外,由于UserOperation交易量依旧较低,启用了签名聚合的钱包(如BLS Wallet)仍然不是主流。
EIP 4337下游基础设施
这些包括EIP 4337未定义但实现EIP 4337基础设施所需的下游基建,比如可以集成到Paymaster的法币出入金聚合器和DeFi聚合器。因为这些解决方案已经存在,所以创新最有可能在现有提供商内部发生,提供商只需重新配置它们公开的接口。
dApp SDK和脚手架
尽管现有的智能合约钱包都为了方便dApp集成而构建了自己的客户端SDK,但市场仍然缺少:
更激进的做法:将账户从智能合约钱包分离
EIP 4337的智能合约钱包接口只需要一个validateOp函数,将所有的核心业务逻辑,如用户注册、权限控制和社交恢复等,留给钱包开发者自由决定。 虽然这提供了更多的灵活性,但不同的智能合约钱包会更加割裂以太坊生态,因为一个钱包中的数据不能轻易地转移到另一个钱包。dApp也可能通过支持某些智能合约钱包而不支持其他钱包加剧这种分裂。
此外,尽管用户可以通过邮箱或其他在Web2常见的流程登录智能合约钱包,他们仍需要通过“连接钱包”这类Web2用户不熟悉的操作流程来登录dApp。
解决这些问题的一个激进方案是通过创建新的账户标准,将账户与智能合约钱包分离,例如Hexlink倡导的EIP 6662。EIP 6662定义了一个IAccountMetadata的账号接口,使用户可以自定义自己账号的认证方法(如Web2社交媒体账号),从而将认证逻辑从钱包主合约转移到单独的账户接口。支持此接口的智能合约钱包可以允许用户将其账户数据转移到另一个钱包。支持此接口的dApp可以允许用户使用账户接口中定义的Web2认证方法登录他们的Web3账户。dApp可以验证来自Web2认证方法的签名,以此查询Web3账户地址,向Web2账户推送通知,并连接到Web3账户。用户不需要为不同的dApp创建其支持的不同的钱包。相反,dApp会自动连接到与用户Web2认证方式关联的Web3账户。 用户账户和钱包不再是一体也不再受制于钱包,钱包本质上成为了用户可以登录账户来进行资产管理的dApp。
在撰写本文时向几位行业专家和朋友进行了请教交流,特别在此感谢陈剑Jason、PlanckerDAO的王奕翔Aaron、独立研究员菠菜菠菜、Hexlink团队、AntAlpha Ventures的Circle Fang、Skyhigh等各位的交流探讨! 因本人认知有限,调研时间有限,可能会出现错误和疏忽。如有不同意见,欢迎交流指正,非常感谢!研究为个人兴趣,与文章里提到的所有项目都不存在经济利益关系,但也不作为投资建议。 欢迎大家关注我的推特@SteveIsEmployed,如果你想深入探讨交流,也可以添加微信clairvoyant_98。
https://ethereum.org/en/roadmap/account-abstraction/ https://eips.ethereum.org/EIPS/eip-4337 https://antalphaventures.notion.site/2edc5e36f69a44fe9a27dad0ef6ac3fb?v=a0fad60e889a4b2f831a2349d92ca11b https://www.stackup.sh/blog/a-guide-to-the-top-erc-4337-bundlers-features-performance-and-more https://github.com/PaymagicXYZ/awesome-account-abstraction https://camiinthisthang.substack.com/p/account-abstraction-for-everyone https://research.web3caff.com/zh/archives/4660 https://research.web3caff.com/zh/archives/3212 https://www.alchemy.com/blog/account-abstraction https://www.alchemy.com/blog/account-abstraction-paymasters https://www.alchemy.com/blog/account-abstraction-wallet-creation https://www.alchemy.com/blog/account-abstraction-aggregate-signatures https://docs.starknet.io/documentation/architecture_and_concepts/Account_Abstraction/approach/ https://era.zksync.io/docs/dev/developer-guides/aa.html#example-of-using-the-library https://www.alchemy.com/account-abstraction https://docs.zerodev.app/ https://eips.ethereum.org/EIPS/eip-4361 https://beta-docs.0xpass.io/ https://braavos.notion.site/Public-Docs-d98f625edb2e4399acab2e30d060ef8e https://github.com/proofofsoulprotocol/soul-wallet-contract https://docs.wallet.unipass.id/introduction/intro https://docs.blocknative.com/4337-tools/blocknative-bundler https://docs.candidewallet.com/develop/getting-started https://docs.stackup.sh/docs/packages/bundler/introduction https://github.com/web3well/bls-wallet https://docs.etherspot.dev/ https://biconomy.gitbook.io/sdk/introduction/overview
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!