跳到主要内容

签名与鉴权

本文档说明 链写操作 的签名与鉴权(亦可使用 官方 SDK 封装)。做市接入流程见 做市商对接指南;Action 字段 schema 见 write-actions


1. 双通道概览

通道适用 Action签名方式典型私钥
L141 个交易/管理操作(PlaceOrder、CancelOrder、SetMarginMode…)msgpack → connectionId → EIP-712 phantom L1ActionAgent 或 Master secp256k1
User-Signed RegisterAgent · RevokeAgent · WithdrawRequest标准 EIP-712 typed data(钱包 eth_signTypedData_v4Master 钱包

做市推荐路径:Master 注册 Agent → 日常用 Agent 私钥 走 L1 通道;envelope.signer 始终为 master 地址

禁止:对 PlaceOrder / SetMarginMode / SetLeverage 等 L1 Action 构造 primaryType 等于 Action 名的 typed data(钱包 eth_signTypedData_v4)。链上只认 phantom L1Action(string source,bytes32 connectionId)。签错通道时 ecrecover 出野地址,常表现为 AgentNotRegistered(即使 agent 已注册)。


2. 环境参数

以下值参与签名,须与目标环境 逐字一致

2.1 Auroran 生产(单节点)

参数用途
chain_id42envelope.chain_id(auth 校验等于节点配置)
network_tag"zepto-dev"L1 phantom L1Action.source(UTF-8,区分大小写)
zeptoChain"zepto-dev"User-Signed 消息体(与 network_tag 同值)
domain_chain_id(L1)42必须与 chain_id 相同。验签 digest 与 txid 读此字段;L1 EIP-712 domain 的 chainId = envelope.domain_chain_id
action_version2可用 getExchangeConfig 校验
EIP-712 domainZeptoSignTransaction / 1 / verifyingContract=0x0…0两通道共用 domain 名与版本

domain_chain_id 按通道

通道envelope.domain_chain_idEIP-712 domain chainId
L142(= chain_id= domain_chain_id(故亦为 42
User-Signedmaster 钱包当前 EVM 链 ID(如 BSC 56同上(写入 typed data)
  • User-Signed 时 envelope.chain_id 仍为 42,可与钱包 EVM 链 ID 不同。
  • 把 User-Signed 的 56 套到 L1 的 domain_chain_id——否则 digest domain 与按 chain_id=42 签出的摘要不一致。

2.2 本地开发

典型值
Chainhttps://rpc.auroran.io
chain_id / network_tag / zeptoChain与本地 genesis.json 一致(常为 42 / "zepto-dev"

链上 只读 RPC 返回 chain_id / network_tag;私有节点以 genesis.json 为准。


3. Envelope 与 Credential

所有写请求 params 格式:

{
"envelope": {
"chain_id": 42,
"domain_chain_id": 42,
"action_version": 2,
"nonce": 0,
"signer": "0x1111222233334444555566667777888899990000",
"credential": {
"Secp256k1": {
"signature": [95, 83, 94, "... 64 bytes r||s ..., 27"]
}
},
"action": { "PlaceOrder": { "...": "..." } }
}
}
字段说明
signerMaster 地址;Agent 代签时仍为 master,不是 agent 地址
credential.Secp256k1.signature65 字节 JSON 数组 r||s||vv ∈ {27,28}(与 eth_signTypedData_v4 / ethers 输出一致)
method(JSON-RPC 外层)必须等于 action 变体名,否则 -32602

鉴权逻辑:recover 地址 == signer → master 直签;否则在 signeragents 列表中查找 → agent 代签(须未过期且角色满足)。详见 交易与账户 §5


4. User-Signed:注册 Agent

4.1 流程

  1. getAccount → 当前 nonce
  2. 构造 EIP-712 RegisterAgentzeptoChain="zepto-dev"roleMask=1 = Trader)。
  3. Master 钱包签名;domain.chainId = 钱包 EVM 链 ID。
  4. POST /api/v1/actionmethod=RegisterAgentenvelope.chain_id=42domain_chain_id=钱包链 ID。
  5. 成功后,用 agent 私钥 对后续 Trader Action 做 L1 签名

Typed data 与字段表见 write-actions §3.3

4.2 撤销 Agent

RevokeAgent 同为 User-Signed;见 write-actions §3.4


5. L1 通道:msgpack 与 digest

适用于除 User-Signed 三例外外的全部 Action(含 Agent 代签的 PlaceOrder 等)。

5.1 算法(5 步)

msgpack_bytes = rmp_serde::to_vec_named(action) // 禁止 JSON
connectionId = keccak256(msgpack_bytes || nonce.to_be_bytes(8))

domain = EIP712Domain(ZeptoSignTransaction, 1, domain_chain_id, 0x0)
// L1 须 domain_chain_id == chain_id(生产均为 42)
struct_hash = keccak256( typeHash(L1Action) || enc_string(network_tag) || connectionId )
digest = keccak256(0x19 || 0x01 || domain || struct_hash)

signature = secp256k1_sign(digest) → credential.Secp256k1.signature // r||s||v

逐步公式与 enc_string / enc_uint 定义见 write-actions §2.1交易与账户 §4.6

5.2 msgpack 编码规则(自研必守)

类型编码
Action enumexternally-tagged map{"PlaceOrder": {…}}
Address2020 字节 bin(非 hex 字符串)
Option::Nonemsgpack nil(JSON 省略字段 ≡ null
i128 / 整数msgpack 定长整数
Stringmsgpack str
nonce 拼接8 字节 大端 附在 msgpack 后参与 keccak256

使用 JSON 代替 msgpack 会导致 BadMasterSignature

5.3 PlaceOrder 请求骨架

{
"jsonrpc": "2.0",
"id": 1,
"method": "PlaceOrder",
"params": {
"envelope": {
"chain_id": 42,
"domain_chain_id": 42,
"action_version": 2,
"nonce": 0,
"signer": "0x1111222233334444555566667777888899990000",
"credential": { "Secp256k1": { "signature": ["...r||s...", 27] } },
"action": {
"PlaceOrder": {
"owner": "0x1111222233334444555566667777888899990000",
"symbol": "BTC-USDT",
"side": "Bid",
"limit_price": "97100.00",
"qty": "1.00000",
"tif": "Gtc",
"client_order_id": "mm-btc-001",
"reduce_only": false,
"expires_at_ms": null
}
}
}
}
}

Action 内数值均为 canonical decimal string,见 precision


6. txid 与 signing digest(勿混淆)

signing digesttxid(result.tx_hash
哈希keccak256(EIP-712)SHA-256
输入msgpack(action)+nonce, network_tagchain_id, domain_chain_id, action_version, nonce, signer, SHA256(msgpack(action))
用途验签公共交易标识

7. 常见错误

现象可能原因
ChainIdMismatchenvelope.chain_id ≠ 节点配置
BadMasterSignaturemsgpack 非 canonical、错 network_tag、错 nonce 拼接、错私钥、signature 非 r||s||v、ecrecover 失败
AgentNotRegistered① 未 RegisterAgent;② 更常见:签错通道 / digest 不一致(如对 SetMarginMode 做 typed data),recover 地址既不是 master 也不是已注册 agent——先查签名算法,勿仅当「未注册」
AgentExpiredagent 委托已过期
AgentRoleMissingagent 未授予 Trader(roleMask
MasterOnlyAction管理类 Action 不允许 agent 代签

8. 延伸阅读

主题文档
做市接入流程做市商对接指南
Action schema / 批量上限write-actions
Nonce / kept-reject做市商对接指南 §4 · 交易与账户 §4.3
raw i128 reasonprecision §5