{"id":19164902,"url":"https://github.com/bobotig/py-eip712-structs-ng","last_synced_at":"2025-05-07T12:21:52.398Z","repository":{"id":260177959,"uuid":"826290662","full_name":"BoboTiG/py-eip712-structs-ng","owner":"BoboTiG","description":"A Python interface for EIP-712 struct construction.","archived":false,"fork":false,"pushed_at":"2025-05-06T02:52:06.000Z","size":204,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-06T03:32:27.684Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://pypi.org/project/eip712-structs-ng","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BoboTiG.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-07-09T12:23:03.000Z","updated_at":"2025-05-06T02:52:09.000Z","dependencies_parsed_at":null,"dependency_job_id":"bf0ac65c-3689-4f72-a9b3-0c5e5e5bb9f2","html_url":"https://github.com/BoboTiG/py-eip712-structs-ng","commit_stats":null,"previous_names":["bobotig/py-eip712-structs-ng"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BoboTiG%2Fpy-eip712-structs-ng","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BoboTiG%2Fpy-eip712-structs-ng/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BoboTiG%2Fpy-eip712-structs-ng/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BoboTiG%2Fpy-eip712-structs-ng/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BoboTiG","download_url":"https://codeload.github.com/BoboTiG/py-eip712-structs-ng/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252618144,"owners_count":21777228,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T09:25:37.535Z","updated_at":"2025-05-07T12:21:52.373Z","avatar_url":"https://github.com/BoboTiG.png","language":"Python","funding_links":["https://www.patreon.com/mschoentgen"],"categories":[],"sub_categories":[],"readme":"# EIP-712 Structs\n\n[![PyPI version](https://badge.fury.io/py/eip712-structs-ng.svg)](https://badge.fury.io/py/eip712-structs-ng)\n[![Python versions](https://img.shields.io/pypi/pyversions/eip712-structs-ng.svg)](https://pypi.python.org/pypi/eip712-structs-ng)\n\n\u003e [!TIP]\n\u003e Become **my boss** to help me work on this awesome software, and make the world better:\n\u003e \n\u003e [![Patreon](https://img.shields.io/badge/Patreon-F96854?style=for-the-badge\u0026logo=patreon\u0026logoColor=white)](https://www.patreon.com/mschoentgen)\n\nA Python interface for [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md) struct construction.\n\n\u003e Note: this is a **drop-in replacement** for the [eip712-structs](https://pypi.org/project/eip712-structs/) module, which is dead since 2019.\n\u003e\n\u003e It brings the same objects as its predecessor with some sugar:\n\u003e - the code is fully typed\n\u003e - dependencies were cleaned up\n\u003e - support for Python 3.9 and newer\n\u003e - code modernization, including Sourcery clean-up\n\u003e - 99% tests coverage\n\u003e - simplified testing (no more need for docker)\n\n\u003e **Warning**: Remove any installation of the old `eip712-structs` module to prevent import mismatches: `python -m pip uninstall -y eip712-structs`\n\nIn this module, a \"struct\" is structured data as defined in the standard.\nIt is not the same as the Python standard library's [struct](https://docs.python.org/3/library/struct.html).\n\n## Supported Python Versions\n\nPython 3.9 and newer.\n\n## Install\n\n```bash\npython -m pip install -U eip712-structs-ng\n```\n\n## Usage\n\nSee [API.md](API.md) for a succinct summary of available methods.\n\nExamples \u0026 details below.\n\n## Quickstart\n\nSay we want to represent the following struct, convert it to a message and sign it:\n\n```solidity\nstruct MyStruct {\n    string some_string;\n    uint256 some_number;\n}\n```\n\nWith this module, that would look like:\n\n```python\nfrom eip712_structs import make_domain, EIP712Struct, String, Uint\n\n\n# Make a domain separator\ndomain = make_domain(name='Some name', version='1.0.0')\n\n# Define your struct type\nclass MyStruct(EIP712Struct):\n    some_string = String()\n    some_number = Uint(256)\n\n# Create an instance with some data\nmine = MyStruct(some_string=\"hello world\", some_number=1234)\n\n# Values can be get/set dictionary-style:\nmine[\"some_number\"] = 4567\nassert mine[\"some_string\"] == \"hello world\"\nassert mine[\"some_number\"] == 4567\n\n# Into a message dict - domain required\nmy_msg = mine.to_message(domain)\n\n# Into message JSON - domain required.\n# This method converts bytes types for you, which the default JSON encoder won't handle.\nmy_msg_json = mine.to_message_json(domain)\n\n# Into signable bytes - domain required\nmy_bytes = mine.signable_bytes(domain)\n```\n\nSee [Member Types](#member-types) for more information on supported types.\n\n### Dynamic Construction\n\nAttributes may be added dynamically as well.\nThis may be necessary if you want to use a reserved keyword like `from`:\n\n```python\nfrom eip712_structs import EIP712Struct, Address\n\n\nclass Message(EIP712Struct):\n    pass\n\nMessage.to = Address()\nsetattr(Message, \"from\", Address())\n\n# At this point, `Message` is equivalent to `struct Message { address to; address from; }`\n```\n\n### The Domain Separator\n\nEIP-712 specifies a domain struct, to differentiate between identical structs that may be unrelated.\nA helper method exists for this purpose.\nAll values to the `make_domain()` function are optional - but at least one must be defined.\nIf omitted, the resulting domain struct's definition leaves out the parameter entirely.\n\nThe full signature:\n\n```python\nmake_domain(name: string, version: string, chainId: uint256, verifyingContract: address, salt: bytes32)\n```\n\n#### Setting a Default Domain\n\nConstantly providing the same domain can be cumbersome. You can optionally set a default, and then forget it.\nIt is automatically used by `.to_message()` and `.signable_bytes()`:\n\n```python\nimport eip712_structs\n\n\nfoo = SomeStruct()\n\nmy_domain = eip712_structs.make_domain(name=\"hello world\")\neip712_structs.default_domain = my_domain\n\nassert foo.to_message() == foo.to_message(my_domain)\nassert foo.signable_bytes() == foo.signable_bytes(my_domain)\n```\n\n## Member Types\n\n### Basic Types\n\nEIP712's basic types map directly to solidity types:\n\n```python\nfrom eip712_structs import Address, Boolean, Bytes, Int, String, Uint\n\n\nAddress()  # Solidity's 'address'\nBoolean()  # 'bool'\nBytes()    # 'bytes'\nBytes(N)   # 'bytesN' - N must be an int from 1 through 32\nInt(N)     # 'intN' - N must be a multiple of 8, from 8 to 256\nString()   # 'string'\nUint(N)    # 'uintN' - N must be a multiple of 8, from 8 to 256\n```\n\nUse like:\n\n```python\nfrom eip712_structs import EIP712Struct, Address, Bytes\n\n\nclass Foo(EIP712Struct):\n    member_name_0 = Address()\n    member_name_1 = Bytes(5)\n    # etc.\n```\n\n### Struct References\n\nIn addition to holding basic types, EIP-712 structs may also hold other structs!\nUsage is almost the same - the difference is you don't \"instantiate\" the class.\n\nExample:\n\n```python\nfrom eip712_structs import EIP712Struct, String\n\n\nclass Dog(EIP712Struct):\n    name = String()\n    breed = String()\n\nclass Person(EIP712Struct):\n    name = String()\n    dog = Dog  # Take note - no parentheses!\n\n# Dog \"stands alone\"\nDog.encode_type()  # Dog(string name,string breed)\n\n# But Person knows how to include Dog\nPerson.encode_type()  # Person(string name,Dog dog)Dog(string name,string breed)\n```\n\nInstantiating the structs with nested values may be done a couple different ways:\n\n```python\n# Method one: set it to a struct\ndog = Dog(name=\"Mochi\", breed=\"Corgi\")\nperson = Person(name=\"E.M.\", dog=dog)\n\n# Method two: set it to a dict - the underlying struct is built for you\nperson = Person(\n    name=\"E.M.\",\n    dog={\n        \"name\": \"Mochi\",\n        \"breed\": \"Corgi\",\n    }\n)\n```\n\n### Arrays\n\nArrays are also supported for the standard:\n\n```python\narray_member = Array(\u003citem_type\u003e[, \u003coptional_length\u003e])\n```\n\n- `\u003citem_type\u003e` - The basic type or struct that will live in the array\n- `\u003coptional_length\u003e` - If given, the array is set to that length.\n\nFor example:\n\n```python\ndynamic_array = Array(String())      # String[] dynamic_array\nstatic_array  = Array(String(), 10)  # String[10] static_array\nstruct_array  = Array(MyStruct, 10)  # MyStruct[10] - again, don't instantiate structs like the basic types\n```\n\n## Development\n\nContributions always welcome.\n\nSetup a development environment:\n\n```bash\npython -m venv venv\n. venv/bin/activate\n```\n\nInstall dependencies:\n\n```bash\npython -m pip install -U pip\npython -m pip install -e '.[tests]'\n```\n\nRun tests:\n\n```bash\npython -m pytest\n```\n\nRun linters before submitting a PR:\n\n```bash\n./checks.sh\n```\n\n### Solidity Contract\n\nWhen changing the code of the Solidity test contract, you will have to regenerate its Python data code:\n\n```shell\ncd src/tests/integration/contract_sources \u0026\u0026 ./compile.sh\n```\n\nThat's it! Do not forget to commit those changes.\n\n## Deploying a New Version\n\n- Bump the version number in `__init__.py`, commit it into the `main` branch.\n- Make a release tag on the `main` branch in GitHub.\n- The CI will handle the PyPi publishing.\n\n## Shameless Plug\n\nOriginally written by [ConsenSys](https://consensys.net) for the world! And continued by [BoboTiG](https://github.com/BoboTiG)! :heart:\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbobotig%2Fpy-eip712-structs-ng","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbobotig%2Fpy-eip712-structs-ng","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbobotig%2Fpy-eip712-structs-ng/lists"}