You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让MetaMask的eth_signTypedData_v4以可读格式显示日期与价格

问题描述

使用eth_signTypedData_v4方法签署链下NFT挂单请求时,合约要求价格与日期值以uint256类型传入,但MetaMask向用户展示签名消息时,会将这些值显示为原始数字(比如wei值、时间戳),希望能将这些数字转换为更易读的格式,例如价格以ETH单位展示、日期转换为易懂的日期格式。

当前签名请求代码如下:

const metamaskProvider = new Web3Provider(window.ethereum);
// Get the signer and account address
const signer = metamaskProvider.getSigner();
const marketPlaceContractName = "NFTMarketplace";
const listingDomain = {
  name: marketPlaceContractName,
  version: "1",
  chainId: chainId, // or whatever chain ID you're using
  verifyingContract: marketPlaceAddress, // address of the contract
};

const listingTypes = {
  NftListing: [
    { name: "seller", type: "address" },
    { name: "nftAddress", type: "address" },
    { name: "nftId", type: "uint256" },
    { name: "startPrice", type: "uint256" },
    { name: "endPrice", type: "uint256" },
    { name: "startedAt", type: "uint256" },
    { name: "duration", type: "uint256" },
  ],
};

const listing = {
  seller: account,
  nftAddress: process.env.REACT_APP_CONTRACT_ADDRESS,
  nftId: nftId,
  startPrice: BigNumber.from(parseEther("0.02")).toString(),
  endPrice: BigNumber.from(parseEther("0.01")).toString(),
  startedAt: timestampBefore,
  duration: 5 * 60,
};

const listSignature = await signer._signTypedData(
  listingDomain,
  listingTypes,
  listing
);
解决方案

MetaMask支持EIP-712的扩展display属性,可以在定义typed data的字段时,为uint256类型的价格、日期字段添加自定义展示格式,不会影响签名的哈希计算(合约验证签名逻辑无需改动),仅在用户签名弹窗中显示易读的转换后值。

具体实现步骤:

  1. 价格字段:将wei值转换为ETH单位的字符串,添加到字段的display属性中
  2. 日期/时长字段:将时间戳转换为ISO日期格式,时长转换为分钟/小时等易读文本,添加到display属性中

修改后的代码示例

const metamaskProvider = new Web3Provider(window.ethereum);
const signer = metamaskProvider.getSigner();
const marketPlaceContractName = "NFTMarketplace";
const listingDomain = {
  name: marketPlaceContractName,
  version: "1",
  chainId: chainId,
  verifyingContract: marketPlaceAddress,
};

// 计算易读的展示值
const ethStartPrice = "0.02";
const ethEndPrice = "0.01";
const startPriceWei = BigNumber.from(parseEther(ethStartPrice)).toString();
const endPriceWei = BigNumber.from(parseEther(ethEndPrice)).toString();
// 将时间戳转换为ISO日期字符串
const startedAtDate = new Date(timestampBefore * 1000).toISOString();
// 将秒数转换为分钟文本
const durationText = `${Math.floor(duration / 60)}分钟`;

const listingTypes = {
  NftListing: [
    { name: "seller", type: "address" },
    { name: "nftAddress", type: "address" },
    { name: "nftId", type: "uint256" },
    { 
      name: "startPrice", 
      type: "uint256",
      // 添加价格的展示格式
      display: {
        type: "string",
        value: `${ethStartPrice} ETH`
      }
    },
    { 
      name: "endPrice", 
      type: "uint256",
      display: {
        type: "string",
        value: `${ethEndPrice} ETH`
      }
    },
    { 
      name: "startedAt", 
      type: "uint256",
      // 添加日期的展示格式(MetaMask会自动解析为友好日期)
      display: {
        type: "date-time",
        value: startedAtDate
      }
    },
    { 
      name: "duration", 
      type: "uint256",
      // 添加时长的展示文本
      display: {
        type: "string",
        value: durationText
      }
    },
  ],
};

const listing = {
  seller: account,
  nftAddress: process.env.REACT_APP_CONTRACT_ADDRESS,
  nftId: nftId,
  startPrice: startPriceWei,
  endPrice: endPriceWei,
  startedAt: timestampBefore,
  duration: 5 * 60,
};

const listSignature = await signer._signTypedData(
  listingDomain,
  listingTypes,
  listing
);

关键说明

  • display属性是MetaMask等主流钱包支持的EIP-712扩展,不会改变签名的核心逻辑,合约端仍可正常验证uint256类型的原始值
  • 对于日期字段,使用display.type: "date-time"时,MetaMask会自动将ISO字符串转换为用户本地时区的友好日期格式
  • 所有展示值仅用于用户界面显示,签名哈希计算只依赖字段的name和type以及原始uint256值

内容的提问来源于stack exchange,提问作者Mohammed Abo-zaid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 20:37:43