Developer (English)
  • Get Started
  • Wallet
    • ​Ready to start
    • Mobile SDK
      • iOS
      • Android
    • EOS MiniWallet SDK
      • iOS
      • Android
    • ​Pull up wallet with DeepLink
    • JS-SDK
    • EOS resource payment
    • Debug DApp
    • Clear Cache
  • Extension Wallet
    • Guide
      • Introduction
      • Getting Started
      • Common Terms
      • Initialize the DApp
      • Access account
      • Send transaction
    • API Reference
      • Ethereum Provider API
      • Tron Provider API
      • RPC API
      • Signing Data
  • QRCode Protocol
    • Dynamic QRCode
    • EVM network
    • TRON
    • EOSIO
    • Solana
    • BTC
  • TIP Protocol
  • Wallet Connect
  • Token
    • Token price display support
    • How to submit token
    • How to Submit a Token Logo
    • FAQ
  • DApp
    • How to Submit DApps
    • FAQ
  • Network
    • Blockchain Unique Identifier
    • Supported Chains
      • Transaction Data
    • New Blockchains
      • Lite add blockchain
      • Basic support introduction and demonstration
      • Adding Advanced blockchain
      • Adding custom blockchain
  • FAQ
Powered by GitBook
On this page
  • Introduction
  • Sign Typed Data v1
  • Sign Typed Data v3
  • Sign Typed Data v4
  1. Extension Wallet
  2. API Reference

Signing Data

PreviousRPC APINextQRCode Protocol

Last updated 2 years ago

Signing Data with TokenPocket Extension

If you’d like to jump to some working signature examples,

If you’d like to read our JavaScript implementations of these methods, they are all available in the npm package

Introduction

There are currently six signing methods in TokenPocket Extension, and you might wonder about the history of these methods. Studying the history of these methods yields some guiding lessons for the emergence of decentralized standards. Our current five methods are:

  • eth_sign

  • personal_sign

  • signTypedData(currently identical to signTypedData_v1)

  • signTypedData_v1

  • signTypedData_v3

  • signTypedData_v4

eth_sign is an open-ended signing method that allows signing an arbitrary hash, which means it can be used to sign transactions or any other data, making it a dangerous phishing risk.

For this reason, we make this method show the most frightening possible message to the user, and generally discourage using this method in production. However, some applications (usually admin panels internal to teams) use this method for the sake of its ease of use, and so we have continued to support it for the sake of not breaking the workflows of active projects.

Eventually, the personal_sign was proposed, which added a prefix to the data so it could not impersonate transactions. We also made this method able to display human-readable text when UTF-8 is encoded, making it a popular choice for site logins.

Sign Typed Data v1

This early version of the spec lacked some later security improvements, and should generally be neglected in favor of signTypedData_v3.

Also known as signTypedData, this method was the original state-channel-centric signing method.

The signTypedData family has a few major design considerations:

  • Cheap to verify on chain

  • Still somewhat human-readable

  • Hard to phish signatures

If on-chain verifiability cost is a high priority for you, you might want to consider it

Sign Typed Data v3

Sign Typed Data v4

Sign Typed Data Message Parameters

domain: The Domain or domain signature is important because it:

  • Will only be accepted for a specific website/contract.

  • Makes sure signatures are valid only where they are intended to be valid

  • Allows you have a unique contract that verifies the address

  • This is a bunch of information that restricts where the signature is valid

  • This is the domain of validity. Could be a contract, a URL, etc.

  • What needs to be put in here, specifically what the DApp tells you

  • Make sure your signature(s) don't collide with other signatures.

chainId:The chainId tells you what chain you're on and this is important because:

  • It makes sure signatures signed on Rinkeby are not valid on another chain, such as the Ethereum MainNet.

name:This is primarily for UX(User Experience) purposes.

  • For example, as a user, you're using an Ether Mail app and a dialog comes up for cryptokitties exchange, this would arouse suspicion due to what the name is on the signature.

verifyingContract: This is an extra layer of assurance. Even if two developers end up creating an app with the same name, they will never have the same contract address. (You can add another field salt but it's complete overkill and unnecessary)

  • If you are unsure of the name this will show the contract responsible for message verification.

  • This field will also take a URL.

version: This tells you the current version of the domain object.

message: Completely open to what you would like the structure of it to be. Every field is optional.

Example

<div>
  <h3>Sign Typed Data V4</h3>
  <button type="button" id="signTypedDataV4Button">sign typed data v4</button>
</div>
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
        );
      }
    }
  );
});

The method signTypedData_v3 currently represents the latest version of the , making it the most secure method for signing cheap-to-verify data on-chain that we have yet.

The method signTypedData_v4 currently represents the latest version of the , with added support for arrays and with a breaking fix for the way structs are encoded.

Below is an example of signing typed data with TokenPocket Extension. Reference

you can visit this repository
eth-sig-util
spec
EIP-712 spec
EIP-712 spec
here