Sender Wallet Developer Documentation
  • Guide
    • Introduction
    • Getting Started
    • Sign in Applications
      • Sign in Applications in Near
      • Sign in Applications in Ethereum
    • Access Accounts
      • Access Accounts in Near
      • Access Account in Ethereum
    • Send Transactions
      • Send Transactions in Near
      • Send Transactions in Ethereum
  • API Reference
    • Near
      • NEAR Provider API
      • Deprecated APIs
    • Ethereum
      • Sign Data
      • Ethereum Provider API
    • Ton
      • Mobile Dapp Provider
  • Best Practices
    • Define App's Icon
Powered by GitBook
On this page
  • Use eth_signTypedData_v4
  • Use eth_sign
  1. API Reference
  2. Ethereum

Sign Data

PreviousEthereumNextEthereum Provider API

Last updated 2 years ago

You can use the following RPC methods to request cryptographic signatures from users:

  • - Use this method to request the most human-readable signatures that are efficient to process on-chain. We recommend this for most use cases.

  • - Use this method for the easiest way to request human-readable signatures that don't need to be efficiently processed on-chain.

Use eth_signTypedData_v4

provides the most human-readable signatures that are efficient to process on-chain. It follows the specification to allow users to sign typed structured data that can be verified on-chain. It renders the structured data as usefully as possible to the user (for example, displaying known account names in place of addresses).

An eth_signTypedData_v4 payload uses a standard format of encoding structs, but has a different format for the top-level struct that is signed, which includes some metadata about the verifying contract to provide replay protection of these signatures between different contract instances.

We recommend using to generate and validate signatures. You can use to generate most of the Solidity required to verify these signatures on-chain. It currently doesn't generate the top-level struct verification code, so you must write that part manually.

CAUTION

Since the top-level struct type's name and the domain.name are presented to the user prominently in the confirmation, consider your contract name, the top-level struct name, and the struct keys to be a user-facing security interface. Ensure your contract is as readable as possible to the user.

Example

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

  const msgParams = JSON.stringify({
    domain: {
      // This defines the network, in this case, Mainnet.
      chainId: 1,
      // Give a user-friendly name to the specific contract you're signing for.
      name: 'Ether Mail',
      // Add a verifying contract to make sure you're establishing contracts with the proper entity.
      verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
      // This identifies the latest version.
      version: '1',
    },

    // This defines the message you're proposing the user to sign, is dapp-specific, and contains
    // anything you want. There are no required fields. Be as explicit as possible when building out
    // the message schema.
    message: {
      contents: 'Hello, Bob!',
      attachedMoneyInEth: 4.2,
      from: {
        name: 'Cow',
        wallets: [
          '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
          '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
        ],
      },
      to: [
        {
          name: 'Bob',
          wallets: [
            '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
            '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
            '0xB0B0b0b0b0b0B000000000000000000000000000',
          ],
        },
      ],
    },
    // This refers to the keys of the following types object.
    primaryType: 'Mail',
    types: {
      // This 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 = await web3.eth.getAccounts();

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

  web3.currentProvider.sendAsync(
    {
      method,
      params,
      from: from[0],
    },
    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
        );
      }
    }
  );
});
<h3>Sign typed data v4</h3>
<button type="button" id="signTypedDataV4Button">eth_signTypedData_v4</button>

Use eth_sign

IMPORTANT

  • Don't use this method to display binary data, because the user wouldn't be able to understand what they're agreeing to.

  • If using this method for a signature challenge, think about what would prevent a phisher from reusing the same challenge and impersonating your site. Add text referring to your domain, or the current time, so the user can easily verify if this challenge is legitimate.

Example

The following is an example of using eth_sign with Sender.

ethSignButton.addEventListener('click', async function (event) {
  event.preventDefault();
  const exampleMessage = 'Example `eth_sign` message.';

  try {
    const from = accounts[0];
    // For historical reasons, you must submit the message to sign in hex-encoded UTF-8.
    // This uses a Node.js-style buffer shim in the browser.
    const msg = `0x${Buffer.from(exampleMessage, 'utf8').toString('hex')}`;
    const sign = await sender.ethereum.request({
      method: 'eth_sign',
      params: [msg, from, 'Example password'],
    });

    personalSignResult.innerHTML = sign;
    personalSignVerify.disabled = false;
  } catch (err) {
    console.error(err);
    personalSign.innerHTML = `Error: ${err.message}`;
  }
});
<h3>Personal sign</h3>
<button type="button" id="personalSignButton">eth_sign</button>

is the easiest way to request human-readable signatures that don't need to be efficiently processed on-chain. It's often used for signature challenges that are authenticated on a web server, such as .

eth_sign
Sign-In with Ethereum
eth_signTypedData_v4
EIP-712
eth-sig-util
eip712-codegen
eth_signTypedData_v4
eth_sign