以太坊有多难用

很多人说 Ethereum 用户体验不好。

这个说法太客气了。

Ethereum 真正荒诞的地方不是“操作步骤有点多”,而是:

它要求一个只是想转账、买币、使用应用的人,理解本应该只有协议工程师才需要理解的东西。

Nonce。

Gas Limit。

Base Fee。

Priority Fee。

Allowance。

Calldata。

EOA。

Contract Account。

Signature。

Typed Data。

MEV。

Slippage。

RPC。

Chain ID。

Bridge。

Finality。

UserOperation。

Bundler。

Paymaster。

你甚至不能简单地说:

我有 ETH。

因为接下来还可能有人问:

Native ETH 还是 WETH?

这已经不是学习曲线陡峭。

这是一套基础设施把自己的内部实现细节全部吐到了用户脸上,然后告诉用户:

请自行学习。

更离谱的是,Crypto 用户用了几年以后,居然开始觉得这一切很正常。

所以这一篇我不想再讨论“Ethereum Gas 很贵”这种已经被说烂的问题。

我们讨论一些更荒唐的东西。


一、以太坊最荒诞的事实之一:ETH 甚至不是一个正常的 Ethereum Token

Ethereum 有一种最重要的 Token 标准:

ERC-20。

USDC 是 ERC-20。

USDT 是 ERC-20。

DAI 是 ERC-20。

UNI 是 ERC-20。

几乎整个 Ethereum DeFi 世界都围绕 ERC-20 工作。

那么:

ETH 是不是 ERC-20?

不是。

Ethereum 自己的原生货币,居然不符合 Ethereum 后来最重要的 Token Interface。

原因也非常朴素:

ETH 出生得太早了。

官方文档自己承认,ETH 早于 ERC-20,因此并不符合 ERC-20 标准;为了让 ETH 能够像普通 ERC-20 一样被 DeFi 应用处理,人们后来创造了 WETH。

于是 Ethereum 出现了一幅非常有时代特色的画面:

Ethereum 原生货币:ETHEthereum Token 标准:ERC-20问题:ETH 不符合 Ethereum Token 标准解决办法:写一个合约,把 ETH 存进去,再铸造一个代表 ETH 的 ERC-20 Token。名字:Wrapped ETH

也就是说:

Ethereum 为了让自己的原生货币能够正常进入自己的 Token 生态,需要先把自己的原生货币包装成一个“假的自己”。

这件事情已经存在太久,以至于大家甚至不觉得滑稽。

你有 10 ETH。

进入某些 DeFi 协议:

请先 Wrap。

于是:

ETH ↓WETH

用完:

WETH ↓ETH

最精彩的是:

你可以拥有价值几万美元的 WETH,

但是如果 Native ETH 恰好为 0,

你仍然可能没法发送需要 Gas 的交易。

Ethereum 官方甚至特意提醒:

Wrap ETH 的时候记得留一些 Native ETH 支付 Gas。

换句话说:

你有 ETH。

但不是那个能付 Gas 的 ETH。

这种事情如果第一次接触 Crypto 的人觉得莫名其妙,不是因为他不懂区块链。

而是因为它本来就莫名其妙。


二、Ethereum 有一种很神奇的“取消交易”方式:再发一笔交易

接下来是我认为 Ethereum 用户体验史上最有喜剧效果的设计之一。

假设你发了一笔交易。

Gas 给低了。

它卡在 mempool 里。

你后悔了。

你点击:

Cancel Transaction

一个正常人理解的“取消”是什么?

把刚才那笔交易撤回来。

Ethereum 的取消是什么?

再发一笔新的交易。

而且要:

  • 使用和原交易完全相同的 nonce;
  • 给更高的手续费;
  • 通常给自己发送 0 ETH;
  • 让新交易抢在旧交易之前被打包;
  • 依靠“同一个 nonce 只能执行一次”的规则,把旧交易挤掉。

这不是段子。

MetaMask 官方给高级用户的手动取消方法就是:

给自己发送一笔 0 ETH 交易,使用旧交易相同的 nonce,并提高 Gas。

所以 Ethereum 里的:

Cancel

真正的语义其实是:

用另一笔更贵的交易,和原来的交易争夺同一个序号,争取先把这个序号消耗掉。

甚至“取消”都不是协议里的真正操作。

它是一场竞速。

你的旧交易:

我要执行。

你的取消交易:

不,你别执行,让我先执行。

然后用户还要额外付钱,请验证者优先执行:

“请不要执行我刚才那笔交易。”

这已经不是 UX 不好。

这是一个人在操作数据库事务日志。


三、最精彩的是:一笔交易卡住,可以把你后面的交易全部堵死

为什么刚才那套骚操作有效?

因为 Ethereum EOA 的 transaction nonce 是严格递增的。

比如你的账户已经执行到:

nonce = 100

接下来:

101102103104

必须按照顺序。

官方文档把 nonce 定义为账户发送交易时顺序递增的计数器,同一 nonce 不能执行两次。

这意味着一个特别荒唐的用户体验:

你发了 nonce 101。

Gas 太低。

101 卡住。

然后你发:

102。

103。

104。

很可能全部一起在那里等。

因为:

101 还没过去。

MetaMask 的官方排障文档甚至要求用户从最老的 pending nonce 开始处理,并明确说明不能先取消 nonce 10 而留下 nonce 9。

想象一下一个银行系统:

你上午发了一笔 10 元转账。

它卡住了。

于是下午你所有其他支付:

咖啡。

打车。

午饭。

网购。

全部不许进行。

银行告诉你:

因为第 71 号支付指令尚未执行。
请先处理第 71 号。

你会觉得这个银行疯了。

在 Ethereum:

这叫 nonce management。

甚至还有开发者专门写:

Nonce Manager

来管理这件事情。

一个只想转钱的人,最后需要理解分布式系统里的 ordered sequence number。

然后大家说:

Web3 需要用户教育。

教育个鬼。

这是数据库内部细节跑出来要求用户手工维护。


四、Ethereum 甚至把“加速交易”实现成了“重新发一次交易”

“Speed Up”也一样。

你看到钱包里有个:

Speed Up

看起来像是修改了原交易。

实际上通常是在干什么?

构造另一笔拥有相同 nonce、但出价更高的 replacement transaction。

MetaMask 明确说明,加速操作会重新提交交易,并复用原交易的 nonce,提高 Gas 使它更有机会先被打包。

Ethereum 甚至曾经有人专门提交 EIP-2831 来标准化这种 transaction replacement 的通知,因为 replacement 机制会给 dapp 开发者带来追踪问题。

所以 Ethereum 钱包里的两个按钮:

Speed UpCancel

背后的真实实现分别是:

同 nonce,发另一笔更贵的相同交易

和:

同 nonce,发另一笔更贵的空交易

如果一个普通用户必须知道这件事情,他会觉得整个系统像 1990 年代写出来的。

我们只是用漂亮 UI 把它遮住了。


五、Ethereum 还发明了一种消费体验:东西没买到,钱照扣

假设你去便利店买东西。

付款失败。

东西没拿到。

收银员说:

交易失败了。

你:

好。

收银员:

但是我们还是扣了你 20 块。

你:

为什么?

收银员:

因为我们刚才尝试处理你的付款,产生了计算成本。

这就是 Ethereum。

Smart Contract 执行一半:

REVERT

状态修改回滚。

Token 没交换。

NFT 没买到。

借款没借出来。

但已经消耗的 Gas:

不给你退。

官方 Gas 文档明确说明:如果交易执行过程中耗尽 Gas,状态修改会回滚,但用于执行工作的 Gas 仍然被消耗;REVERT 虽然不会像早期失败机制那样烧掉全部剩余 Gas,但已经执行掉的计算成本仍然存在。

工程上当然合理。

CPU 已经算了。

节点已经执行了。

所以收钱。

问题是:

用户为什么要承担应用执行路径预测失败的成本?

Web2 里服务器写了 Bug:

公司付服务器费。

Ethereum:

智能合约写了 Bug,或者状态刚好变化导致交易 revert:

用户付服务器费。

这是 Crypto 特别伟大的商业模式:

程序执行失败了,

账单寄给调用程序的人。


六、Ethereum 的手续费不是“手续费”,而是一场实时计算资源竞价

再看 Gas。

普通用户希望看到:

手续费:$2

Ethereum 底层给他的东西是:

gasLimitmaxFeePerGasmaxPriorityFeePerGasbaseFeePerGas

EIP-1559 以后,一笔 Type-2 交易甚至明确包含:

max_priority_fee_per_gasmax_fee_per_gas

而 Base Fee 根据区块利用率动态变化。

翻译成人话:

你不是在支付一个手续费。

你是在说:

我最多愿意为一个计算单位支付多少钱;
其中最多愿意拿多少钱给出块者当小费;
协议还会按照当前拥堵程度产生一个动态基础价格;
如果价格合适,请帮我执行这段程序。

一个用户只是想:

Swap 100 USDC。

结果钱包底层实际上在帮他参与:

全球分布式计算资源的实时拍卖。

然后大家夸:

钱包现在都会自动估 Gas,用户不用懂。

很好。

这句话本身就像在说:

我们这辆车的发动机启动需要手工调节喷油比例,不过现在仪表盘已经帮用户自动调了,所以体验还不错。

真正正常的 UX 是:

这个旋钮从一开始就不应该存在于用户的认知世界里。


七、Approve 是一个堪称反人类的权限模型

Ethereum DeFi 另一个经典设计:

approve(spender, amount)

我要 Swap 100 USDC。

正常人的语义:

花掉我的 100 USDC。

ERC-20 的经典语义却是:

我授权这个地址,以后可以从我的账户里主动拉走最多 N USDC。

这两个概念根本不是一回事。

而早年为了避免每次使用都重新 Approve,大量应用干脆让用户:

Approve Unlimited

于是:

我只是想买一次东西。

最终授权的是:

这个智能合约未来可以持续动我的 Token。

更加精彩的是,ERC-20 标准本身关于 approve() 的说明里就留下了一段历史伤疤:

客户端在修改非零 allowance 时,应该考虑先把 allowance 设成 0,再设置新值,以降低已知的攻击向量;但标准又不能直接强制这样做,因为必须兼容已经部署的旧合约。

仔细读这一段。

这几乎是上一篇《Ethereum 技术有多脏》的用户版缩影:

权限模型有问题。↓不能修改旧标准。↓让客户端 UI 帮忙规避。↓因为还得兼容以前的合约。

最后谁承担这个历史债?

用户。

所以你会看到有些 Token 修改 allowance 时:

先:

Approve 0

再:

Approve 100

一项正常的“修改授权额度”,可能变成两笔链上状态修改。

这不是金融创新。

这像是在操作一个从来没有完成过数据库 migration 的生产环境。


八、最荒唐的安全建议之一:不要相信 Token 的名字,要核对 40 位十六进制地址

普通金融系统识别一种资产:

USD

Crypto:

USDC

很好。

然后发现任何人都能部署一个 Token:

name = USD Coinsymbol = USDClogo = 看起来也一样

怎么办?

Crypto 老用户会非常认真地告诉新人:

别看名字。
一定要确认 Contract Address。

于是识别一种“美元”,最终需要识别:

0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48

这种字符串。

我们甚至把:

会检查 Contract Address

当成了一种 Crypto 素养。

不。

这不是用户素养。

这是命名系统基本不存在以后产生的生存技能。

正常系统面对:

Microsoft.com

不会告诉用户:

域名容易被骗,为安全起见请记住服务器的 IPv6 地址。

Web3 差不多就是这么干的。


九、Ethereum 的“签名”可能是整个消费者互联网里最危险的确认按钮

普通产品:

Confirm

通常意味着:

确认眼前这件事情。

Ethereum 钱包:

Sign

可能意味着:

证明你控制这个地址。

可能是登录。

可能是订单。

可能是 Permit。

可能是授权。

可能是 Typed Data。

可能最终让另一个协议拥有某种资产操作权。

用户看到的共同动作却都是:

签。

真正离谱的是:

Ethereum 的安全模型建立在密码学签名非常可靠的基础上,

但用户安全却经常建立在:

希望用户能读懂自己到底在签什么。

密码学可以证明:

确实是你签的。

密码学证明不了:

你知不知道自己签了什么。

这两件事之间,隔着整个 Crypto Scam 行业。


十、然后 EIP-7702 把这件事情推向了新的境界:一次授权,可以让 EOA 开始执行别人的代码

Ethereum 发现 EOA 太弱。

怎么办?

EIP-7702。

现在 EOA 可以通过 authorization,把账户执行逻辑 delegate 给一段合约代码。

这确实可以实现非常强大的钱包能力。

但 EIP-7702 自己的安全章节说了一件极其值得玩味的话:

应用不应该直接给用户一个界面,让用户随意签 delegation authorization。

为什么?

因为被授权的代码可以拥有对账户极大的控制能力,而普通用户没有能力审核自己到底 delegate 给了什么代码。

EIP 原文甚至明确指出:

没有安全的通用界面能够简单解决这件事;很少有用户具备合理审查 delegation code 的专业能力。

请欣赏这个技术进化过程:

第一代:

私钥控制账户。

大家嫌功能太弱。

于是下一代:

用户可以签名,让自己的账户执行另一个地址的代码。

然后协议设计者必须提醒钱包:

千万不要让用户自己随便签这个。

这已经非常 Ethereum 了。

增加一个能力。

然后增加一整套安全基础设施,

防止用户真的直接使用这个能力。


十一、公开 mempool:你甚至要先公开告诉全世界你准备怎么交易,然后祈祷没人从你身上赚钱

这是我认为 Ethereum 用户体验最“赛博朋克”的一个地方。

你想在 DEX 买一个 Token。

于是把交易广播出去。

交易还没上链。

但是搜索者可以看到:

这个人马上要买。

然后可以围绕你的交易排序。

例如最臭名昭著的:

Sandwich Attack。

攻击者:

先在你之前买。

你的交易把价格推高。

再在你后面卖。

利润来自哪里?

来自你获得了更差的成交价格。

Ethereum 官方 MEV 文档非常直接地承认,sandwich trading 会让用户遭受更大的 slippage 和更差的交易执行。

也就是说:

Ethereum 上一个用户准备交易时,默认模型长期以来近似是:

先把自己的交易意图广播给全世界↓告诉大家:我要买什么买多少愿意接受多少滑点↓等待别人决定有没有办法在你的交易前后插东西赚钱

这像什么?

你走进证券交易所,大喊:

我要市价买 500 万美元的这只股票!

然后所有高频交易员先听见。

交易完之后你再问:

为什么成交价格这么差?

别人回答:

这是 MEV。

一个普通人竟然需要知道什么是:

Private RPCMEV ProtectionSlippageSandwichBuilderSearcher

才能比较安全地完成一次兑换。

我们居然把这种系统叫:

Permissionless Finance。

确实 permissionless。

连抢你滑点的人也 permissionless。


十二、Slippage 本身就是一个非常荒唐的用户输入项

DEX 还有一个神奇设置:

Slippage Tolerance0.5%1%5%

普通用户想表达的是:

帮我用 1000 USDC 买 ETH。

Ethereum DeFi 要他回答:

在交易真正执行的时候,如果市场状态发生变化,你允许最终结果比当前 Quote 差多少?

这实际上是在让用户自己配置:

交易执行保护参数。

设太低:

交易 revert。

Gas 可能白花。

设太高:

可能遭遇差价格,甚至扩大 sandwich 的盈利空间。

这是什么用户体验?

用户需要在:

交易失败风险

和:

被别人抽取价值风险

之间手动调一个滑块。

然后 UI 告诉你:

建议 0.5%。

非常现代。


十三、最 Ethereum 的产品逻辑:系统先制造问题,再让钱包发明“聪明模式”遮住它

Nonce 难用?

钱包加:

Speed UpCancel

Gas 难懂?

钱包自动估算。

MEV 有问题?

加:

MEV Protection

Approve 危险?

钱包做:

Allowance Warning

签名看不懂?

钱包开始模拟交易。

L2 太多?

钱包隐藏网络。

账户太弱?

4337。

Gas Token 麻烦?

Paymaster。

EOA 太弱?

7702。

你会发现 Ethereum 的一个惊人规律:

底层每留下一个不适合普通人的抽象,上层就需要再生长一整套产品,把这个抽象藏起来。

然后我们把隐藏复杂度所产生的新基础设施称为:

Innovation。


十四、ERC-4337 更像一个证据:Ethereum 原始交易模型已经不适合现代用户了

看看 4337 到底在解决什么:

Gas Sponsorship。

Batch Calls。

Smart Account。

自定义认证。

账户恢复。

ERC-20 支付 Gas。

听起来很好。

但是这些需求其实证明了一件事情:

原始 Ethereum Transaction 根本不够用了。

于是 4337 做了一件极其 Ethereum 的事情。

不改底层。

在底层交易系统上面:

重新实现一套类似交易的系统。

它甚至故意不把自己的对象叫 Transaction。

而叫:

UserOperation

然后加入:

UserOperationBundlerEntryPointPaymasterFactoryAggregatorUserOp Mempool

ERC-4337 官方规范明确写着,它通过一个额外 mempool、UserOperation、Bundler 以及 EntryPoint,避免修改 Ethereum consensus layer。

这就像一个操作系统的进程模型实在不好用了。

但不能改 ABI。

怎么办?

在用户态重新造一个:

准操作系统。

然后终于实现:

普通用户不需要理解 Gas。

多么感人。

为了让用户终于不用理解 Ethereum,

Ethereum 先在 Ethereum 上面又实现了一层 Ethereum。


十五、甚至 4337 的“用户不用管 Gas”,背后都需要一整个影子金融系统

用户看到:

Gas Sponsored

很简单。

后台是什么?

Paymaster。

Paymaster 要先往 EntryPoint 存 ETH。

Bundler 要判断这个 Paymaster 愿不愿意付款。

还需要模拟 UserOperation。

需要检查验证逻辑。

Paymaster 可能造成 DoS。

Bundler 甚至需要对某些实体做 reputation / staking 约束。

也就是说为了实现一个 Web2 世界平平无奇的功能:

商家帮用户支付操作成本。

Ethereum 搭出来的是:

User ↓Smart Account ↓UserOperation ↓Bundler ↓Paymaster Validation ↓EntryPoint ↓Ethereum Transaction ↓Block

用户最后看到:

Fee: $0

然后大家说:

看,Web3 UX 已经跟 Web2 一样了。

是的。

只需要在按钮下面埋七层基础设施。


十六、Layer 2 最荒诞的地方不是“流动性割裂”,而是 Ethereum 连“余额”这个概念都搞得不再完整

L2 流动性割裂已经被说烂了。

真正更值得吐槽的是:

Ethereum 生态把“我有多少钱”从一个标量变成了一个向量。

以前:

balance = 10,000 USDC

现在实际上更接近:

balance = {  Ethereum: 2000,  Base: 3500,  Arbitrum: 4000,  Optimism: 500}

甚至这还没包括:

native USDC。

bridged USDC。

其他桥的 representation。

所以钱包里显示:

Total Balance: $10,000

这其实是一种 UI 幻觉。

因为这 10,000 美元:

并不是任意时刻都具有同样的可使用性。

资产总额相同,

但状态空间不同。

你能否马上用它,

取决于:

哪个 Rollup。

哪个 Token Contract。

有没有 Gas。

应用部署在哪。

有没有 bridge liquidity。

这才是 L2 最大的 UX 失败。

Ethereum 把“余额”这种人类几千年都理解得非常清楚的概念,重新变成了一道分布式系统题。


十七、智能账户甚至让“我的地址是什么”这件事重新变得复杂

EOA 有个很大的好处:

同一把私钥可以在大量 EVM 网络得到同一个地址。

然后我们开始拥抱 Smart Account。

问题出现了:

智能账户是合约。

合约地址取决于部署机制、factory、salt、init code 等条件。

为了让同一个智能账户能够在不同链拥有一致地址,生态甚至需要专门依赖 CREATE2、确定性部署 factory、counterfactual deployment 等机制。

EIP-7955 的动机甚至直接写明:

让合约在多个链拥有相同地址和代码,本身就是一个困难问题。

所以我们走过了一条很奇妙的路线:

EOA:功能太简单,但地址很好理解。↓Smart Account:功能终于丰富了。↓等等,现在得解决怎么让我的账户在不同链还是“同一个账户”。

Ethereum 的很多进步都有这种味道:

解决旧问题,顺便创造一个更高级的新问题。


十八、Ethereum 的终极荒诞:最先进的密码学系统,最后却依靠钱包猜用户想干什么

今天钱包越来越强调:

Transaction Simulation。

为什么?

因为用户根本看不懂:

tovaluedata

也看不懂合约调用到底最终会产生什么状态变化。

所以钱包开始在真正发送之前:

先模拟执行一次。

然后告诉用户:

预计你会失去 100 USDC。
预计你会得到 0.03 ETH。

这当然是巨大的 UX 进步。

但它同时也是一个极其讽刺的事实:

Ethereum 的原始交易格式提供给用户的信息,

已经不足以让一个普通人知道自己签名以后究竟会发生什么。

于是钱包需要运行 EVM。

需要追踪内部调用。

需要解析 Token Transfer。

需要识别恶意合约。

再把这一切翻译成人话。

我们最终造出了一个惊人架构:

人 ↓钱包 ↓交易模拟器 ↓RPC ↓EVM ↓智能合约 ↓再回到钱包 ↓告诉人类:“你刚才想做的事情大概是这个。”

一个确认按钮背后,

运行着半套区块链分析系统。


十九、Ethereum 最大的问题已经不是“不够简单”,而是它几乎没有能力重新变简单

如果 Ethereum 是一个创业公司内部系统:

重构。

删掉 EOA。

统一账户模型。

改 Token 标准。

重新设计 Gas。

废弃 Legacy Transaction。

重新设计权限。

甚至重新设计执行模型。

但是 Ethereum 做不到。

原因恰恰是它成功了。

数千亿美元资产。

十几年历史。

无数合约。

无数钱包。

无数假设。

全部必须继续工作。

所以:

ETH 不是 ERC-20?

不能重来。

包一个 WETH。

EOA 太弱?

不能删。

加 4337。

4337 不够原生?

再加 7702。

账户没有 Gas?

加 Paymaster。

公开 mempool 被 MEV?

搞 Private Orderflow。

Nonce 体验差?

钱包做 transaction replacement。

Approve 危险?

钱包做提醒、simulation、revoke。

多 L2 太碎?

搞 Chain Abstraction。

你会发现:

Ethereum 已经很少真正消灭复杂度。

它更擅长的是:

把旧复杂度包起来,再增加一个抽象层。


二十、所以 Ethereum 真正可怕的不是难用

“Ethereum 难用”其实还是在替它说话。

因为“难用”听起来像:

UI 还需要优化。

按钮还需要调整。

新手教程还需要完善。

不是。

更准确的说法应该是:

Ethereum 把一个分布式计算机应该自己承担的复杂性,大规模外包给了钱包、应用开发者,最后不可避免地外包给用户。

于是一个普通人只是想:

拿 USDC 买 ETH。

背后可能隐含着:

你的 ETH 是不是 WETH?你在哪条链?你有没有 Native ETH?Allowance 够不够?要不要 Approve?Approve 多少?Gas 多少?Base Fee 多少?Priority Fee 多少?Nonce 是多少?前面有没有 Pending Transaction?Slippage 设多少?会不会被 Sandwich?交易是否会 Revert?钱包模拟结果可信吗?走 Public RPC 还是 Protected RPC?这是 Transaction 还是 UserOperation?谁是 Bundler?有没有 Paymaster?

然后行业告诉你:

Mass Adoption is coming.

结语:一个真正成功的金融协议,应该让用户越来越蠢

这里的“蠢”不是贬义。

恰恰是技术成功的最高境界。

你刷信用卡的时候,

不需要理解 ISO 8583。

你用 HTTPS 的时候,

不需要检查 TLS handshake。

你发邮件的时候,

不需要知道 SMTP relay。

你打开手机的时候,

不需要知道虚拟内存页表。

技术越成熟,

用户需要知道的越少。

而 Ethereum 很长时间以来恰恰反过来。

使用得越深入,

需要理解的东西越多。

最后一个所谓“Crypto Native User”,其实是什么?

不是一个普通消费者。

而是一个被训练出来的:

兼职钱包安全工程师 + Gas 交易员 + RPC 运维 + 智能合约审计员 + 跨链清算员。

他知道怎么换 RPC。

知道怎么改 nonce。

知道怎么 replacement transaction。

知道怎么 revoke allowance。

知道 ETH 和 WETH 的区别。

知道怎么看 Contract Address。

知道怎么避开 sandwich。

知道什么情况下交易 revert 还会烧 Gas。

知道什么时候该用 bridge。

甚至知道什么叫 Bundler 和 Paymaster。

然后这个人转过头来对新人说:

Ethereum 其实不难,用几次就习惯了。

这句话本身,

可能就是 Ethereum 用户体验失败最好的墓志铭。

不是 Ethereum 终于变简单了。

是你终于被它训练成了协议工程师。

添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论