A utility for generating Solidity code for recovering signatures using the EIP-712 signTypedData schema.

Overview

EIP 712 Codegen

EIP 712: Sign Typed Data as of 2022 is the most human-readable way of getting signatures from user that are easily parsed into solidity structs.

The documentation has not always been the greatest, and in particular I think this method has failed to catch on because writing the verification code is a huge pain.

Well, no more. This module will generate basically all the solidity you need to let users basically sign structs and then mostly just think about the structs you have signed in your code. This should really level up your ability to keep more user actions off-chain and gas-free.

Usage

Add this module to your project: npm i eip712-codegen -D or yarn add eip712-codegen -D.

As a module:

const codeGen = require('eip712-codegen');
const yourTypes = { primaryMessage, domain, entries, types };
const solidityFile = codGen(yourTypes);

As a module, we are exporting typescript definition files, which can help you get your types right in case the example type file isn't enough.

As a CLI tool:

You point it at a typeDef file (defined as a CommonJS module, as seen in sampleTypes.js), and it then prints out some solidity to the console. You can then pipe it into a file.

Examples:

npx eip-712gen ./sampleTypes.js >> YourTypesFile.sol

If you're using hardhat and their console.log feature, you can generate a logged version by adding log:

npx eip-712gen ./sampleTypes.js log >> YourTypesFile.sol

You'll then need to import this typefile into your contract, and inherit from EIP712Decoder.

pragma solidity ^0.8.13;
// SPDX-License-Identifier: MIT

import "./YourTypesFile.sol";
import "./caveat-enforcers/CaveatEnforcer.sol";

abstract contract Delegatable is EIP712Decoder {

You'll also need to include this one method that defines your DomainHash, which I'm leaving to you because it's pretty straightforward, you can copy paste this and change it:

  bytes32 public immutable domainHash;
  constructor (string memory contractName, string memory version) {
    domainHash = getEIP712DomainHash(contractName,version,block.chainid,address(this));
  }

  function getEIP712DomainHash(string memory contractName, string memory version, uint256 chainId, address verifyingContract) public pure returns (bytes32) {
    bytes memory encoded = abi.encode(
      EIP712DOMAIN_TYPEHASH,
      keccak256(bytes(contractName)),
      keccak256(bytes(version)),
      chainId,
      verifyingContract
    );
    return keccak256(encoded);
  }
}

There's one more thing you have to do, this part will require the most thinking. You'll have to write the method that verifies the top-level signatures. I have not written codegen for this yet, because I don't know which types you want to use as your entry points, and there are some design decisions that are up to you here, but here is a sample method for verifying a SignedDelegation as defined in our sampleTypes.js file:

  function verifyDelegationSignature (SignedDelegation memory signedDelegation) public view returns (address) {

    // Break out the struct that was signed:
    Delegation memory delegation = signedDelegation.delegation;

    // Get the top-level hash of that struct, as defined just below:
    bytes32 sigHash = getDelegationTypedDataHash(delegation);

    // The `recover` method comes from the codegen, and will be able to recover from this:
    address recoveredSignatureSigner = recover(sigHash, signedDelegation.signature);
    return recoveredSignatureSigner;
  }

  function getDelegationTypedDataHash(Delegation memory delegation) public view returns (bytes32) {
    bytes32 digest = keccak256(abi.encodePacked(
      "\x19\x01",

      // The domainHash is derived from your contract name and address above:
      domainHash,

      // This last part is calling one of the generated methods.
      // It must match the name of the struct that is the `primaryType` of this signature.
      GET_DELEGATION_PACKETHASH(delegation)
    ));
    return digest;
  }

From there, you should be good! This library is tested to work with eth_signTypedData_v4 as implemented in MetaMask. I have not yet tested it with ethers.js or other wallets, but there's a good chance it works for simple types, and a chance it works for arrays and structs as well.

You might also like...

The first place winning no-code platform for generating developer resume pages, designed for and submitted to the 2022 Tech Optimum Hackathon.

Genfolio Genfolio is a no-code platform for generating developer portfolios. A demo can be found on the project's devpost or on youtube. Our stack We

Dec 5, 2022

A utility for creating toggleable items with JavaScript. Inspired by bootstrap's toggle utility. Implemented in vanillaJS in a functional style.

LUX TOGGLE Demo: https://jesschampion.github.io/lux-toggle/ A utility for creating toggleable dom elements with JavaScript. Inspired by bootstrap's to

Oct 3, 2020

This is a fully functional DAO, a Web3 project made using Solidity, Hardhat, JS, Next.js, Openzeppelin, CSS, HTML, using the Rinkerby network!

My First DAO! This is made for a DAO-Tutorial via learnweb3.io This is a DAO, a decentralised autonomous organisation, essentially a more collective a

Jun 20, 2022

Code in Solidity like a PRO with Egor Gavrilov. Check out YouTube channel ▶️

Code in Solidity like a PRO with Egor Gavrilov. Check out YouTube channel ▶️

Code in Solidity like a PRO with Egor Gavrilov Check out YouTube channel youtube.com/EgorGavrilov Tutorials Perfect Solidity Stack It's easy to get st

Dec 19, 2022

A simple nodejs module which is wrapper around solc that allows you to compile Solidity code

A simple nodejs module which is wrapper around solc that allows you to compile Solidity code

Simple Solidity Compiler It's a simple nodejs module which is wrapper around solc that allows you to compile Solidity code and get the abi and bytecod

Feb 21, 2022

A technology stack solution using the AWS Serverless architecture.Atlas stack for building applications focused on generating value.

Atlas A technology stack solution using the AWS Serverless architecture.Atlas stack for building applications focused on generating value. Description

Dec 15, 2022

Solidity NFT whitelist contract example using MerkleTree.js for constructing merkle root and merkle proofs.

MerkleTree.js Solidity NFT Whitelist example Allow NFT minting only to whitelisted accounts by verifying merkle proof in Solidity contract. Merkle roo

Dec 29, 2022

Decentralized twitter using Solidity, Ethereum, hardhat, ethers, IPFS, Next.JS, TypeScript, TailwindCSS.

DWITTER: Decentralized Twitter Check out the deployed version of this app at https://dwtr.wajeshubham.in Transactions on Ethereum are slow. Therefore,

Sep 2, 2022

Introductory fullstack ethereum dapp using: solidity, hardhat, react.js, ethers.js

Intro to Fullstack Ethereum Development Check out deployed dapp here! (Make sure you're connected to the Rinkeby Testnet) This article will help you e

Dec 21, 2022
Comments
  • uint type other than uint256 would result in `GET_UINT*_PACKETHASH` function

    uint type other than uint256 would result in `GET_UINT*_PACKETHASH` function

    uint type other than uint256 like uint64 would result in generating GET_UINT64_PACKETHASH function like below:

    struct Example {
      uint8 a;
      uint256 b;
      uint64 c;
      bytes d;
    }
    
    function GET_EXAMPLE_PACKETHASH (Example memory _input) public pure returns (bytes32) {
        
        bytes memory encoded = abi.encode(
          Example_TYPEHASH,
          GET_UINT8_PACKETHASH(_input.a),
          _input.b,
          GET_UINT64_PACKETHASH(_input.c),
          keccak256(_input.d)
        );
        
        return keccak256(encoded);
    }
    

    Expected:

    struct Example {
      uint8 a;
      uint256 b;
      uint64 c;
      bytes d;
    }
    
    function GET_EXAMPLE_PACKETHASH (Example memory _input) public pure returns (bytes32) {
        
        bytes memory encoded = abi.encode(
          Example_TYPEHASH,
          _input.a,
          _input.b,
          _input.c,
          keccak256(_input.d)
        );
        
        return keccak256(encoded);
    }
    
    opened by NIC619 0
  • Encode `name` and `version` in EIP712Domain packet hash

    Encode `name` and `version` in EIP712Domain packet hash

    In the generated GET_EIP712DOMAIN_PACKETHASH function, name and version of EIP712Domain struct are of dynamic type (string), should they be encoded as the hash of their contents ?

    function GET_EIP712DOMAIN_PACKETHASH (EIP712Domain memory _input) public pure returns (bytes32) {
        
        bytes memory encoded = abi.encode(
          EIP712DOMAIN_TYPEHASH,
          _input.name,
          _input.version,
          _input.chainId,
          _input.verifyingContract
        );
        
        return keccak256(encoded);
    }
    

    Expected:

    function GET_EIP712DOMAIN_PACKETHASH (EIP712Domain memory _input) public pure returns (bytes32) {
        
        bytes memory encoded = abi.encode(
          EIP712DOMAIN_TYPEHASH,
          keccak256(bytes(_input.name)),
          keccak256(byes(_input.version)),
          _input.chainId,
          _input.verifyingContract
        );
        
        return keccak256(encoded);
    }
    
    opened by NIC619 0
  • Add generators for which types are

    Add generators for which types are "entry points"

    The EIP-712 signTypedData method requires a special form of type when a user is interacting with it. While this codegen generates MOST OF the code involved in complicated relationships of structs, it does not handle the entrypoint signature recovery. We should generate that too.

    Sample code for recovering a delegation:

      function verifyDelegationSignature (SignedDelegation memory signedDelegation) public view returns (address) {
        Delegation memory delegation = signedDelegation.delegation;
        bytes32 sigHash = getDelegationTypedDataHash(delegation);
        address recoveredSignatureSigner = recover(sigHash, signedDelegation.signature);
        return recoveredSignatureSigner;
      }
    
      function getDelegationTypedDataHash(Delegation memory delegation) public view returns (bytes32) {
        bytes32 digest = keccak256(abi.encodePacked(
          "\x19\x01",
          domainHash,
          GET_DELEGATION_PACKETHASH(delegation)
        ));
        return digest;
      }
    
    opened by danfinlay 0
Owner
Dan Finlay
Dan Finlay
Fullstack Dynamic NFT Mini Game built using 💎 Diamond Standard [EIP 2535] 🏃‍♀️Players can use Hero NFT to battle against Thanos ⚔ Heroes can be Healed by staking their NFT 🛡

?? Fullstack Dynamic NFT Mini Game ?? ?? Using Diamond Standard Play On ?? ?? ⏩ http://diamond-dapp.vercel.app/ Project Description ?? Fullstack Dynam

Shiva Shanmuganathan 21 Dec 23, 2022
First blockchain explorer to navigate and visualize EIP-4844 blobs

Blobscan Blobscan is the first blockchain explorer that helps to navigate and visualize those EIP-4844 blobs, providing the necessary infrastructure t

Blossom Labs 6 Dec 29, 2022
A simple CLI to generate a starter schema for keystone-6 from a pre-existing prisma schema.

Prisma2Keystone A tool for converting prisma schema to keystone schema typescript This is a proof of concept. More work is needed Usage npx prisma2key

Brook Mezgebu 17 Dec 17, 2022
A hardhat solidity template with necessary libraries that support to develop, compile, test, deploy, upgrade, verify solidity smart contract

solidity-hardhat-template A solidity hardhat template with necessary libraries that support to develop, compile, test, deploy, upgrade, verify solidit

ChimGoKien 4 Oct 16, 2022
A professional truffle solidity template with all necessary libraries that support developer to develop, debug, test, deploy solidity smart contract

solidity-truffle-template A professional truffle solidity template with necessary libraries that support to develop, compile, test, deploy, upgrade, v

ChimGoKien 6 Nov 4, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Utility for generating preview images of StarCraft: Brood War and Remastered maps

bwpreview Utility for generating preview images of StarCraft: Brood War and Remastered maps (.scm and .scx files). All of the actual work of parsing m

Michiel Sikma 5 Oct 14, 2022
Password Generator - A fast, simple and powerful open-source utility tool for generating strong, unique and random passwords

A fast, simple and powerful open-source utility tool for generating strong, unique and random passwords. Password Generator is free to use as a secure password generator on any computer, phone, or tablet.

Sebastien Rousseau 11 Aug 3, 2022