Giter Club home page Giter Club logo

eip712-codegen's Introduction

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 = codeGen(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 eip712-codegen ./sampleTypes.js > YourTypesFile.sol

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

npx eip712-codegen ./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 (in particular, your entrypoint types are your user-facing security enforcement, 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.

eip712-codegen's People

Contributors

danfinlay avatar dawsbot avatar nic619 avatar robriks avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.