Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: refactor sign_message and update to 0.7.0 eth-ape #5

Merged
merged 4 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/codeql.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: python

- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v3

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
4 changes: 2 additions & 2 deletions .github/workflows/commitlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.10"

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/prtitle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.10"

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.10"

Expand Down
16 changes: 8 additions & 8 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.10"

Expand All @@ -42,10 +42,10 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.10"

Expand All @@ -66,10 +66,10 @@ jobs:
python-version: [3.8, 3.9, "3.10", "3.11"]

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

Expand All @@ -89,10 +89,10 @@ jobs:
# fail-fast: true
#
# steps:
# - uses: actions/checkout@v3
# - uses: actions/checkout@v4
#
# - name: Setup Python
# uses: actions/setup-python@v4
# uses: actions/setup-python@v5
# with:
# python-version: "3.10"
#
Expand Down
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ repos:
- id: isort

- repo: https://github.com/psf/black
rev: 23.11.0
rev: 24.2.0
hooks:
- id: black
name: black

- repo: https://github.com/pycqa/flake8
rev: 6.1.0
rev: 7.0.0
hooks:
- id: flake8

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.6.1
rev: v1.8.0
hooks:
- id: mypy
additional_dependencies: [types-requests, types-setuptools]
Expand Down
101 changes: 73 additions & 28 deletions ape_frame/accounts.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from typing import Iterator, Optional
from typing import Any, Callable, Iterator, Optional, Union

from ape.api.accounts import AccountAPI, AccountContainerAPI, TransactionAPI
from ape.types import AddressType, MessageSignature, SignableMessage, TransactionSignature
from eip712.messages import EIP712Message
from eth_account._utils.legacy_transactions import serializable_unsigned_transaction_from_dict
from eth_account.messages import _hash_eip191_message
from eth_account.messages import encode_defunct
from eth_utils.curried import keccak
from hexbytes import HexBytes
from web3 import HTTPProvider, Web3


Expand All @@ -21,10 +23,26 @@ def accounts(self) -> Iterator[AccountAPI]:
yield FrameAccount()


def wrap_sign(fn: Callable) -> Optional[bytes]:
try:
return fn()

except ValueError as err:
if not err.args[0]["message"] == "User declined transaction":
raise # The ValueError

return None


class FrameAccount(AccountAPI):
@property
def web3(self) -> Web3:
return Web3(HTTPProvider("http://127.0.0.1:1248"))
headers = {
"Origin": "Ape",
"User-Agent": "ape-frame/0.1.0",
"Content-Type": "application/json",
NotPeopling2day marked this conversation as resolved.
Show resolved Hide resolved
}
return Web3(HTTPProvider("http://127.0.0.1:1248", request_kwargs={"headers": headers}))

@property
def alias(self) -> str:
Expand All @@ -34,37 +52,64 @@ def alias(self) -> str:
def address(self) -> AddressType:
return self.web3.eth.accounts[0]

def sign_message(self, msg: SignableMessage) -> Optional[MessageSignature]:
try:
raw_signature = self.web3.eth.sign(self.address, hexstr=_hash_eip191_message(msg).hex())
except ValueError as e:
if not e.args[0]["message"] == "User declined transaction":
raise
def sign_message(self, msg: Any, **signer_options) -> Optional[MessageSignature]:
raw_signature = None

return None
if isinstance(msg, str):
raw_signature = wrap_sign(lambda: self.web3.eth.sign(self.address, text=msg))
elif isinstance(msg, int):
raw_signature = wrap_sign(
lambda: self.web3.eth.sign(self.address, hexstr=HexBytes(msg).hex())
)
elif isinstance(msg, bytes):
raw_signature = wrap_sign(lambda: self.web3.eth.sign(self.address, hexstr=msg.hex()))
elif isinstance(msg, SignableMessage):
raw_signature = wrap_sign(lambda: self.web3.eth.sign(self.address, data=msg.body))
elif isinstance(msg, EIP712Message):
raw_signature = wrap_sign(
lambda: self.web3.eth.sign_typed_data(
self.address, msg._body_ # type: ignore[arg-type]
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@z80dev may know more about the type discrepancy here, but I created this issue: ethereum/web3.py#3255

)

return MessageSignature( # type: ignore[call-arg]
v=raw_signature[64], # type: ignore[arg-type]
r=raw_signature[0:32], # type: ignore[arg-type]
s=raw_signature[32:64], # type: ignore[arg-type]
return (
MessageSignature(
v=int(raw_signature[64]),
r=HexBytes(raw_signature[0:32]),
s=HexBytes(raw_signature[32:64]),
)
if raw_signature
else None
)

def sign_transaction(self, txn: TransactionAPI, **signer_options) -> Optional[TransactionAPI]:
# TODO: need a way to deserialized from raw bytes
# raw_signed_txn_bytes = self.web3.eth.sign_transaction(txn.dict())
txn_data = txn.dict(exclude={"sender"})
txn_data = txn.model_dump(by_alias=True, mode="json", exclude={"sender"})
unsigned_txn = serializable_unsigned_transaction_from_dict(txn_data)
try:
raw_signature = self.web3.eth.sign(self.address, hexstr=keccak(unsigned_txn).hex())
except ValueError as e:
if not e.args[0]["message"] == "User declined transaction":
raise

return None

txn.signature = TransactionSignature( # type: ignore[call-arg]
v=raw_signature[64], # type: ignore[arg-type]
r=raw_signature[0:32], # type: ignore[arg-type]
s=raw_signature[32:64], # type: ignore[arg-type]
raw_signature = wrap_sign(
lambda: self.web3.eth.sign(self.address, hexstr=keccak(unsigned_txn).hex())
)
txn.signature = (
TransactionSignature(
v=int(raw_signature[64]),
r=HexBytes(raw_signature[0:32]),
s=HexBytes(raw_signature[32:64]),
)
if raw_signature
else None
)
return txn

def check_signature(
self,
data: Union[SignableMessage, TransactionAPI, str, EIP712Message, int],
signature: Optional[MessageSignature] = None,
) -> bool:
if isinstance(data, str):
data = encode_defunct(text=data)
elif isinstance(data, bytes):
data = encode_defunct(primitive=data)
if isinstance(data, EIP712Message):
data = data.signable_message

return super().check_signature(data, signature)
10 changes: 8 additions & 2 deletions ape_frame/providers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from typing import Any

from ape.api import UpstreamProvider, Web3Provider
from ape.api import UpstreamProvider
from ape.exceptions import ProviderError
from ape_ethereum.provider import Web3Provider
from eth_utils import to_hex
from requests import HTTPError # type: ignore[import]
from web3 import HTTPProvider, Web3
Expand All @@ -24,7 +25,12 @@ def connection_str(self) -> str:
return self.uri

def connect(self):
self._web3 = Web3(HTTPProvider(self.uri))
headers = {
"Origin": "Ape",
antazoey marked this conversation as resolved.
Show resolved Hide resolved
"User-Agent": "ape-frame/0.1.0",
"Content-Type": "application/json",
}
self._web3 = Web3(HTTPProvider(self.uri, request_kwargs={"headers": headers}))

if "Frame" not in self._web3.client_version:
raise FrameNotConnectedError()
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ write_to = "ape_frame/version.py"

[tool.black]
line-length = 100
target-version = ['py38', 'py39', 'py310']
target-version = ['py38', 'py39', 'py310', 'py311']
include = '\.pyi?$'

[tool.pytest.ini_options]
Expand Down
9 changes: 5 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@
"hypothesis>=6.2.0,<7.0", # Strategy-based fuzzer
],
"lint": [
"black>=23.11.0,<24", # Auto-formatter and linter
"mypy>=1.6.1,<2", # Static type analyzer
"black>=24.2.0,<25", # Auto-formatter and linter
"mypy>=1.8.0,<2", # Static type analyzer
"types-requests", # Needed due to mypy typeshed
"types-setuptools", # Needed due to mypy typeshed
"types-PyYAML", # Needed due to mypy typeshed
"flake8>=6.1.0,<7", # Style linter
"flake8>=7.0.0,<8", # Style linter
"isort>=5.10.1,<6", # Import sorting linter
"mdformat>=0.7.17", # Auto-formatter for markdown
"mdformat-gfm>=0.3.5", # Needed for formatting GitHub-flavored markdown
"mdformat-frontmatter>=0.4.1", # Needed for frontmatters-style headers in issue templates
"mdformat-pyproject>=0.0.1", # Allows configuring in pyproject.toml
],
"release": [ # `release` GitHub Action job uses this
"setuptools", # Installation tool
Expand Down Expand Up @@ -59,7 +60,7 @@
url="https://github.com/ApeWorX/ape-frame",
include_package_data=True,
install_requires=[
"eth-ape>=0.6.0,<0.7.0",
"eth-ape>=0.7.10,<0.8",
],
python_requires=">=3.8,<4",
extras_require=extras_require,
Expand Down
Loading