自己部署签名页
Vela 在你批准每一笔交易之前都会先解码,这份解码是实打实的活——但干这活的,是 构造这笔交易的同一个应用。如果这个应用、或者它送到你手上的那条路被动了手脚, 它就能给你看一样东西、却签下另一样。Bybit 遇到的正是这件事。
签名页存在的意义,就是把这件事一分为二:交易从一个地方来,而核对和签名发生在 另一个由你控制的地方。
它是什么
一个文件夹——仓库里的 app-web/clearsigning——它既是一个网页,也是一个 Chrome 扩展。
纯 HTML、CSS 和 JavaScript:没有框架,没有打包器,没有构建步骤,没有依赖,
也不会自己发任何网络请求。
拿到一个签名请求时,它不相信随请求一起送来的那份摘要。它自己解码原始 calldata、 自己算出摘要、把这个签名实际会授权的内容摆给你看,然后才去请求你的通行密钥。
因为没有构建步骤,你读到的文件就是正在跑的文件。你可以把这个文件夹跟仓库逐字比对, 从而确切知道自己托管的是什么。
哪一份副本才能替你的钱包签名
通行密钥绑定在它被创建时的那个域名上。你的 Vela 钥匙注册在 getvela.app 之下,
而浏览器只会把它们提供给一个依赖方(relying party)是 getvela.app 的页面。
这一条规则,决定了哪一种「自己跑一份」的方式对你有用。
作为 Chrome 扩展——这是配合你现有钱包该用的那种。 不管这个文件夹从哪儿来,
扩展的依赖方都是 getvela.app,所以你现有的钥匙可以在里面签名,而跑着的代码
正是你加载并检查过的那个文件夹。
- 打开
chrome://extensions,开启开发者模式。 - 点加载已解压的扩展程序,选择
app-web/clearsigning文件夹。 - 工具栏上的图标会在新标签页里打开这个页面。
作为你自己域名上、或者 localhost 上的一个页面。 通过 HTTP(S) 提供服务时,
这个页面的依赖方是它自己的主机名——所以它能用注册在那个主机名下的钥匙签名,
而不是注册在 getvela.app 下的钥匙。这让它非常适合把整套流程端到端跑一遍、
跑桌面端的流程,以及替一个钥匙就创建在你自己域名下的钱包签名。它不是一种
替已有的 getvela.app 钱包签名的办法。
cd app-web/clearsigning
python3 -m http.server 8080 # → http://localhost:8080 应用里所有路径都是相对的,所以放在现有主机的一个子目录下也能用;直接从磁盘打开 index.html(file://)也可以随便看看——那种情况下没有来源,也就没有依赖方,
什么都签不了。
它在签名之前会做什么
- 它自己解码这笔交易。 这个调用做什么、给谁、多少钱,全部从 calldata 里读出来 ——包括批量交易里嵌套的调用。
- 它只签自己算出来的摘要。 EIP-191、EIP-712、SafeOp 和 SafeMessage 的摘要都在
页面里计算,并与
vela-core——钱包用的同一份代码——对拍。算不出的摘要就是拒签, 而不是签一个。 - 它检查这笔交易就是被请求的那一笔。 站点请求的那个调用,必须真的在被签的 操作里面。
- 它拒绝无限额度的授权。 不是警告——是拒绝,并且告诉你该怎么做。
- 它看不懂的时候会说出来, 而不是拿一段自己也担不起责任的友好摘要顶上。
- 它显示账户的地址和身份图标, 并且不显示由请求方提供的收款方名字。凡是请求方 能控制的东西,要么被拿掉,要么被明确标注成「这是它说的」。
它故意没有什么
- 没有任何编辑器。 请求一到就定死了:你要么签,要么不签。费用选择器或者额度 编辑器都会重写 calldata,而那正是这个页面要防的病。
- 不能创建钥匙。 签名页没有创建通行密钥的能力。创建一把新钥匙,等于创建一个 不同的账户。
- 不发任何网络请求。 没有东西要取,也就没有东西能被拦截。
一个请求怎么到达它
| 请求方 | 通道 |
|---|---|
| 同一个浏览器里的一个页面 | postMessage |
| 同一个浏览器里的页面,发给扩展 | 扩展端口 |
| 同一台机器上的桌面应用 | URL 片段 + 回环回调 |
| 一部手机或者另一台电脑 | 低功耗蓝牙(协议已实现;射频部分还没在真机上测过) |
线上格式、摘要算法,以及一张「屏幕上每一项来自哪里」的对照表,都在代码旁边的 PROTOCOL.md 里。
什么时候该用它
从这个账户开始放着你输不起的钱那天起——而且从那以后,每一次签名都用它。不只是 大额的时候:一笔很小的授权,就可能交出足以掏空账户的权限。一个只在特殊场合才拿出来 的签名习惯,到了真正需要它的那天,其实并不在位。