Skip to content

Commit

Permalink
feat(account): Signing plain, defunct messages (for EIP-191) (refs: e…
Browse files Browse the repository at this point in the history
  • Loading branch information
kalloc committed Jul 24, 2021
1 parent e63dde2 commit 83a9ab8
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This changelog format is based on [Keep a Changelog](https://keepachangelog.com/
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased](https://github.com/eth-brownie/brownie)
- Added `LocalAccount.sign_defunct_message` method to sign `EIP-191` text messages ([#1163](https://github.com/eth-brownie/brownie/pull/1163))

## [1.15.1](https://github.com/eth-brownie/brownie/tree/v1.15.1) - 2021-07-23
### Fixed
Expand Down
22 changes: 22 additions & 0 deletions brownie/network/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from eip712.messages import EIP712Message, _hash_eip191_message
from eth_account._utils.signing import sign_message_hash
from eth_account.datastructures import SignedMessage
from eth_account.messages import defunct_hash_message
from eth_utils import keccak
from eth_utils.applicators import apply_formatters_to_dict
from hexbytes import HexBytes
Expand Down Expand Up @@ -815,6 +816,27 @@ def save(self, filename: str, overwrite: bool = False) -> str:
json.dump(encrypted, fp)
return str(json_file)

def sign_defunct_message(self, message: str) -> SignedMessage:
"""Signs an `EIP-191` using this account's private key.
Args:
message: An text
Returns:
An eth_account `SignedMessage` instance.
"""
msg_hash_bytes = defunct_hash_message(text=message)
eth_private_key = eth_keys.keys.PrivateKey(HexBytes(self.private_key))
(v, r, s, eth_signature_bytes) = sign_message_hash(eth_private_key, msg_hash_bytes)
return SignedMessage(
messageHash=msg_hash_bytes,
r=r,
s=s,
v=v,
signature=HexBytes(eth_signature_bytes),
)


def sign_message(self, message: EIP712Message) -> SignedMessage:
"""Signs an `EIP712Message` using this account's private key.
Expand Down
14 changes: 14 additions & 0 deletions docs/account-management.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,20 @@ To do so, add the account to the ``unlock`` setting in a project's :ref:`configu
The unlocked accounts are automatically added to the :func:`Accounts <brownie.network.account.Accounts>` container.
Note that you might need to fund the unlocked accounts manually.
Signing Raw Text Messages (EIP-191)
================
To sign an EIP-191 message, use the :func:`LocalAccount.sign_defunct_message <brownie.network.account.LocalAccount.sign_defunct_message>` method to produce an ``eth_account`` `SignableMessage <https://eth-account.readthedocs.io/en/stable/eth_account.html#eth_account.messages.SignableMessage>`_ object:
.. code-block:: python
>>> msg = f"It is my permission to spent 1000 SHIB from {local.address.lower()}"
>>> signed = local.sign_defunct_message(msg)
>>> type(signed)
<class 'eth_account.datastructures.SignedMessage'>
>>> signed.messageHash.hex()
'0x2a180b353c317ae903c063141592ec360b25be9f75c60ae16ca19f5578f70a50'
Signing Messages
================
Expand Down
10 changes: 10 additions & 0 deletions tests/network/account/test_accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,13 @@ class TestMessage(EIP712Message):
signed.messageHash.hex()
== "0x131c497d4b815213752a2a00564dcf667c3bf3f85a410ef8cb50050b51959c26"
)


def test_sign_defunct_message(accounts):
local = accounts.add(priv_key)
msg = f'I authorize Foundation to migrate my account to {local.address.lower()}'
signed = local.sign_defunct_message(msg)
assert (
signed.messageHash.hex()
== "0xb9bb14ce5c17b2b7217cfa638031a542b95fc25b18d42a61409066001d01351d"
)

0 comments on commit 83a9ab8

Please sign in to comment.