no-std eip712

tool to generate EIP-712 compatible Solidity

1 unstable release

0.1.0 Mar 10, 2022


Used in eip712-cli

MPL-2.0 license

83KB
2K SLoC

eip712

Generates Solidity code to verify EIP-712 style signatures.

Usage

First, create an abstract contract implementing the functionality you want:

// SPDX-License-Identifier: CC0-1.0

pragma solidity ^0.8.11;

abstract contract NameRegistry {
    mapping (string => address) public nameToAddress;
    mapping (address => string) public addressToName;

    // This `claim` function implements the functionality you want to expose
    // via an EIP-712 signature.
    //
    // Importantly, the first argument must be the sender's address, and
    // the function must be internal.
    function claim(address sender, string memory name) internal {
        require(bytes(addressToName[sender]).length == 0, "address already registered");
        require(nameToAddress[name] == address(0), "name already registered");

        addressToName[sender] = name;
        nameToAddress[name] = sender;
    }

    // You can optionally expose your functionality using `msg.sender`.
    function claim(string memory name) external {
        claim(msg.sender, name);
    }

    // Finally, you should declare an abstract function that accepts a signature.
    //
    // The implementation will be generated for you.
    function claim(string memory name, uint8 v, bytes32 r, bytes32 s) external virtual;
}

On the Command Line

Install eip712-cli:

$ cargo install eip712-cli

Then run it with:

$ eip712 \
    --base NameRegistry \
    --signing-domain NameRegistry \
    --version 1 \
    --output /tmp/output.sol \
    NameRegistry.json

As a Library

For advanced uses, this crate can be used as a library from Rust or JavaScript.

Rust

use eip712::Eip712;

use std::io::Write;

fn main() {
    // Read the ABI file (normally generated by `solc`.)
    let abi = include_str!("NameRegistry.json");

    let mut output = String::new();

    // Configure and run the generator.
    Eip712::<()>::new("NameRegistry")       // Name of the base contract.
        .signing_domain("NameRegistry")     // Name for the EIP-712 domain.
        .version("1")                       // Contract version.
        .read_str(abi)
        .unwrap()
        .generate(&mut output)
        .unwrap();

    std::io::stdout().write_all(output.as_bytes()).unwrap();
}

JavaScript

import { default as eip712, Eip712 } from './eip712.js';

async function main() {
    await eip712();

    // Read the ABI file (normally generated by `solc`.)
    const resp = await fetch("./NameRegistry.json");
    const abi = await resp.text();

    // Configure and run the generator.
    const output = new Eip712("NameRegistry")   // Name of the base contract.
        .error(console.log)                     // Error handler.
        .warning(console.log)                   // Warning handler.
        .signing_domain("NameRegistry")         // Name for the EIP-712 domain.
        .version("1")                           // Contract version.
        .read_str(abi)
        .generate();

    let elem = document.createElement('pre');
    elem.innerText = output;
    document.body.appendChild(elem);
}

main();

Dependencies

~1.9–7.5MB
~71K SLoC