跳到主要内容

加密调用 vs 明文调用

OXN 上每一笔交易和每一次 eth_call 要么是加密的、要么是明文的。这是客户端侧的选择,不是链侧的。链两种都接受。你应该理解两者,因为把本应加密的调用发成明文,是应用无意间泄漏数据的最常见方式。

各客户端的默认行为

客户端默认行为
ethers.js(未 wrap)明文。 Calldata 明文上链。
ethers.js + OXN 封装加密。 自动 X25519 + Deoxys-II 端到端。
viem明文。
viem + OXN 封装加密。
原始 JSON-RPC(eth_sendRawTransaction明文,除非你自己构造了加密信封。
直接用 MetaMask明文,直到你的 dApp 构造出加密交易。

规律:客户端侧的加密永远不会意外发生。 如果你没法指出是哪个具体的 wrapper 或 SDK 函数加密了这次调用,它就是以明文发出去的。

两种模式在链上的样子

明文调用: tx.data 是标准 ABI 编码——4 字节函数选择器加 ABI 编码的参数。读区块的人直接看到 transfer(0x…, 100)

加密调用: tx.data 是一个 CBOR 信封。首字节落在 0xa0–0xbf 区间(CBOR map major type)。信封包含调用者的临时 X25519 公钥、随机 nonce、Deoxys-II 密文。读区块的人无法提取函数选择器或参数。

你可以通过检查 tx.data 来验证一笔交易用的是哪种模式:

const tx = await provider.getTransaction(txHash);
const firstByte = parseInt(tx.data.slice(2, 4), 16);
const looksEncrypted = (firstByte & 0xe0) === 0xa0;

什么时候用哪一种

任何必须保密的场景都用加密。 这是 OXN 上大部分合约交互的默认。犹豫就加密。

用明文的场景:

  • 调用本身就是公开的(查询公开预言机、调用明文中继合约)。
  • 接收方合约不是机密合约、且读取 calldata 是预期行为。
  • 你在调试,想看链上真实字节。

从不应"意外"发送明文。 最常见的错误:从裸 ethers.js 初始化一个 Signer,忘了 wrap。交易照样成功,但敏感参数从此永远存在于公开区块里。

强制加密

import { ethers } from "ethers";
import { wrapEthersProvider, wrapEthersSigner } from "<oxn-ethers-wrapper>";

const raw = new ethers.JsonRpcProvider("https://rpc.bout.network");
const provider = wrapEthersProvider(raw);
const signer = wrapEthersSigner(new ethers.Wallet(PRIVATE_KEY, raw));

const contract = new ethers.Contract(addr, abi, signer);
await contract.transfer(recipient, amount); // 端到端加密

经过这个 wrapped signer 的每一次调用都是加密的。无需对每个函数 opt-in。

强制明文

不做 wrap,直接用裸 provider / signer:

const raw = new ethers.JsonRpcProvider("https://rpc.bout.network");
const signer = new ethers.Wallet(PRIVATE_KEY, raw); // 未 wrap
const contract = new ethers.Contract(addr, abi, signer);
await contract.publicMethod(...); // 明文

没有中间态。Wrapped signer 永远加密;裸 signer 永远明文。

常见 bug

"本地测试跑通了,但生产上泄漏了。" 本地 Hardhat network 是一个没有真实 enclave 的纯 EVM。任何"在 Hardhat network 上跑通"的测试对"你生产上的调用是不是加密的"没有任何证明力。集成测试必须打真实的 OXN 网络。

"我 wrap 了 provider,但忘了 signer。" wrapEthersProvider 只加密调用(eth_call);wrapEthersSigner 加密交易。绝大多数场景两者都需要。

"我用的库内部自己重建了一个 signer。" 有些库在内部用 mnemonic 自己创建 Wallet。即便你传进去的是 wrapped signer,库可能用自己的裸 signer。读一遍库源码,或者在集成测试里每笔交易之后确认 tx.data 看起来像 CBOR 信封。

下一步