Scaling Web3 with SignTypedData

Dan Finlay
MetaMask
Published in
3 min readOct 24, 2017

Please note: This is a very early stage feature, and the exact implementation may be subject to change! Do not use this method for production applications that you’re not able to update should the API change in the future!

There are a wide array of ways that Ethereum plans to scale, and it’s a favorite topic of blockchain fans, because the scalability of the blockchain is a hard technical limit on how useful it can become.

One of the easiest ways you can start scaling your application on Ethereum today, without waiting for any other technology to be available, is to construct mechanisms that allow users to sign state changes that aren’t always submitted to the blockchain, but can be if needed, like a state channel. To make a working state channel today, there’s no easier option than to take advantage of MetaMask’s new signTypedData method.

Originally proposed in EIP 712 by Leonid Logvinov of 0x, and then implemented for MetaMask by Sergey Ukustov of Machimony. This new method makes it easier than ever to create applications involving user signatures that:

  • Represent structured data.
  • Are human readable.
  • Cannot impersonate Ethereum transactions.
  • Are cheap to compute on-chain.

In this article, you’ll learn to show the MetaMask user something like this:

Structured data user prompts that are cheap to compute on-chain? No way!

The API is simple, and will be even simpler once it has been deployed in new versions of EthJS and Web3.js. In the meanwhile, using it exposes you to the lowest-level API that MetaMask gives you: The Ethereum Provider.

You can find this code live online on github here.

// A JS library for recovering signatures:
const sigUtil = require('eth-sig-util')
const msgParams = [
{
type: 'string', // Any valid solidity type
name: 'Message', // Any string label you want
value: 'Hi, Alice!' // The value to sign
},
{
type: 'uint32',
name: 'A number',
value: '1337'
}
]
// Get the current account:web3.eth.getAccounts(function (err, accounts) { if (!accounts) return signMsg(msgParams, accounts[0])})function signMsg(msgParams, from) { web3.currentProvider.sendAsync({
method: 'eth_signTypedData',
params: [msgParams, from],
from: from,
}, function (err, result) {
if (err) return console.error(err)
if (result.error) {
return console.error(result.error.message)
}
const recovered = sigUtil.recoverTypedSignature({
data: msgParams,
sig: result.result
})
if (recovered === from ) {
alert('Recovered signer: ' + from)
} else {
alert('Failed to verify signer, got: ' + result)
}
})
}

As you can see, in this we:

  • Imported the signature recovery library eth-sig-util.
  • Assembled parameters for the method.
  • Retrieved the current user’s address from the web3 API.
  • Asked the user to sign those parameters.
  • Using the parameters and the signature, we were able to verify this signature came from their address (and only their address!).

Not only can you verify this data with JavaScript, you can also verify it in Solidity. Here is an example of verifying one of these signatures in Solidity. This can be useful for writing code for closing a state channel.

I hope this has been useful to you, let us know if you have any questions, and if you create any sample examples you’d like to share!

--

--

Dan Finlay
MetaMask

Decentralized web developer at ConsenSys working on MetaMask, with a background in comedy, writing, and teaching.