MetaMask Snap 技术解读:开发体验、能力限制、安全性和商业潜力分析
内容 | 李大猫、Bruce
编辑 & 排版 | Cikey
设计 | WangTeng
本文由LXDAO 专家组成员李大猫、Bruce共同编写,我们将深入探讨MetaMask Snap 技术方面的内容。MetaMask Snap 是什么?它有哪些技术能力?安全性如何保障?开发体验如何?这些问题或许将决定 MetaMask Snap 的未来潜力。
MetaMask Snap 是什么?
前几天 ConsenSys 宣布向公众推出 MetaMask Snaps Open Beta。MetaMask Snaps 可以扩展钱包的能力,可以安装由第三方开发人员创建的 app(Snap)来获得新的功能。
如果说 ConsenSys 将 MetaMask 打造成了微信,那么 Snap 就是微信小程序。因此可以看出 MetaMask 的雄心,结合 ConsenSys 的体量和 MetaMask 的用户数,钱包领域的格局将因此产生改变。
目前官方已经公布了 35 款可用的 Snap,并发布了 Snap 应用商店https://snaps.metamask.io/。
部分 Snap 一览
那么 MetaMask Snap 从技术角度来看具体是什么样的呢?它们有什么能力限制?是否安全?开发体验如何?这些或许都将决定了 MetaMask Snap 的未来潜力。
去年开始,LXDAO 就深入研究了 Snap 的实现,目前多位成员已参与了 Snap 的开发并积极参与相关黑客松。今天,我们将从技术角度深入探讨上面的问题,并实际动手开发一个 Snap 来让你感受下 Snap 的开发者体验。
MetaMask Snap 初体验
安装 MetaMask Snap
通常可以通过 MetaMask Snap 官方市场进行安装,也可以直接在项目方的官网进行安装。以 UniPass 为例,当访问应用页面时,会提供一个按钮让你链接 MetaMask。
点击之后,会进行 Snap 的安装:
使用 MetaMask Snap
安装完成之后,就可以开始使用对应的产品和功能了,在这个应用中 UniPass 为你创建一个智能合约账号,方便你通过 MetaMask 的 EOA 账号进行操控等。
当你执行转账时,UniPass 会弹出来 Snap 向你确认是否要对 UniPass AA 钱包执行该操作。
通过 MetaMask 确认之后,即可执行相关操作。在这个场景中,MetaMask 通过 Snap 拥有了控制 UniPass AA 钱包的能力,UniPass 无需自己开发一个钱包插件即可让用户操作钱包,也可以借助 MetaMask 非常低成本的引入用户!
从这个安装和使用流程中,我们可以得到什么信息?
-
Snap 具备比较精细的权限控制,甚至包括链接钱包的权限、网络请求等。整体采用了最小权限访问(Principle of Least Privilege)的思路来设计,安全第一。
-
从 npm:@unipasswallet/unipass-snap 可以看到 Snap 是基于 NPM 进行包和版本管理。后面详细介绍一下安全性。
-
Snap 具备非常高的灵活性,可以按照项目的需求自行开发和决定展示的内容和逻辑。但是 UI 比较简陋,有一定的优化空间。
-
Snap 的体验非常简单和可靠,确实达到了 Beta 版本和生产环境的水平。
对于一个钱包产品来说,安全性永远是第一位的,接下来我们分析一下 Snap 的安全性设计。
Snap 是安全的吗?
Snap 代码运行时分析
上面提到了 Snap 是基于 NPM 进行包和版本管理,说明 Snap 实际上是基于 Web 和 JavaScript 的应用。众所周知,JS 的语法非常灵活自由,很容易带来 XSS 以及钓鱼等攻击。MetaMask Snap 如何应对这一挑战?
经过一些研究不难发现,MetaMask 资助 Agoric 并且深度集成了 Agoric 团队的 Hardened JavaSscript(又称 Secure EcmaScript )作为其"完全虚拟化"沙盒方案。Agoric 设计了一个 JavaScript 限制 API,并且提交了 Draft 提案到 TC-39(JS 标准化协会),地址是:https://github.com/tc39/proposal-ses。
简单的说 Hardened JavaScript 是一个更加安全的标准 JavaScript 的子集。借助了一些 JS 的能力和机制,削减了一些 JS API 的调用权限和方式,从而降低了一些风险。它为对应的代码创建了安全的沙盒来执行,同时遵循了Principle of Least Privilege 的原则来规划代码的权限控制。
Agoric 跟 MetaMask 合作开发了 LavoMoat (https://github.com/LavaMoat/lavamoat) 这个项目来增强 Snap 的安全性。LavaMoat 是一套工具,重点解决 JS 项目外部依赖的安全风险,增加对一些 API 和逻辑的限制。
Agoric 和跟 MetaMask 联合发起过黑盒白盒安全攻防测试,并输出过详细的安全报告。所以在代码运行时的层面,我们有充足的理由相信 Snap 是安全的。
Snap 代码必须开源且经过审计
除了有明确的用户授权流程和最小权限的设计,成为官方认可的 Snap 必须开源代码,通过社区的力量大大降低 Snap 自带恶意代码的可能性。
此外,我们也发现在官网上的 Snap 均经过第三方安全公司的代码审计才能发布。这大大提高了 Snap 的安全可信度,审计方包括大家都非常熟悉的慢雾。
目前发现的 Snap 的安全风险
由于目前 Snap 是基于 NPM 的包和版本管理,在代码的层面存在一定变更的可能性,而且非强制性审计,可能产生一定的安全风险。
因为 MetaMask 无法控制 NPM 平台的版本发布,因此项目方可以随时发布新的版本来让用户进行安装。而由于审计的成本原因,审计公司并不会对每一个版本进行审计,因此会出现一种情况:最新版本的变更,可能并没有开源或者经过审计。
不过由于执行环境是沙箱环境,而且使用了最小权限的设计,除非用户手动确认新的权限变更,新版本 Snap 则只会拥有之前的版本的权限来执行操作。但如果某个 Snap 的权限索取过大,这仍然将会产生风险,因此在安装使用 Snap 的时候,仍然需要保持警惕之心。
MetaMask Snap 的技术能力和限制
虽然近期 MetaMask Snap 正式公布,但实际上 Snap 已经开发了 4 年了!最早 MetaMask Snap 的构想由 Dan Finlay 在 2019 年 10 月 10 日发布在 Medium https://medium.com/metamask/introducing-the-next-evolution-of-the-web3-wallet-4abdf801a4ee。
平衡安全性、灵活性、有效性是一个非常大的挑战,也可以看出 MetaMask 为这一天付出了非常多的成本,做了很多准备工作。
目前主要开放了三大 API:
-
Interoperability(互操作性),允许开发者基于 MetaMask 开发其他链钱包
-
Transaction Insights(交易洞察),允许开发者在用户交易发起前获取交易data,从而分析交易是否存在风险
-
Notifications(通知),通过 Snap 直接推送消息给用户(不过这里似乎需要网站支持,略微有点鸡肋)
下面简单介绍下 MetaMask Snap 具体开放的能力以及效果,方便你有一个更为形象的感知。
Notification 通知能力
Snap_notify 接口可以在 MetaMask 或浏览器中显示通知。Snap 可以通过这个接口向用户直接发送消息,具体如下图所示
Transaction Insights 能力
当用户与智能合约进行交互时,MetaMask 会触发 Snap 的 onTransaction事件,MetaMask 会将未签名的原始交易传递给 onTransaction 处理程序方法,Snap可以在交易的二次确认页面返回一个界面,并且自定义显示内容。
通过这种能力,可以实现交易信息的安全审计、扩展信息展示等功能。
Dialog 接口和定制界面能力
Dialog 能力将允许 Snap 直接弹出一个独立窗口,实现类似传统 Alert/Confirm/Prompt 弹窗能力(如下图),分别用于提醒、确认、提交信息等。
通过 Dialog,你将可以定制简单的交互界面以及操作,来对接你的 DApp。
MetaMask Snap 暂时无法实现什么样的功能?
限制于安全性等原因,Snap 目前不支持第三方前端框架,只提供了比较少数的 UIKit,以下仍然是用 insight 做示例,展示所有开发者可以调用的 UI 组件库。
如图所示,目前上线的只有 Heading (大文字),Text (小文字),Panel (卡片且只能用一次),Divider (分割线),Copyable (点击复制)和小部分 Markdown 子集(bold和italic),所以说构建可交互似乎暂时无法实现,也无法使用内嵌 html 来实现交互操作。不过在官方 Discord 中提问后,官方声称这些都是出于安全性的考虑,并将会在接下来的版本中放开。
此外,同样基于安全的考虑,对外部的请求也只支持 Fetch 方法,而不支持更多请求协议例如 WebSocket。由于安全、能力和隐私限制,也无法获取到客户端的信息,比如当前唤起 Snap 的网址是什么,无法实现更丰富多样的功能。
这些问题和限制大多数是出于安全性的考虑,相信未来在安全性得到验证之后,会考虑开放更多权限。
提供了这些 API 的 MetaMask 实际上已经成为类似开放平台一样的产品。这种感觉就像当时微信推出公众号、小程序一样,瞬间让人感觉不再是一个简单的聊天工具。
MetaMask 在 19 年就预料到了今天的市场格局,即有非常多的公链和项目方、各种定制化的钱包需求。与其每个项目方都需要开发自己的插件而用户需要同时安装数个插件,倒不如基于 MetaMask Snap 来开发。在第一批放出来的 Snaps 中,我们也发现了类似 Sui Wallet、Solana Wallet、Arweave Wallet 等其他非 EVM 生态的钱包。凭借已有的用户量,MetaMask Snap 必将对钱包的格局产生重大的影响。
实际上,MetaMask Snap 的想象空间或许要比我们预想的更大,甚至超出了钱包的范畴。我们也可以看到来自 EthSign 团队的作品,基于 MetaMask Snaps 做了通用的密码管理器 KeyChain,所有浏览器里的密码都可以被钱包密钥加密后存储。这样管好钱包,就带上了所有的密码。
Snap 跟开发者非常相关,有了开放 API,具体的开发者体验如何?我们不妨亲自动手开发一个 Snap 体验一下。
直接开发一个 Snap 测试
疏离思路
众所周知,大部分用户在绝大多数情况下其实并不知道正在交互的智能合约到底是什么,主要包括如下几个问题:
-
交易的合约是否是钓鱼网站替换的合约
-
交易的合约是否是一个可升级合约
-
智能合约是否是一个刚被部署还没有多少人验证过的合约
-
交易的合约是否开源
对于普通用户来说,让他在操作之前去阅读合约的 solidity 代码更是天方夜谭。这时其实非常适合通过 Transaction Insight 功能来实现一些智能合约分析,比如使用 AI 来对智能合约做一个比较浅显的安全性审计,或许可以过滤到 80% 的低级钓鱼攻击。
准备开发环境,下载钱包
首先需要安装 MetaMask Flask
MetaMask Flask 是一个以开发人员为中心的 MetaMask 扩展发行版,主要用于新功能预览以及实验性功能开发。注意这是 MetaMask 的开发者版本,请不要进行日常使用,也不要导入自己日常使用的私钥。这里使用 Flask 主要是方便我们开发的 Snap 能本地即时预览。
建议安装后先暂时关掉小狐狸钱包以及其他浏览器钱包,或者新创建一个 Chrome Profile 使用,否则会冲突。
创建账户
安装钱包后就像正常创建 MetaMask 钱包一样创建一个新钱包,请注意,这是一个专门用于测试的钱包,请不要导入自己的日常钱包。
接下来我们需要给新创建的钱包中充值一些测试币,测试币可以通过水龙头获取,本文讲的 Snap 使用的是 Goerli,所以下文以 Goerli 为主。
基于模板初始化Snap
按照官方文档,首先使用@metamask/create-snap
这个 CLI 来创建一个新的 Snap 项目,同时我们使用官方的模板进行初始化:
yarn create @metamask/snap transaction-insights-snap && cd transaction-insights-snap
Snap 文件结构
Snap 的主要文件在./packages/snap
中,文件目录结构如下
Snap 的配置文件被放在snap.mainfest.json
中,Snap 的主体文件为./src/index.ts,
可以看到非常简洁。
启用权限
首先需要启用权限,首先我们在 snap.mainfest.json 中新增如下三条
"initialPermissions": {
"endowment:transaction-insight": {},//交易洞察
"endowment:ethereum-provider": {},//获取rpc
"endowment:network-access": {}//请求网络
}
Mainfest 文件中还可以修改 description 和 proposedName 来修改项目的描述和名称。
获取交易
接下来本案例中只需要修改index.ts
文件即可完成全部功能,简单的代码示例如下,可以完整运行的代码请移步:https://github.com/LidamaoHub/insights。
import { OnTransactionHandler, OnRpcRequestHandler } from'@metamask/snaps-types';import { heading, panel, text, copyable, divider } from'@metamask/snaps-ui';export const onTransaction: OnTransactionHandler = async ({ transaction }) => {
// transaction 包含了 to(合约地址)、data(交互数据)等值
// 以下为获取合约 Audit 数据的代码示例
const info = fetch(`http://contract-info.audit.dev/?address=${transaction.address}`);
// 以下是UI部分代码示例
return {
content: [
text(
`${info.riskList.length} risk item`,
),
heading(`${info.riskList.length ? 'Risk List' : ''}`),
…info.riskList.map((item, i) => text(`${i + 1} ${item.text}`)),
divider(),
text(
`More audit info from the following url`,
),
copyable(
`https://contract-info.audit.dev/mm${info.token}`,
)
]
};
};
更多的内容请参考 MetaMask Snap 开发者文档完成更复杂的 Snap 产品。
安装之后,你的每个交易将会可以看到类似的风险提示信息:
目前 Snap 的开发体验非常流畅,其中几乎没有遇到什么问题,而且官方的模版也是非常丰富多样。拥有丰富经验的开发者通常可以在几个小时内上手并且开始开发自己需要的 Snap。但需要正式发布并让主流用户都可以使用,最大的拦路虎将会是安全审计。并不是所有独立开发者和小团队都有资源为他的 Snap 做审计。因此可以预期 Snap 的数量和丰富度在未来很长的一段时间,都不会有非常大的爆发增长量。
开发者支持
如果你能够跑通以上样例,那么恭喜你已经成为一个合格的 Snap 入门开发者!
MetaMask 官方也在去年成立了一个 MetaMask Grants DAO,通过赠款计划资助 MetaMask 生态系统中高价值项目。MetaMask Grants DAO 是一项由员工主导的实验性计划,向全球外部开发人员发放赠款,以在 MetaMask 生态系统中构建有影响力的体验。MetaMask 将每个季度的部分利润注资到这个 DAO,当前 MetaMask Grants DAO 每年的预算为 240 万美元。
目前只要是能丰富 MetaMask 生态的项目都可以申请官方的 MetaMask Grants DAO( MetaMask Grant ),关于更多的信息请移步https://metamaskgrants.org/。
值得一提的是 LXDAO 很荣幸的在今年申请到了 MetaMask 的 Grants 并参与了相关项目的开发,并建立了联系通道,如果你是 LXDAO 成员有相关的想法,可以更高效的联系到他们递交申请。
结语
我们在上面从技术层面剖析了一下 Snap 是什么、是否安全、能力限制以及开发者体验。简单总结如下:
-
Snap 类似微信小程序,开启了 MetaMask 更大的想象空间
-
安全性整体不错,但是也存在一定的风险,仍然需要对高危权限保持警惕
-
由于安全性的考虑,目前开放的能力不多,但仍然可以产生足够想象空间的 Snap
-
经过四年的打磨和测试,开发者体验优异,然而由于其安全性的考虑,设计了白名单机制和审计的要求,可以预期的是在未来一段时间并不会有海量的 Snap 涌现出来
目前 MetaMask Snap 仍在快速迭代的,相信未来会开放更多权限和能力。希望能推出更开放同时安全的机制,比如苹果官方 Audit 审核机制以及官方代码仓库版本控制,这样才能让更多开发者低成本参与进来。如果这个问题得到改善,可以预期将会在未来产生大量的需求。甚至会出现专门的 Snap 开发者岗位。
借助海量的 MetaMask 用户,独立开发者或许也有一定的机会。让我们拭目以待 Snap 带来的下一个突破性创新。