Using Web3.js to Sign and Recover EIP-712 Typed Structured Data
Solidity - EIP-712 Typed Structured Data Hashing and Signing explains how smart contracts verify the signature of EIP-712. This article explains how to use Web3.js for EIP-712 signing. This article uses Web3.js version 4.1.1.
Sign
Browser Wallet
Web3.js can use the following functions to sign EIP-712:
- web3.eth.signTypedData
- web3.currentProvider.request
Browser wallets can use the above functions, but Web3.js does not have a private key signing method, so another library will be introduced later to handle it.
web3.eth.signTypedData
This function was added since 4.1.0
1 | web3.eth.signTypedData(address: string, typedData: Eip712TypedData): Promise<string> |
- address: Address of the signer.
- typedData: The content to sign, includes the domain, struct definition and message content of EIP-712. Please refer to the example below directly.
- Return: A Promise object, and the content is a signature.
Use the previous example:
1 | import "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; |
The corresponding Web3.js usage is as follows
1 | // Signer address, e.g. |
We will get a not spiltted signature. We can refer to the previous article Using Web3.js to Sign and Recover to handle it.
web3.currentProvider.request
This is a general function for calling RPC. In the older version of Web3.js, the above signTypedData is not available, so you can call the RPC method directly.
1 | web3.currentProvider.request(args: Web3APIPayload): Promise<string> |
- args: RPC content, refer to the example below.
- Return: A Promise object, and the content is the RPC execution result. The result here is the signature.
The first part of the above example is the same, just change the last line:
1 | const signature = await web3.eth.signTypedData(address, typedData); |
Change to
1 | const params = [address, typedData]; |
Private Key Wallet
If you want to use a private key wallet to sign, you can use the library provided by Metamask @metamask/eth-sig-util.
1 | signTypedData({ data: TypedMessage, privateKey: Buffer, version: SignTypedDataVersion }): string |
- data: Content to sign. The same as typedData above.
- privateKey: Private key, Buffer type.
- version: EIP-712 version.
- Return: signature.
After installation, you must first import the library
1 | import { signTypedData, SignTypedDataVersion } from '@metamask/eth-sig-util'; |
Then just change the last line
1 | const privatekey = '0x...'; |
Other Examples
struct array
1 | struct Mail { |
types and message change to the following
1 | const types = { |
Recover Signature
If you want to recover and verify the signature in the backend for login purposes, you can also use the @metamask/eth-sig-util package:
1 | recoverTypedSignature({ data: TypedMessage, signature: string, version: SignTypedDataVersion }): string |
- data: Content to sign. The same as typedData above.
- signature: Not splitted signature.
- version: EIP-712 version.
- Return: Signer address.
For example:
1 | import { recoverTypedSignature, SignTypedDataVersion } from '@metamask/eth-sig-util'; |
Conclusion
- The browser wallet uses
web3.eth.signTypedData
to sign if Web3.js is v4.1.0 or above. - The browser wallet uses
web3.currentProvider.request
to sign if Web3.js is old version. - Private key signing uses
signTypedData
of@metamask/eth-sig-util
to sign. - Use
recoverTypedSignature
of@metamask/eth-sig-util
to recover and verify the signature.
Further Reading
Solidity - EIP-712 Typed Structured Data Hashing and Signing
Using Ethers.js to Sign and Recover EIP-712 Typed Structured Data
Solidity - ecrecover
Using Web3.js to Sign and Recover