Skip to main content

EIP-712 Structs PyPI Python License

A python interface for simple EIP-712 struct construction.

In this module, a "struct" is structured data as defined in the standard. It is not the same as the Python Standard Library's struct (e.g., import struct).

Read the proposal:
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md

Supported Python Versions

  • 3.9.10+

Install

pip install kuest-py-eip712-structs

Usage

See API.md for a succinct summary of available methods.

Examples/Details below.

Quickstart

Say we want to represent the following struct, convert it to a message and sign it:

struct MyStruct {
    string some_string;
    uint256 some_number;
}

With this module, that would look like:

# Make a unique domain
from kuest_eip712_structs import make_domain
domain = make_domain(name='Some name', version='1.0.0')  # Make a Domain Separator

# Define your struct type
from kuest_eip712_structs import EIP712Struct, String, Uint
class MyStruct(EIP712Struct):
    some_string = String()
    some_number = Uint(256)

# Create an instance with some data
mine = MyStruct(some_string='hello world', some_number=1234)

# Values can be get/set dictionary-style:
mine['some_number'] = 4567
assert mine['some_string'] == 'hello world'
assert mine['some_number'] == 4567

# Into a message dict - domain required
my_msg = mine.to_message(domain)

# Into message JSON - domain required.
# This method converts bytes types for you, which the default JSON encoder won't handle.
my_msg_json = mine.to_message_json(domain)

# Into signable bytes - domain required
my_bytes = mine.signable_bytes(domain)

See Member Types for more information on supported types.

Dynamic construction

Attributes may be added dynamically as well. This may be necessary if you want to use a reserved keyword like from.

from kuest_eip712_structs import EIP712Struct, Address
class Message(EIP712Struct):
    pass

Message.to = Address()
setattr(Message, 'from', Address())

# At this point, Message is equivalent to `struct Message { address to; address from; }`

The domain separator

EIP-712 specifies a domain struct, to differentiate between identical structs that may be unrelated. A helper method exists for this purpose. All values to the make_domain() function are optional - but at least one must be defined. If omitted, the resulting domain struct's definition leaves out the parameter entirely.

The full signature:
make_domain(name: string, version: string, chainId: uint256, verifyingContract: address, salt: bytes32)

Setting a default domain

Constantly providing the same domain can be cumbersome. You can optionally set a default, and then forget it. It is automatically used by .to_message() and .signable_bytes()

import kuest_eip712_structs

foo = SomeStruct()

my_domain = kuest_eip712_structs.make_domain(name='hello world')
kuest_eip712_structs.default_domain = my_domain

assert foo.to_message() == foo.to_message(my_domain)
assert foo.signable_bytes() == foo.signable_bytes(my_domain)

Member Types

Basic types

EIP712's basic types map directly to solidity types.

from kuest_eip712_structs import Address, Boolean, Bytes, Int, String, Uint

Address()  # Solidity's 'address'
Boolean()  # 'bool'
Bytes()    # 'bytes'
Bytes(N)   # 'bytesN' - N must be an int from 1 through 32
Int(N)     # 'intN' - N must be a multiple of 8, from 8 to 256
String()   # 'string'
Uint(N)    # 'uintN' - N must be a multiple of 8, from 8 to 256

Use like:

from kuest_eip712_structs import EIP712Struct, Address, Bytes

class Foo(EIP712Struct):
    member_name_0 = Address()
    member_name_1 = Bytes(5)
    # ...etc

Struct references

In addition to holding basic types, EIP712 structs may also hold other structs! Usage is almost the same - the difference is you don't "instantiate" the class.

Example:

from kuest_eip712_structs import EIP712Struct, String

class Dog(EIP712Struct):
    name = String()
    breed = String()

class Person(EIP712Struct):
    name = String()
    dog = Dog  # Take note - no parentheses!

# Dog "stands alone"
Dog.encode_type()     # Dog(string name,string breed)

# But Person knows how to include Dog
Person.encode_type()  # Person(string name,Dog dog)Dog(string name,string breed)

Instantiating the structs with nested values may be done a couple different ways:

# Method one: set it to a struct
dog = Dog(name='Mochi', breed='Corgi')
person = Person(name='E.M.', dog=dog)

# Method two: set it to a dict - the underlying struct is built for you
person = Person(
    name='E.M.',
    dog={
        'name': 'Mochi',
        'breed': 'Corgi',
    }
)

Arrays

Arrays are also supported for the standard.

array_member = Array(<item_type>[, <optional_length>])
  • <item_type> - The basic type or struct that will live in the array
  • <optional_length> - If given, the array is set to that length.

For example:

dynamic_array = Array(String())      # String[] dynamic_array
static_array  = Array(String(), 10)  # String[10] static_array
struct_array = Array(MyStruct, 10)   # MyStruct[10] - again, don't instantiate structs like the basic types

Development

Contributions always welcome.

Install dependencies:

  • pip install -r requirements.txt

Run tests:

  • python setup.py test
  • Some tests expect an active local ganache chain on http://localhost:8545. Docker will compile the contracts and start the chain for you.
  • Docker is optional, but useful to test the whole suite. If no chain is detected, chain tests are skipped.
  • Usage:
    • docker-compose up -d (Starts containers in the background)
    • Note: Contracts are compiled when you run up, but won't be deployed until the test is run.
    • Cleanup containers when you're done: docker-compose down

Deploying a new version:

  • Bump the version number in setup.py and push the commit to main.
  • Publish a GitHub Release for that version. The GitHub Actions release workflow will run the tests, build the package, and publish it to PyPI.

Shameless Plug

Written by ConsenSys for the world! :heart:

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kuest_py_eip712_structs-0.0.5.tar.gz (18.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kuest_py_eip712_structs-0.0.5-py3-none-any.whl (12.6 kB view details)

Uploaded Python 3

File details

Details for the file kuest_py_eip712_structs-0.0.5.tar.gz.

File metadata

  • Download URL: kuest_py_eip712_structs-0.0.5.tar.gz
  • Upload date:
  • Size: 18.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for kuest_py_eip712_structs-0.0.5.tar.gz
Algorithm Hash digest
SHA256 2f612ea9958a0c8005836738d60195c71164db938a9ab8dd6861d8adafe26151
MD5 399c67085815f54c264fb92e992c2dbb
BLAKE2b-256 5c5a2cbfd62b584b89be492fe9c1b22a67171ef45208ee658a50e4a4478cb0ca

See more details on using hashes here.

Provenance

The following attestation bundles were made for kuest_py_eip712_structs-0.0.5.tar.gz:

Publisher: release.yaml on kuestcom/py-eip712-structs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kuest_py_eip712_structs-0.0.5-py3-none-any.whl.

File metadata

File hashes

Hashes for kuest_py_eip712_structs-0.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 5f5ceb2279761833f803a83b68e961cce5d17818e204f4c687d7a36ad0cc1da1
MD5 8e8702e925ffc7f6001006d9855ce637
BLAKE2b-256 d005c33ae5129def92e4fd079b489ff970ded6580d767ac0290361551e8b01de

See more details on using hashes here.

Provenance

The following attestation bundles were made for kuest_py_eip712_structs-0.0.5-py3-none-any.whl:

Publisher: release.yaml on kuestcom/py-eip712-structs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.0.5 This release

2 files

0.0.4

2 files

0.0.3

2 files

0.0.2

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page