自托管指南

你的钱在链上的 Safe 合约里,由你的钥匙控制。Vela 运行的任何东西都动不了它。 Vela 运行的,是让钱包用起来方便的那套机器:替你提交交易的中继、帮新设备找回钱包的 索引、链数据目录、汇率源,以及各个 App 本身。

这一页把这些部件逐一列出来:每样是做什么的、没有它会怎样、怎么换成你自己的。 也讲清楚唯一无法替换的那一样——你的通行密钥所属的域名——以及 getvela.app 不在了该怎么办。

全景

部件做什么Vela 的默认实例能换吗没有它会怎样
中继接收你签好的操作,垫付 gas、提交上链,收取你签名同意的手续费vela-relay-cf.getvela.app能——运行 vela-relay 并让钱包指向它无法发送交易
公钥索引把新钱包的钥匙登记上链;回答“这把钥匙属于哪个钱包”p256-index-v2.getvela.app能——运行 p256-index无法创建新钱包;登录时改为直接读链
注册表合约每个钱包钥匙的永久公开记录Gnosis 上的 0x94fD…1EA9不需要换——它没有所有者,钱包直接读取
链数据网络信息、代币列表、图标、清晰签名描述文件ethereum-data.getvela.app能——运行 ethereum-data没有代币列表和图标;能解码的交易变少;无法添加网络
汇率按你选择的法币显示金额vela-currency.getvela.app能——运行 vela-currency 或任何兼容 Frankfurter 的服务App 会尽量改用链上的 Chainlink 汇率(桌面版显示美元)
RPC 节点读取余额、模拟交易各网络的公共节点能——在“设置 → 网络”里按网络设置Vela 会在节点之间自动切换
App钱包本身wallet.getvela.app、发布版安装包能——自己编译
getvela.app你的通行密钥所属的域名不能——见下文

另外还会连接几个不属于 Vela 的第三方服务:解码交易时最后才用到的公共函数选择器 数据库(sourcify、openchain、4byte)、用来显示安全密钥型号名称的认证器目录, 以及用手机扫码签名时经过的 Apple 和 Google 隧道服务器。

唯一无法替换的:通行密钥的域名

通行密钥属于创建它的那个网站。Vela 的钥匙是为 getvela.app 创建的。浏览器只会把它们提供给 getvela.app 及其子域名上的页面(或 getvela.app 声明为相关的来源),手机自带的通行密钥也只在 getvela.app 认可的 App 里可用。在浏览器之外,规则要宽松一些:Chrome 允许获得 getvela.app 权限的 扩展使用它们,而你电脑上的程序可以直接向安全密钥或手机请求一个 getvela.app 签名——自编译 App 正是 这样工作的,这也是为什么你运行什么软件很重要。由此有两个结论。

把网页钱包部署到你自己的域名上,得到的是另一个钱包。同一份代码放在 wallet.example.com 上,创建的是属于 wallet.example.com 的通行密钥——新的钥匙, 因此是新的地址。它无法给在 wallet.getvela.app 创建的钱包签名。这份副本仍然有用: 用于在它上面新建的钱包,或者从零开始完整运行你自己的一套。

对于已有的钱包,即使 getvela.app 下线或消失,下面这些方式依然可用:

方式能用哪些钥匙从哪里获得
Vela 浏览器扩展(Chromium 系浏览器:Chrome、Edge、Brave)浏览器能用到的任何钥匙:本设备的通行密钥、USB 安全密钥(电脑支持时也可用 NFC)、扫码连接的手机GitHub 上的发布包,或自己编译
你自己编译的桌面或手机 App扫码连接的手机、USB 安全密钥自己编译
商店版和经过公证的桌面版扫码手机和安全密钥始终可用;“本设备”通行密钥只在操作系统还能把 App 与 getvela.app 对上时可用GitHub 发布页(之后上架商店)

扩展能用 getvela.app 的钥匙,是因为 Chrome 允许获得某网站权限的扩展使用该网站 的通行密钥。这项权限由浏览器在本地检查;我们实测过它可用,但还没有在域名真正下线的情况下测试过。自己编译的 App 能用手机和安全密钥,是因为 Vela 直接与它们通信;而手机 自带的通行密钥(“本设备”)要求 App 由 Vela 签名,你编译的版本不是。

签名页本身不是一条独立的路:它只给别的程序发来的 请求签名,而目前还没有任何 Vela App 会向它发送请求。

让钱包指向你的服务

每个 App 在 设置 → 高级 → 服务端点(桌面版为 设置 → 服务端点)下有四个字段:链数据、通行密钥索引、 Vela 中继、法币汇率。在你修改之前,字段显示的是 Vela 的默认值;恢复默认 会把 四个一起还原。对中继、索引和链数据,钱包会请求 /api/health 并显示一个状态标记, 只有返回了正确的服务名且 status"ok" 时才是绿色。无论标记是什么颜色,你输入的 内容都会被保存——请等它变绿。

服务/api/health 中的 service
中继vela-relay
公钥索引webauthn-p256-publickey-registry
链数据ethereum-data
汇率不按名称校验——必须返回以美元为基准的汇率列表

四个 App 都完整支持这四个字段,而且改过的端点在下一次调用时就生效,不必等下一次启动: 创建钱包、登录、按地址查名字——每条路径都在真正用到端点的那一刻才去读它。 在 iOS 上,默认索引连不上时,还可以在登录界面修改通行密钥索引。

(在 2026 年 9 月之前,这件事有四条例外, 其中最严重的是 iOS 上那个显示占位数据、又什么都不保存的页面。它们都已经修好了。)

运行你自己的中继

中继就是 vela-relay(Rust,MIT 许可)。 一个部署服务所有链:钱包调用 https://your-relay/<chainId>。必须是 vela-relay—— 钱包用一个 Vela 专有的方法获取手续费报价,通用的 ERC-4337 打包器没有实现它。

你需要

  • Docker,外加你已经在运行的 Redis 和 Iggy 服务;或者一个 Workers Paid 付费套餐的 Cloudflare 账号,并在本机装好 Node.js 和带 wasm32-unknown-unknown 目标的 Rust 工具链。
  • 一个 OPERATOR_SECRET(十六进制,至少 32 字节)。它派生出一个金库地址和一组 中继地址,在每条链上都相同。务必保密:它控制着中继的资金。
  • 你要服务的每条链上都要有 gas:把该链的原生币(Tempo 上是 pathUSD)转到你的 金库地址,金库会自动给各个中继地址补充。

Docker

git clone https://github.com/mondaylabsltd/vela-relay
cd vela-relay
cp .env.example .env
# 在 .env 中填写 VELA_RELAY_IGGY_URL、VELA_RELAY_REDIS_URL、OPERATOR_SECRET,
# 自己运行链数据的话再填 VELA_RELAY_CHAIN_DIRECTORY_URL,
# 并把 VELA_RELAY_IMAGE 设为你信任的发布镜像(见 docs/docker.md)
docker compose pull relay
docker compose up -d --no-build
curl --fail http://127.0.0.1:4567/readyz

两条路都走得通:已发布的镜像最省事,而 docker compose up --build 是从你能读到的源码构建出同样的东西。不用 Docker 的话, cargo run --release --bin vela-relay 可以直接运行。

Cloudflare Workers

cd vela-relay/vela-relay-cf
npx wrangler queues create vela-relay-ops
npx wrangler queues create vela-relay-dlq
npx wrangler secret put OPERATOR_SECRET
# 自己的链数据:在 wrangler.jsonc 的 "vars" 里加上 "VELA_RELAY_CHAIN_DIRECTORY_URL"
npx wrangler deploy

检查

curl https://your-relay/api/health        # {"service":"vela-relay","status":"ok",…}
curl https://your-relay/v1/treasury/100   # 你在 Gnosis 上的金库地址,以及是否需要补 gas

然后把 https://your-relay 填进 Vela 中继 字段。

需要知道的

  • 钱包支付的手续费进入你的金库。无论用哪个中继,钱包计算手续费的方式都一样 (见网络与手续费)。
  • 在更换中继之前添加的自定义网络,会继续使用添加时记录的中继地址。
  • 中继从链目录读取每条链的信息和它接受的稳定币:默认是 ethereum-data.getvela.app, 把 VELA_RELAY_CHAIN_DIRECTORY_URL 设为你自己的链数据即可替换。这个设置需要 vela-relay v0.9.6 或更新版本;更早的版本只会读 Vela 的那一份。

运行你自己的公钥索引

索引就是 p256-index(Rust,MIT 许可)。创建钱包时, 它逐一检查每把钥匙的证明,然后把这组钥匙写进 Gnosis 上的注册表合约,并支付 gas。请继续使用现有的注册表 0x94fD1A891EB6c5F340622Baf2F3A0cb70A941EA9:它没有 所有者,任何有余额的地址都能写入,而每个 Vela App 都会直接读取它。你另建的注册表, 它们是看不到的。

你需要

  • Docker 加 Redis 和 Iggy(服务端版本),或者一个 Cloudflare 账号(Worker 版本;它自己的 README 说明链上写入尚未做过端到端测试)。
  • 一个有 xDAI 的 Gnosis 私钥。登记一个钱包,一把钥匙约需 110 万 gas,七把约 360 万。
  • 以下配置:
P256_INDEX_IGGY_URL=iggy+tcp://user:password@iggy.example:5100
P256_INDEX_REDIS_URL=redis://redis.example:6379/0
P256_INDEX_CONTRACT_ADDRESS=0x94fD1A891EB6c5F340622Baf2F3A0cb70A941EA9
P256_INDEX_DOMAIN_REGISTRY=0x5266DfF591B9F9EecfEdb8E7EfEf6c687854edaf
PRIVATE_KEY=0x…

P256_INDEX_DOMAIN_REGISTRY 是最容易被漏掉的一项:缺了它, 服务端发出的挑战会被合约拒绝,所有登记都会失败。它就在 .env.example 里, 而且必须和已部署合约自己的 DOMAIN_REGISTRY 一致—— 从注册表 VERSION 12 起,挑战所用的域在部署时就固定下来,合约重新部署也不会变。

运行与检查

git clone https://github.com/mondaylabsltd/p256-index
cd p256-index
cargo run --release -p p256-index-server
curl https://your-index/api/health   # "service":"webauthn-p256-publickey-registry","status":"ok"

服务端监听的是普通 HTTP(默认端口 11256);钱包只接受 https:// 端点,所以要在前面加一个 TLS 代理。docker build -f p256-index-server/Dockerfile . 从全新克隆的仓库也能构建成功; 如果用 Compose,先把 .env.example 复制成 p256-index-server/.env

如果完全没有索引可用,已有的钱包照样能用:登录时 App 会通过你的 RPC 节点直接读取 Gnosis(然后是以太坊)上的注册表合约。只有一把钥匙的钱包,甚至可以不经过注册表, 凭两次签名重建出来。创建新钱包则确实需要索引,因为登记总得有人付费。

运行你自己的链数据

链数据就是 ethereum-data(MIT):约 2600 条网络及其代币的静态 JSON 和图片,外加 Vela 用来解释交易的 ERC-7730 描述文件。

docker run -d --name ethereum-data -p 3000:3000 --restart unless-stopped 
  ghcr.io/atshelchin/ethereum-data:latest
curl http://localhost:3000/api/health   # "service":"ethereum-data","status":"ok"

它的 README 也讲了如何从源码构建和部署到 Cloudflare。用 HTTPS 对外提供服务,然后把地址 填进 链数据 字段。

中继也读取这些文件,包括一个 Vela 专有的字段(stables 列表决定哪些稳定币能付手续费)。 用 VELA_RELAY_CHAIN_DIRECTORY_URL=https://your-chain-data 让它读你的这一份;每条网络的信息 它会缓存一小时。

运行你自己的汇率服务

vela-currency(MIT)转发欧洲央行每天 公布的汇率,不需要任何密钥。

docker run -d -p 8080:8080 -v rates-data:/data ghcr.io/mondaylabsltd/vela-currency:latest
curl "http://localhost:8080/v2/rates?base=USD"

https://your-host/v2/rates?base=USD 填进 法币汇率 字段。任何兼容 Frankfurter 的 服务也可以。一定要保留 ?base=USD:所有换算都以它为前提。

自己编译 App

所有 App 都在同一个仓库里(MIT)。 README 里有每个 App 的编译步骤,这里是简版:

App编译能给你在 getvela.app 已有的钱包签名吗
浏览器扩展cd app-web/vela-wallet && pnpm install && pnpm build:extension,然后在 chrome://extensions 以“加载已解压的扩展程序”加载 extension/dist能,任何钥匙都行
网页钱包cd app-web/vela-wallet && pnpm install && pnpm build;以 Cloudflare Worker 部署不能——在你的域名上它是另一个钱包(见上文)
桌面版cd app-desktop/vela-wallet && cargo run(打包脚本见其 README)能,用扫码手机或 USB 安全密钥
Android先生成核心绑定,再 ./gradlew :app:installDebug能,用扫码手机或 USB 安全密钥
iOS./rust/scripts/build-ios-xcframework.sh,然后用你自己的开发者团队在 Xcode 中编译能,用扫码手机或 USB-C / Lightning 接口的 YubiKey(固件 5.8 及以上)

自己编译的 App 无法用“本设备”的通行密钥给 getvela.app 钱包签名:Apple 和 Google 只允许 由 Vela 签名的 App 使用 getvela.app 的通行密钥。

添加 Vela 没有内置的网络

任何支持 P-256 预编译、并部署了它所检查的那些标准合约的 EVM 链都能运行 Vela。 链设置会告诉你一条链缺什么,并部署任何人都能部署的那部分; 网络与手续费解释了具体要求。 这项检查已经包含了多把钥匙的钱包所需的那两个合约,并且会单独标明它们—— 一条链上没有它们,单钥匙钱包照样能跑。

全部换掉之后,还剩哪些指向 Vela

把上面的都换成你自己的,还会剩下这些:

  • 显示安全密钥型号的认证器目录——只影响显示;连不上时 App 会显示通用名称。
  • getvela.app 上的关联文件——商店版 App 使用“本设备”通行密钥时需要它们。扫码手机和 安全密钥用不到。

以下这些不属于 Vela:公共函数选择器数据库、Apple 和 Google 的手机扫码隧道,以及你自己 选择的 RPC 服务商。

下一步:可以自己运行的签名页