@ethereum-sourcify/clear-signing

中文文档
0.3.1发布于 2026/10/29MITTypeScriptESM + CJS构建来源已验证近 30 天下载 8452

用于人类可读交易预览的清晰签名库

中文使用文档
文档目录18 节
  1. 钱包整合指南
  2. 安装
  3. 快速启动
  4. API 参考
  5. format(tx, opts?)
  6. formatTypedData(typedData, opts?)
  7. formatEip5792Batch(batch, opts?)
  8. FormatOptions
  9. ExternalDataProvider
  10. 描述来源
  11. 证明(ERC-8176)
  12. 信任的令牌列表
  13. 显示模式
  14. 批量显示模式
  15. 已知的局限性——EIP-712指数覆盖率
  16. 发展
  17. 相关
  18. 许可证

@etereum-surcify/ clear- signing (中文(简体) )

引用类型脚本执行 ERC-7730:结构化数据清晰签名格式。 。 。 .

这个库将原始交易 calldata和EIP-712打出的数据转换为人可读的显示模型,使钱包能够准确显示用户的签名内容.

设计可跳入钱包代码库 :

  • 运行在现代浏览器上,Node.js (≥22),和回放原生(ESM + CJS).
  • 两个运行时间依赖: @noble/hashes 财务报告和审定财务报表 @noble/curves。 。 。 .
  • 纯格式化:没有 RPC 客户端, 没有令牌/ 链/ ENS 获取; 外部数据通过 : ExternalDataProvider。 。 。 .
  • 没有内部缓存 : 调用者在获取描述和索引时控制 .

钱包整合指南

融入钱包? 见 钱包整合指南。 。 。 .

安装

npm install @ethereum-sourcify/clear-signing

快速启动

建议的模式:在应用程序启动时获取登记索引,并传递给每个 format() 编号 : formatTypedData() 电话 库不会在内部缓存取来索引——没有索引,每个格式调用再fetches.

import {
  format,
  fetchPrebuiltRegistryIndex,
} from "@ethereum-sourcify/clear-signing";

// At app startup — fetch once, keep in memory.
const index = await fetchPrebuiltRegistryIndex();
const baseOpts = {
  descriptorResolverOptions: { type: "github" as const, index },
  externalDataProvider: {
    resolveToken: async (chainId, address) => {
      // return token metadata from your wallet's token list
      // or call the ERC-20 methods on-chain
      return { name: "Tether USD", symbol: "USDT", decimals: 6 };
    },
  },
};

// Reuse on every format call — no re-fetching of the index.
const result = await format(
  {
    chainId: 1,
    to: "0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT
    data:
      "0x095ea7b3" +
      "0000000000000000000000001234567890abcdef1234567890abcdef12345678" + // spender
      "00000000000000000000000000000000000000000000000000000000000f4240", // value
  },
  baseOpts,
);

console.log(result.intent); // "Approve"
console.log(result.fields); // [{ label: "Spender", value: "0x1234..." }, { label: "Amount", value: "1 USDT" }]
console.log(result.interpolatedIntent); // "Approve 1 USDT to 0x1234..."

如果你省略 index (或 descriptorResolverOptions 完全如此, format() 仍然有效——它只是收集每个电话的预设索引.

API 参考

format(tx, opts?)

将单个交易的调用数据格式化为 DisplayModel。通过链和合同地址确定一个ERC-7730描述符,解码调用数据,并制作字段。 跌回一个 rawCalldataFallback 当没有描述符匹配时.

async function format(
  tx: Transaction,
  opts?: FormatOptions,
): Promise<DisplayModel>;
interface Transaction {
  chainId: number;
  to: string;
  data: string; // calldata as hex string
  value?: bigint;
  from?: string;
}

formatTypedData(typedData, opts?)

将 EIP-712 输入的数据电文格式化为 DisplayModel通过域链和核查合同,确定一个ERC-7730描述符,与主类型匹配 encodeType,并制作地块。 要求数 chainId 财务报告和审定财务报表 verifyingContract 在域内.

async function formatTypedData(
  typedData: TypedData,
  opts?: FormatOptions,
): Promise<DisplayModel>;
interface TypedData {
  account: string; // signer address
  types: Record<string, TypeMember[]>;
  primaryType: string;
  domain: TypedDataDomain;
  message: Record<string, unknown>;
}

formatEip5792Batch(batch, opts?)

格式化为 EIP-5792 信息技术 批次调用为a BatchDisplayModel中,每个调用都通过 format()。批量级别 interpolatedIntent 将所有个人意图与 " 和 " 合并,具体方式如下: ERC-7730 (英语)。 。 。 .

async function formatEip5792Batch(
  batch: Eip5792Batch,
  opts?: FormatOptions,
): Promise<BatchDisplayModel>;
interface Eip5792Batch {
  from?: string;
  chainId: number;
  calls: Eip5792Call[];
}

interface Eip5792Call {
  to?: string;
  data?: string;
  value?: bigint;
}

FormatOptions

interface FormatOptions {
  /**
   * Wallets should provide an object with async methods to resolve
   * external data like ENS names, token metadata, and NFT collection
   * names. The provided functions may use RPC calls or fetch data
   * from internal sources. This allows the library to remain
   * agnostic about how this data is fetched. If absent, the library
   * will fall back to raw formats for the corresponding fields.
   */
  externalDataProvider?: ExternalDataProvider;

  /**
   * Controls where descriptors are fetched from, and optionally carries a
   * `trustedTokens` list (see below). Defaults to the GitHub registry when
   * omitted.
   */
  descriptorResolverOptions?: GitHubResolverOptions | CustomResolverOptions;
}

ExternalDataProvider

图书馆将所有外部数据解析到钱包中 。 钱包可能使用 RPC 调用来解决数据 。 见 src/types.ts 用于完整返回类型定义(例如:. TokenResult, (中文(简体) ), ChainInfoResult(见a/c.5/49/70,附件).

interface ExternalDataProvider {
  /**
   * Raw chain access for checks the library performs itself. Required when an AttestationOptions policy
   * is set: the ERC-8176 revocation check reads the EAS contract on Ethereum
   * mainnet.
   */
  chainClient?: ChainClient;

  /**
   * Resolution for addressName formats. The wallet should verify whether the
   * address matches any of the provided accepted types (e.g., "eoa", "contract", ...)
   * if able to. If none of the types match, set typeMatch to false so the library
   * can include a warning in the DisplayModel. When acceptedTypes is absent, the
   * descriptor has no type constraint and typeMatch: true can be returned safely.
   */
  resolveLocalName?: (
    address: string,
    acceptedTypes?: DescriptorAddressType[],
  ) => Promise<AddressNameResult | null>;
  /**
   * Resolution for addressName formats. The wallet should verify whether the
   * address matches any of the provided accepted types (e.g., "eoa", "contract", ...)
   * if able to. If none of the types match, set typeMatch to false so the library
   * can include a warning in the DisplayModel. When acceptedTypes is absent, the
   * descriptor has no type constraint and typeMatch: true can be returned safely.
   */
  resolveEnsName?: (
    address: string,
    acceptedTypes?: DescriptorAddressType[],
  ) => Promise<AddressNameResult | null>;

  /** Resolution for tokenAmount formats. */
  resolveToken?: (
    chainId: number,
    tokenAddress: string,
  ) => Promise<TokenResult | null>;

  /** Resolution for nftName formats. */
  resolveNftCollectionName?: (
    chainId: number,
    collectionAddress: string,
  ) => Promise<NftCollectionNameResult | null>;

  /** Resolution for date format with blockheight encoding. */
  resolveBlockTimestamp?: (
    chainId: number,
    blockHeight: bigint,
  ) => Promise<BlockTimestampResult | null>;

  /** Resolution for chainId and amount formats. */
  resolveChainInfo?: (chainId: number) => Promise<ChainInfoResult | null>;

  /**
   * Decryption for fields carrying an `encryption` annotation. Optional and
   * scheme-specific. Return `null` when the value cannot be decrypted — the
   * field then renders the descriptor's `fallbackLabel`. See DECRYPTION.md.
   */
  resolveDecryptedValue?: (
    chainId: number,
    encryptedValue: string,
    params: {
      scheme: DescriptorFieldEncryptionScheme;
      contractAddress?: string;
    },
  ) => Promise<DecryptedValueResult | null>;
}

interface ChainClient {
  /** Performs eth_call against `chainId` and returns the 0x-hex return data. */
  call: (
    chainId: number,
    request: { to: string; data: string },
  ) => Promise<string>;
}

描述来源

描述从 明确签名的登记册 默认在 GitHub 上。 见 快速启动 用于推荐的预选模式.

GitHub 注册( 默认)

过 githubSource 改为 fetchPrebuiltRegistryIndex 和比对 descriptorResolverOptions数字 :

const index = await fetchPrebuiltRegistryIndex(source);
const opts = {
  descriptorResolverOptions: {
    type: "github" as const,
    githubSource: {
      repo: "ethereum/clear-signing-erc7730-registry", // default
      ref: "master", // default
    },
    index,
  },
};

从描述文件构建索引

如果预设的索引缺失,或者您正在使用一个没有公布的分叉,请自己走入登记册 createGitHubRegistryIndex()。它的速度要慢得多(每个描述文件一个抓取对预建索引的两个),所以保留它用于设置时间.

文件系统解析器( 只有节点)

对于节点中捆绑的描述符或测试,从本地目录中构建自己的索引并加载描述符JSON文件. 文件系统解析器生活在一个仅节点的子路径导出中, 因此它不会被浏览器捆绑 :

import { format } from "@ethereum-sourcify/clear-signing";
import { createFilesystemResolver } from "@ethereum-sourcify/clear-signing/filesystem";
import type { RegistryIndex } from "@ethereum-sourcify/clear-signing";

const index: RegistryIndex = {
  calldataIndex: {
    "eip155:1:0xdac17f958d2ee523a2206206994597c13d831ec7":
      "path/to/descriptor.json",
  },
  typedDataIndex: {},
};

const result = await format(tx, {
  descriptorResolverOptions: {
    type: "custom",
    resolver: createFilesystemResolver({
      index,
      descriptorDirectory: "./descriptors",
    }),
  },
});

自定义解析器

{ type: "custom", resolver } 接受任何匹配对象 DescriptorResolver 形状,因此可以插入任意描述源(在映射图中,自定义的 HTTP 端点,.):

import type { DescriptorResolver } from "@ethereum-sourcify/clear-signing";

const resolver: DescriptorResolver = {
  index,
  fetchDescriptor: async (path) => {
    /* return parsed descriptor for `path` */
  },
};

const result = await format(tx, {
  descriptorResolverOptions: { type: "custom", resolver },
});

证明(ERC-8176)

描述符控制用户在签名前所看到的. 钱包不能使用未经审查的描述符 . ERC-8176 (中文(简体) ) 增加一个审查层:审计员用一个 埃及 脱链证明。 登记册将证明文件存放在描述器旁边,单位为 registry/<project>/sigs/登记册 auditors/ 目录列出审计员和审计准则.

设定 attestations 启用此检查的政策。 只有在您所信任的审计员之一有有效证明时,图书馆才接受描述文件:

const result = await format(tx, {
  descriptorResolverOptions: {
    type: "github",
    index,
    attestations: {
      // Auditor addresses your wallet trusts — see the registry's auditors/ directory.
      trustedAttesters: ["0x3846c3A30E62075Fa916216b35EF04B8F53931f6"],
    },
  },
  externalDataProvider: {
    // Required when `attestations` is set. The library uses this raw eth_call
    // access to read the revocation state from the EAS contract on Ethereum
    // mainnet. See GUIDE.md.
    chainClient: {
      call: async (chainId, { to, data }) => rpcEthCall(chainId, to, data),
    },
  },
});

图书馆对每份证明进行离线核查(schema、descriptor hash、过期、签名、UID)。 然后它读取撤销状态 通过 externalDataProvider.chainClient当没有可信证明有效时,结果包含 NO_TRUSTED_ATTESTATION 警告,对于调用数据 rawCalldataFallback。 。 。 .

没有 attestations 政策,图书馆使用登记册描述符,无需任何审查检查。 只用这个模式进行测试.

注释:

  • 政策需要 externalDataProvider.chainClient,而自定义解析器必须执行 DescriptorResolver.fetchAttestation。否则,每门分辨率都会失败 ATTESTATION_OPTIONS_INCOMPLETE。 。 。 .
  • 捆绑的可信任的脚本描述符( E)trustedTokens)没有入门.
  • 只支持带有EAA签名的EAS出链证明(第2版).

信任的令牌列表

登记处不能为每个标志持有描述符。 仍然使ERC-20和ERC-721的平坦互动(transfer, (中文(简体) ), approve, (中文(简体) ), transferFrom, (中文(简体) ), safeTransferFrom, (中文(简体) ), setApprovalForAll),添加一个 trustedTokens 列表为 descriptorResolverOptions地图 chainId → tokenAddress → standard (处理小写或EIP-55复验)。 何时 无登记描述符解析 对于交易合同,图书馆在上面查找;如果列出,交易来自 捆绑 ERC-20 / ERC-721 模板描述符 而不是回到原始的呼叫数据。 登记说明总是优先.

import type { TrustedTokens } from "@ethereum-sourcify/clear-signing";

const trustedTokens: TrustedTokens = {
  1: {
    "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "erc20", // USDC
    "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d": "erc721", // BAYC
  },
};

const result = await format(tx, {
  descriptorResolverOptions: { type: "github", index, trustedTokens },
});

信任完全委托给钱包。 图书馆从来不决定哪些合同值得信赖.

显示模式

所有格式函数返回 a DisplayModel数字 :

/**
 * The complete display model produced by the library.
 *
 * According to ERC-7730, wallets have two display options:
 *   1. Show `intent` as an explanation what the contract call does, and
 *      `fields` as a list of labeled values representing the calldata parameters.
 *   2. Show `interpolatedIntent` as a short string presentation of intent and fields,
 *      which already has formatted field values embedded in it — in this case
 *      `fields` can be omitted or shown as supplementary detail.
 *
 * When interpolation fails or is not defined, wallets should fall back to Option 1.
 */
interface DisplayModel {
  /**
   * The intent from the resolved descriptor, representing a short
   * description of the operation, e.g. "Approve token spending".
   * Two possible forms:
   *   - A simple human-readable string
   *   - A list of human-readable key-value pairs
   */
  intent?: string | Record<string, string>;

  /**
   * Ordered list of fields to show to the user,
   * formatted according to their field format specification.
   */
  fields?: (DisplayField | DisplayFieldGroup)[];

  /**
   * Full sentence with formatted field values interpolated in, e.g.
   * "Approve USDC spending up to 1,000 USDC for Uniswap V3".
   * Absent when the descriptor does not define an interpolatedIntent,
   * or when interpolation fails.
   */
  interpolatedIntent?: string;

  /**
   * Additional metadata directly from the resolved descriptor.
   * Wallets may choose to display these items to provide additional
   * context about the contract being interacted with.
   */
  metadata?: {
    owner?: string;
    contractName?: string;
    info?: { deploymentDate?: string; url?: string };
  };

  /**
   * Raw calldata fallback when no descriptor matched or the descriptor was faulty.
   * Only present for calldata formatting — not applicable to EIP-712 typed data.
   */
  rawCalldataFallback?: RawCalldataFallback;

  /**
   * Warnings providing additional context, e.g. why
   * interpolation failed.
   */
  warnings?: Warning[];
}

批量显示模式

formatEip5792Batch 返回 a BatchDisplayModel数字 :

/**
 * The `callDisplays` array has the same order as the input `calls`.
 * The batch `interpolatedIntent` joins all individual intents with " and ".
 */
interface BatchDisplayModel {
  interpolatedIntent?: string;
  warnings?: Warning[];
  callDisplays: DisplayModel[];
}

见 src/types.ts 用于完整类型定义.

已知的局限性——EIP-712指数覆盖率

GitHub 索引只显示密钥 EIP-712 描述符 context.eip712.deployments通过下列方式绑定的说明 context.eip712.domain 或者说 context.eip712.domainSeparator 无法预索引.

发展

npm install        # Install dependencies
npm run build      # Compile to dist/
npm test           # Run tests
npm run test:watch # Watch mode

许可证

麻省理工学院

版本与发布记录

@ethereum-sourcify/clear-signing 共发布 16 个版本,首次发布于 2026/05/12;过去 12 个月发布了 16 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.3.1latest2026/10/2915 天前
0.3.02026/10/2024 天前
0.2.22026/07/293 个月前
0.2.12026/06/224 个月前
0.2.02026/06/045 个月前
0.1.102026/06/015 个月前

关于 @ethereum-sourcify/clear-signing 的常见问题

@ethereum-sourcify/clear-signing 是什么?

用于人类可读交易预览的清晰签名库

如何安装 @ethereum-sourcify/clear-signing?

在项目目录运行 npm install @ethereum-sourcify/clear-signing,或使用 pnpm add / yarn add / bun add。

@ethereum-sourcify/clear-signing 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@ethereum-sourcify/clear-signing 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@ethereum-sourcify/clear-signing 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@ethereum-sourcify/clear-signing 可以商用吗?

@ethereum-sourcify/clear-signing 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@ethereum-sourcify/clear-signing 的下载量有多少?

根据 npm 官方下载统计,@ethereum-sourcify/clear-signing 在 2026/10/14 – 2026/11/12 这 30 天内被下载 8,452 次,日均约 282 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@ethereum-sourcify/clear-signing 还在维护吗?

最新版本 0.3.1 发布于 2026/10/29(15 天前);至今共发布 16 个版本,其中过去 12 个月发布了 16 个;首次发布于 2026/05/12。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。