返回履历

2025.06–2026.02 · 两个月渐进式重构

MegaWallet

两个月,逐层重构跨端钱包的请求、状态与业务流程

01

选团队更容易接受的切入点

面对从 RN 转向 Electron、链范围反复的既有钱包,我先改相对独立的 Provider / RPC,单独验证后逐步接回主工程。

02

请求规则与业务交付一起推进

统一权限、去重与锁定规则,接入 Send 和地址校验;用 7 份工作文档帮助产品、设计和研发共同决策。

03

项目停止,但边界留下

main 管真实状态,chain-kit 管链能力;平台、状态、权限与业务职责已经拆清。

RPC
权限、去重与锁定统一进入请求管道
跨端职责
Transport 隔离通信,Service 拆分前后台
7 份
在推进中写下并用于团队分享的文档
Send
发送流程与地址校验接入新主干

章节

工作文档

两个月里,我围绕架构心智模型、现状风险、DApp 请求、Send 交互、地址校验、权限机制、前后台 Service 拆分和链能力收口,写下并向团队分享了 7 份工作文档。它们不是项目结束后的包装材料,而是当时用来讲清背景、冲突、取舍和实现路径的工具;展开可查看为什么出现、随后改变了什么,并跳到对应影片章节。

01Wallet-Core 心智模型对比原始文件 · my-history/1.钱包心智模型.md架构心智模型对应影片 03

文档中的核心问题

钱包究竟是“拥有数据与行为的内存对象”,还是“数据库事实在此刻的渲染结果”?

为什么写

接手后先建立一套能够同时讨论状态、持久化与跨端复用的共同坐标。

随后发生了什么

把后续审计拆成内存、持久化与账户模型三条主线。

02原架构风险建议原始文件 · my-history/2.suggestions.md现状风险审计对应影片 03 · 04

文档中的核心问题

明文长期驻留、非原子写入、缺少迁移与一致性校验,以及无法自然扩展的账户分层。

为什么写

把抽象的架构差异落到 MegaWallet 当时的真实代码。

随后发生了什么

确认问题来自全局结构,也说明为什么第一刀不能直接从 UI 开始。

阅读全文跳到
04钱包怎么处理来自 DApp 发起的请求原始文件 · my-history/4.Wallet-RPC.md请求系统重构方案对应影片 04 · 05 · 06

文档中的核心问题

连接权限、重复弹窗、锁定行为与新增链,不该继续分散在 Provider、Handler 和 Service。

为什么写

寻找相对独立、能够先替换并让团队逐步接入的请求边界。

随后发生了什么

形成 Provider / Transport 与 rpc-engine 主干,对应影片第 4–6 屏。

阅读全文跳到
05Send 功能设计稿评审分享原始文件 · my-history/5.Wallet-Send.md产品与设计评审对应影片 08

文档中的核心问题

让产品、设计同学意识到,从原型图、设计稿到实际落地,还差的东西。

为什么写

宿主链路恢复后,Send 成为要落地的真实业务;静态稿没有定义动态高度、输入职责和异常状态。

随后发生了什么

明确“输入时保留联系人搜索,完整后再进入校验”,并引出文档 06。

06useAddressValidation原始文件 · my-history/6.UseValidation.md实现说明对应影片 09

文档中的核心问题

一个面向 Recipient 地址输入流程的小型校验工具集。

为什么写

把 Send 评审得到的交互规则写成可组合、可跨页面复用的能力。

随后发生了什么

形成 typing → settled → complete → validating → valid / invalid 状态与 validators。

07钱包授权机制通识分享原始文件 · my-history/7.SharePermission.md团队通识分享对应影片 10

文档中的核心问题

面向产品和技术团队,覆盖标准 EOA 权限流程与多维边界场景。

为什么写

开始做 DApp 连接和确认页面前,需要先区分长期连接与逐次确认。

随后发生了什么

形成 Connector、ApprovalQueue 和统一 Confirmation UI。

08chain-kit 与 Service 架构原始文件 · my-history/8.chain-kit-and-service-architecture.mdCommit 变动总结对应影片 11 · 12

文档中的核心问题

一条改造把 Service 拆成 frontend / backend 以适配 Electron / Extension;另一条把散落的链能力收进 chain-kit。

为什么写

一次提交同时触及请求、进程、链与密钥,需要把真实的责任变化讲清楚。

随后发生了什么

Service 前后台分层建立宿主边界;chain-kit 独立收拢链能力,重复或虚假的 Service 被移除。

阅读全文跳到

01

不是接手一个空白钱包,而是接手 217 天的方向债务

Git 显示仓库从 2025 年 6 月 5 日开始,到我 2026 年 1 月 8 日提交第一笔核心重构时,已经过了 217 天、累计 836 次提交。6 月先接入 Expo / React Native,9 月再加 Electron;最初的桌面构建脚本直接把 mobile/dist 复制进 Electron renderer。Solana 则从 6–8 月持续加入 Keyring、签名、RPC、交易和 Wallet Standard,后来旧 Send 的 Solana 页面又在 2 月 12 日被删除。平台和链范围没有先定清,历史实现只能层层叠加。

  • Expo / RN 是第一套宿主,Electron 后来直接复用 mobile web 产物
  • Solana 从明确建设范围收缩为产品 UI 不再支持,底层实现仍然存在
  • 需求变化没有新的架构边界承载,只能继续修改旧 Handler、Bridge 与 Service
  • “屎山”是方向债务的结果,不是某个函数单独写得难看

02

两个月里,7 份文档让重构变成团队能接住的过程

这 7 份文档覆盖 Wallet-Core 心智模型、原架构风险、DApp 请求、Send 设计评审、地址校验和权限机制。第 08 份又记录了两条彼此独立的改造:把 Service 拆成 frontend / backend 以适配 Electron / Extension,以及把散落在 crypto、vault、utils/rpc 的链能力收进 chain-kit。它们分别面向产品、设计和研发,不是等代码改完再通知团队,而是先把背景、冲突和可选路径摊开,再通过分享或评审形成共同决定。

03

从 Provider / RPC 切入:相对独立,团队容易接受

Provider / DApp RPC 连接所有平台和链,但与 UI、资产和存储相比仍相对独立,可以先替换、单独验证,再逐步接回主工程。旧 Provider 用四层继承同时承担 EVM 状态、兼容方法、事件和平台通信,最后落到 globalThis.$jsBridge。我将它改成独立的 EthereumProvider / SolanaProvider:各自管理状态与事件,宿主通信只通过 Transport 接口进入,不再让 Provider 感知 RN、Electron 或 Extension 的具体 API。

04

同次改造的请求规则:交给 rpc-engine

旧请求从 service/src/dapp/request.ts 进入 getHandler(base),每次再创建 Evm / Sol Handler;权限、锁定、是否弹窗和 RPC fallback 跟着各个方法散落。新增权限要逐个方法补检查,防重复弹窗要在 handleRequest 维护 pendingApprovals,添加新链还要同时修改 Handler、映射、types 和 base 分支。我用 rpc-engine 按固定顺序执行 blacklist、日志、错误边界、权限、CAIP scope、去重、锁定和 executor;其中五项保护能力旧系统根本没有。请求最终只进入钱包 Handler、用户 Approval 或 RPC Proxy 三条明确路径。

05

Transport:平台通信不再穿进 Provider

旧结构把 Provider 和 JS Bridge 分在两个包:ProviderDelegate 依赖 globalThis.$jsBridge,mobile Bridge 硬编码 ReactNativeWebView.postMessage,desktop Bridge 硬编码 Electron IPC,各自还需要 buildInject 脚本拼装。新增平台要同时修改 Provider 与 Bridge,测试也必须 mock 全局宿主对象。重构后 Provider 不再感知宿主;React Native、Electron 和 Extension 分别实现 Transport Adapter。新增平台只需增加一个 Transport,测试也只需替换接口。

06

独立模块完成后,真正的阻力来自主工程基建

Provider / rpc-engine 在 1 月 15 日已经完成并接回 Service;真正进入 RN、Electron 与 Web 时,才发现主工程缺少承载它们的基础设施。Electron 当时尚未具备 React HMR,WebView DevTools 与 reload 会互相影响,跨宿主运行入口也不完整。我随后补齐这些通路,因为重构的完成标准不是删掉旧实现,而是新主干能在真实 App 里持续开发、调试和运行。

07

UI 与底层不是瀑布顺序,而是交错推进

建立 Provider / RPC 主干后,我逐步接入业务:Send 与 useAddressValidation 在 1 月 28 日先合入;Permission / DApp、双进程 Service 在 2 月 10 日提交;chain-kit 在 2 月 12 日收口。相对独立的模块可以先交付、先接回真实流程,让团队逐步接受改动;UI 业务推进的同时,我继续整理权限、状态权威和链能力。

08

Electron 是两个程序,钱包状态只能有一个真身

项目最初以 RN 为目标,Service 按“一个前端运行时里直接调用”来组织;后来加入 Electron 时,mobile web 和原有启动方式被直接复用,却没有同步定义 main / renderer 的唯一权威。renderer 是用户看到的前台页面,main 是能够访问本地数据库、网络和密钥的钱包后台;两个进程的内存并不共享。旧代码于是让两边各自 import 并启动一份 Service,看起来名字相同,实际是两只互不相通的钱包。我把完整 Service、RPC Engine、SQLite WAL 存储和 signer 放到 main,让它成为唯一真实状态;renderer 只保存脱敏镜像。用户点击通过 IPC 发给 main 执行,状态变化再以 Immer patches 同步回来,应用失败时重新拉取完整状态。

09

把分散的链逻辑和假抽象一起收掉

chain-kit 不是简单改目录:crypto、vault、utils/rpc 三个包被收成一个函数式链能力包;Transfer Service 合入 Tx;从未真正提供并发安全的 Nonce Service 被删除,改为读取 pending nonce;action 与 selector 分成写和读;Zod schema 同时承担运行时校验和类型推导。另一个独立的安全增强是 Signer 用 Uint8Array 保存自身 buffer,并在签名后清零;底层库仍短暂接收 string,这是明确保留的 JS 边界,不是“链能力归位”的证明。

010

长期连接与一次确认不是同一种状态

网站连接钱包时,需要一张长期通行证,记住“哪个网站、哪条链、哪些账户可以互相看见”;但签名、转账、切链和添加资产只需要一张一次确认单。我用 Connector 保存长期关系,用 ApprovalQueue 暂存当前请求;确认、拒绝或超时后,确认单立即销毁。Connect、Sign Message、Send Transaction、Switch / Add Network、Watch Asset 和 Solana Confirmation 页面都接到这条统一流程。

011

Send 是产品定义能力的证据

Figma 中同一个 Recipient Picker 的列表态是 378×406,完整地址态是 378×210。问题不只是一段动画,而是输入框到底先负责搜索联系人,还是先校验地址。我先定义 typing、settled、complete、validating、valid / invalid,再把地址、域名、自转账、合约、通讯录和最近收款人拆成可组合校验器。列表固定三行、提示区固定 64px,300ms debounce 与 600ms settled 让高频抖动收敛为一次有意义的状态转换。

012

项目停止,不代表可以把结果写成“成功上线”

这段工作不是两个月从零造一个钱包,而是在 217 天、836 次历史提交中逐层替换。最终进入当前源码的是:独立的 Provider / Transport、可配置的 RPC pipeline、接回 Service 的跨端请求主干、DApp 连接和确认、main 权威 Service、chain-kit、Send 和地址校验。项目没有完成市场发布,但停下时已经能明确回答平台、链、状态、权限、密钥和 UI 各自归谁。

提交演进

01.08

替换 RPC / Provider 主干

Transport、异构链 Provider 与 middleware pipeline 进入仓库。

01.14–01.15

完成新主干并接回 Service

Provider / rpc-engine 的独立实现进入主工程,宿主基建缺口随之暴露。

01.16–01.22

补齐真实宿主基建

建立跨宿主运行入口,并启用 Electron React HMR、处理 WebView DevTools 与重载冲突。

01.28

落地 Send 与地址校验

把设计冲突翻译成输入状态、校验器、缓存与多链规则。

02.10

连接、审批与双进程 Service

Connector、ApprovalQueue、DApp Confirmation 和 main/renderer bridge 成形。

02.12–02.13

chain-kit、黑名单与清理

三包链能力归入 chain-kit,Transfer / Nonce 收口;另为 signer buffer 增加用后清零。