# 签署数据

### 使用 TokenPocket Extension 签署数据 <a href="#signing-data-with-metamask" id="signing-data-with-metamask"></a>

如果您想跳转到一些工作签名示例，[可以访问此存储库](https://github.com/danfinlay/js-eth-personal-sign-examples).

如果你想阅读这些方法的 JavaScript 实现，它们都可以在 npm 包[eth-sig-util 中找到](https://github.com/MetaMask/eth-sig-util).

### 介绍

TokenPocket Extension 目前有六种签名方法，我们目前的五种方法是：

* `eth_sign`
* `personal_sign`
* `signTypedData`（目前与 相同`signTypedData_v1`）
* `signTypedData_v1`
* `signTypedData_v3`
* `signTypedData_v4`

`eth_sign`是一种开放式签名方法，允许对任意散列进行签名，这意味着它可用于对交易或任何其他数据进行签名，使其具有危险的网络钓鱼风险。

出于这个原因，我们通常不鼓励在生产中使用这种方法。但是，一些应用程序出于易用性的考虑而使用此方法，因此我们支持它，以免破坏活动项目的工作流程。

最终，`personal_sign` [规范](https://github.com/ethereum/go-ethereum/pull/2940)被提议，它为数据添加了一个前缀，因此它不能模拟交易。我们还使此方法能够在 UTF-8 编码时显示人类可读的文本，使其成为站点登录的流行选择。

### 签署类型的数据 v1 <a href="#sign-typed-data-v1" id="sign-typed-data-v1"></a>

这个早期版本的规范缺乏一些后来的安全改进，通常应该被忽略以支持[signTypedData\_v3](#qian-shu-lei-xing-de-shu-ju-v3)。

也称为`signTypedData，`这种方法是原始的以状态通道为中心的签名方法。

该`signTypedData`系列有几个主要的设计考虑：

* 在链上验证便宜
* 还是有点可读性
* 难以钓鱼签名

如果链上可验证性成本对您来说是一个高优先级，您可以考虑使用它。

### 签署类型的数据 v3

该方法`signTypedData_v3`当前代表[EIP-712 规范的最新版本](https://eips.ethereum.org/EIPS/eip-712)，使其成为我们迄今为止签署成本低廉的链上数据的最安全方法。

### 签署类型的数据 v4 <a href="#sign-typed-data-v4" id="sign-typed-data-v4"></a>

该方法`signTypedData_v4`当前代表[EIP-712 规范的最新版本](https://eips.ethereum.org/EIPS/eip-712)，增加了对数组的支持，并对结构的编码方式进行了重大修复。

#### 符号类型数据消息参数 <a href="#sign-typed-data-message-parameters" id="sign-typed-data-message-parameters"></a>

`domain`：域或域签名很重要，因为它：

* 仅适用于特定网站/合约。
* 确保签名仅在预期有效的地方有效。
* 允许您拥有验证地址的唯一合约。
* 这是一组限制签名有效位置的信息。
* 这是有效性域。可以是合约、网址等。
* DApp 告诉你的具体需要放在这里。
* 确保您的签名不会与其他签名发生冲突。

`chainId`：chainId 告诉你你在哪个链上，这很重要，因为：

* 它确保在 Rinkeby 上的签名在另一条链上无效，例如以太坊主网。

`name`：这主要是出于 UX（用户体验）目的。

* 例如，作为用户，您正在使用 Ether Mail 应用程序并出现一个用于加密猫交换的对话框，由于签名上的名称，这会引起怀疑。

`verifyingContract`: 这是额外的保证。即使两个开发人员最终创建了一个同名的应用程序，他们也永远不会拥有相同的合约地址。

* 如果您不确定名称，这将显示负责消息验证的合约。
* 该字段也将采用 url。

`version`: 这告诉你当前版本的域对象。

`message`: 对你想要的结构完全开放。每个字段都是可选的。

下面是使用 TokenPocket Extension 签署类型数据的示例。参考[这里](https://github.com/danfinlay/js-eth-personal-sign-examples)

#### 例子 <a href="#example" id="example"></a>

{% tabs %}
{% tab title="HTML" %}

```html
<div>
  <h3>Sign Typed Data V4</h3>
  <button type="button" id="signTypedDataV4Button">sign typed data v4</button>
</div>
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
signTypedDataV4Button.addEventListener('click', function (event) {
  event.preventDefault();

  const msgParams = JSON.stringify({
    domain: {
      // Defining the chain aka Rinkeby testnet or Ethereum Main Net
      chainId: 1,
      // Give a user friendly name to the specific contract you are signing for.
      name: 'Ether Mail',
      // If name isn't enough add verifying contract to make sure you are establishing contracts with the proper entity
      verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
      // Just let's you know the latest version. Definitely make sure the field name is correct.
      version: '1',
    },

    // Defining the message signing data content.
    message: {
      /*
       - Anything you want. Just a JSON Blob that encodes the data you want to send
       - No required fields
       - This is DApp Specific
       - Be as explicit as possible when building out the message schema.
      */
      contents: 'Hello, Bob!',
      attachedMoneyInEth: 4.2,
      from: {
        name: 'Cow',
        wallets: [
          '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
          '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
        ],
      },
      to: [
        {
          name: 'Bob',
          wallets: [
            '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
            '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
            '0xB0B0b0b0b0b0B000000000000000000000000000',
          ],
        },
      ],
    },
    // Refers to the keys of the *types* object below.
    primaryType: 'Mail',
    types: {
      // TODO: Clarify if EIP712Domain refers to the domain the contract is hosted on
      EIP712Domain: [
        { name: 'name', type: 'string' },
        { name: 'version', type: 'string' },
        { name: 'chainId', type: 'uint256' },
        { name: 'verifyingContract', type: 'address' },
      ],
      // Not an EIP712Domain definition
      Group: [
        { name: 'name', type: 'string' },
        { name: 'members', type: 'Person[]' },
      ],
      // Refer to PrimaryType
      Mail: [
        { name: 'from', type: 'Person' },
        { name: 'to', type: 'Person[]' },
        { name: 'contents', type: 'string' },
      ],
      // Not an EIP712Domain definition
      Person: [
        { name: 'name', type: 'string' },
        { name: 'wallets', type: 'address[]' },
      ],
    },
  });

  var from = web3.eth.accounts[0];

  var params = [from, msgParams];
  var method = 'eth_signTypedData_v4';

  web3.currentProvider.sendAsync(
    {
      method,
      params,
      from,
    },
    function (err, result) {
      if (err) return console.dir(err);
      if (result.error) {
        alert(result.error.message);
      }
      if (result.error) return console.error('ERROR', result);
      console.log('TYPED SIGNED:' + JSON.stringify(result.result));

      const recovered = sigUtil.recoverTypedSignature_v4({
        data: JSON.parse(msgParams),
        sig: result.result,
      });

      if (
        ethUtil.toChecksumAddress(recovered) === ethUtil.toChecksumAddress(from)
      ) {
        alert('Successfully recovered signer as ' + from);
      } else {
        alert(
          'Failed to verify signer when comparing ' + result + ' to ' + from
        );
      }
    }
  );
});
```

{% endtab %}
{% endtabs %}
