自己部署签名页

Vela 在你批准每一笔交易之前都会先解码,这份解码是实打实的活——但干这活的,是 构造这笔交易的同一个应用。如果这个应用、或者它送到你手上的那条路被动了手脚, 它就能给你看一样东西、却签下另一样。Bybit 遇到的正是这件事。

签名页存在的意义,就是把这件事一分为二:交易从一个地方来,而核对和签名发生在 另一个由你控制的地方。

它是什么

一个文件夹——仓库里的 app-web/clearsigning——它既是一个网页,也是一个 Chrome 扩展。 纯 HTML、CSS 和 JavaScript:没有框架,没有打包器,没有构建步骤,没有依赖, 也不会自己发任何网络请求。

拿到一个签名请求时,它不相信随请求一起送来的那份摘要。它自己解码原始 calldata、 自己算出摘要、把这个签名实际会授权的内容摆给你看,然后才去请求你的通行密钥。

因为没有构建步骤,你读到的文件就是正在跑的文件。你可以把这个文件夹跟仓库逐字比对, 从而确切知道自己托管的是什么。

哪一份副本才能替你的钱包签名

通行密钥绑定在它被创建时的那个域名上。你的 Vela 钥匙注册在 getvela.app 之下, 而浏览器只会把它们提供给一个依赖方(relying party)是 getvela.app 的页面。 这一条规则,决定了哪一种「自己跑一份」的方式对你有用。

作为 Chrome 扩展——这是配合你现有钱包该用的那种。 不管这个文件夹从哪儿来, 扩展的依赖方都是 getvela.app,所以你现有的钥匙可以在里面签名,而跑着的代码 正是你加载并检查过的那个文件夹。

  1. 打开 chrome://extensions,开启开发者模式
  2. 加载已解压的扩展程序,选择 app-web/clearsigning 文件夹。
  3. 工具栏上的图标会在新标签页里打开这个页面。

作为你自己域名上、或者 localhost 上的一个页面。 通过 HTTP(S) 提供服务时, 这个页面的依赖方是它自己的主机名——所以它能用注册在那个主机名下的钥匙签名, 而不是注册在 getvela.app 下的钥匙。这让它非常适合把整套流程端到端跑一遍、 跑桌面端的流程,以及替一个钥匙就创建在你自己域名下的钱包签名。它不是一种 替已有的 getvela.app 钱包签名的办法。

cd app-web/clearsigning
python3 -m http.server 8080   # → http://localhost:8080

应用里所有路径都是相对的,所以放在现有主机的一个子目录下也能用;直接从磁盘打开 index.htmlfile://)也可以随便看看——那种情况下没有来源,也就没有依赖方, 什么都签不了。

它在签名之前会做什么

  • 它自己解码这笔交易。 这个调用做什么、给谁、多少钱,全部从 calldata 里读出来 ——包括批量交易里嵌套的调用。
  • 它只签自己算出来的摘要。 EIP-191、EIP-712、SafeOp 和 SafeMessage 的摘要都在 页面里计算,并与 vela-core——钱包用的同一份代码——对拍。算不出的摘要就是拒签, 而不是签一个。
  • 它检查这笔交易就是被请求的那一笔。 站点请求的那个调用,必须真的在被签的 操作里面。
  • 它拒绝无限额度的授权。 不是警告——是拒绝,并且告诉你该怎么做。
  • 它看不懂的时候会说出来, 而不是拿一段自己也担不起责任的友好摘要顶上。
  • 它显示账户的地址和身份图标, 并且不显示由请求方提供的收款方名字。凡是请求方 能控制的东西,要么被拿掉,要么被明确标注成「这是它说的」。

它故意没有什么

  • 没有任何编辑器。 请求一到就定死了:你要么签,要么不签。费用选择器或者额度 编辑器都会重写 calldata,而那正是这个页面要防的病。
  • 不能创建钥匙。 签名页没有创建通行密钥的能力。创建一把新钥匙,等于创建一个 不同的账户。
  • 不发任何网络请求。 没有东西要取,也就没有东西能被拦截。

一个请求怎么到达它

请求方通道
同一个浏览器里的一个页面postMessage
同一个浏览器里的页面,发给扩展扩展端口
同一台机器上的桌面应用URL 片段 + 回环回调
一部手机或者另一台电脑低功耗蓝牙(协议已实现;射频部分还没在真机上测过)

线上格式、摘要算法,以及一张「屏幕上每一项来自哪里」的对照表,都在代码旁边的 PROTOCOL.md 里。

什么时候该用它

从这个账户开始放着你输不起的钱那天起——而且从那以后,每一次签名都用它。不只是 大额的时候:一笔很小的授权,就可能交出足以掏空账户的权限。一个只在特殊场合才拿出来 的签名习惯,到了真正需要它的那天,其实并不在位。