Skip to content

Commit

Permalink
feat!: Support Ape 0.8 (#43)
Browse files Browse the repository at this point in the history
Co-authored-by: Dalena <[email protected]>
  • Loading branch information
antazoey and dtdang authored May 31, 2024
1 parent d66aaf8 commit f181cdb
Show file tree
Hide file tree
Showing 10 changed files with 32 additions and 59 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:
# TODO: Replace with macos-latest when works again.
# https://github.com/actions/setup-python/issues/808
os: [ubuntu-latest, macos-12] # eventually add `windows-latest`
python-version: [3.8, 3.9, "3.10", "3.11", "3.12"]
python-version: [3.9, "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ repos:
rev: 0.7.17
hooks:
- id: mdformat
additional_dependencies: [mdformat-gfm, mdformat-frontmatter]
additional_dependencies: [mdformat-gfm, mdformat-frontmatter, mdformat-pyproject]

default_language_version:
python: python3
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Ape Trezor is a plugin for [Ape Framework](https://github.com/ApeWorx/ape) which

## Dependencies

- [python3](https://www.python.org/downloads) version 3.8 up tp 3.12.
- [python3](https://www.python.org/downloads) version 3.9 up tp 3.12.

**Note**: USB does not work in WSL2 environments natively and is [not currently supported](https://github.com/microsoft/WSL/issues/5158).

Expand Down
7 changes: 4 additions & 3 deletions ape_trezor/accounts.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import json
from collections.abc import Iterator
from functools import cached_property
from pathlib import Path
from typing import Any, Dict, Iterator, Optional
from typing import Any, Optional

from ape.api import AccountAPI, AccountContainerAPI, PluginConfig, TransactionAPI
from ape.types import AddressType, MessageSignature, TransactionSignature
Expand Down Expand Up @@ -183,9 +184,9 @@ def sign_transaction(self, txn: TransactionAPI, **kwargs) -> Optional[Transactio
return txn


def _prepare_data_for_hashing(data: Dict) -> Dict:
def _prepare_data_for_hashing(data: dict) -> dict:
# NOTE: Private method copied from eip712 package.
result: Dict = {}
result: dict = {}

for key, value in data.items():
item: Any = value
Expand Down
4 changes: 2 additions & 2 deletions ape_trezor/choices.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, Optional, Tuple
from typing import Any, Optional

import click
from ape.cli import PromptChoice
Expand Down Expand Up @@ -56,7 +56,7 @@ def convert(
self._choice_index = self.choices.index(address) # type: ignore
return address

def get_user_selected_account(self) -> Tuple[str, HDPath]:
def get_user_selected_account(self) -> tuple[str, HDPath]:
"""Returns the selected address from the user along with the HD path.
The user is able to page using special characters ``n`` and ``p``.
"""
Expand Down
23 changes: 12 additions & 11 deletions ape_trezor/client.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Callable, Dict, Optional, Tuple
from collections.abc import Callable
from typing import Optional

from ape.logging import logger
from eth_typing.evm import ChecksumAddress
Expand Down Expand Up @@ -68,7 +69,7 @@ def get_account_path(self, account_id: int) -> str:
raise TrezorClientError(str(err), status=code) from err


def extract_signature_vrs_bytes(signature_bytes: bytes) -> Tuple[int, bytes, bytes]:
def extract_signature_vrs_bytes(signature_bytes: bytes) -> tuple[int, bytes, bytes]:
"""
Breaks `signature_bytes` into 3 chunks vrs, where `v` is 1 byte, `r` is 32
bytes, and `s` is 32 bytes.
Expand Down Expand Up @@ -109,7 +110,7 @@ def __str__(self):
def address(self) -> str:
return self._address

def sign_personal_message(self, message: bytes) -> Tuple[int, bytes, bytes]:
def sign_personal_message(self, message: bytes) -> tuple[int, bytes, bytes]:
"""
Sign an Ethereum message only following the EIP 191 specification and
using your Trezor device. You will need to follow the prompts on the device
Expand All @@ -120,23 +121,23 @@ def sign_personal_message(self, message: bytes) -> Tuple[int, bytes, bytes]:
)
return extract_signature_vrs_bytes(signature_bytes=ethereum_message_signature.signature)

def sign_typed_data(self, data: Dict) -> Tuple[int, bytes, bytes]:
def sign_typed_data(self, data: dict) -> tuple[int, bytes, bytes]:
"""
Sends a dict of data to the device and is much more obvious and secure
than signing a hash alone.
Args:
data(Dict): The data to sign, following EIP-712.
data(dict): The data to sign, following EIP-712.
Returns:
Tuple[int, bytes, bytes]: A signature tuple.
tuple[int, bytes, bytes]: A signature tuple.
"""
signed_data = sign_typed_data(self.client, self._account_hd_path.address_n, data)
return extract_signature_vrs_bytes(signature_bytes=signed_data.signature)

def sign_typed_data_hash(
self, domain_hash: bytes, message_hash: bytes
) -> Tuple[int, bytes, bytes]:
) -> tuple[int, bytes, bytes]:
"""
Sign an Ethereum message following the EIP 712 specification.
This approach still uses the hash on the device and may not look
Expand All @@ -147,20 +148,20 @@ def sign_typed_data_hash(
message_hash (bytes): The hashed message portion of the data.
Returns:
Tuple[int, bytes, bytes]: A signature tuple.
tuple[int, bytes, bytes]: A signature tuple.
"""
signed_data = sign_typed_data_hash(
self.client, self._account_hd_path.address_n, domain_hash, message_hash=message_hash
)
return extract_signature_vrs_bytes(signature_bytes=signed_data.signature)

def sign_static_fee_transaction(self, **kwargs) -> Tuple[int, bytes, bytes]:
def sign_static_fee_transaction(self, **kwargs) -> tuple[int, bytes, bytes]:
return self._sign_transaction(sign_tx, **kwargs)

def sign_dynamic_fee_transaction(self, **kwargs) -> Tuple[int, bytes, bytes]:
def sign_dynamic_fee_transaction(self, **kwargs) -> tuple[int, bytes, bytes]:
return self._sign_transaction(sign_tx_eip1559, **kwargs)

def _sign_transaction(self, lib_call: Callable, **kwargs) -> Tuple[int, bytes, bytes]:
def _sign_transaction(self, lib_call: Callable, **kwargs) -> tuple[int, bytes, bytes]:
did_change = self._allow_default_ethereum_account_signing()
try:
return lib_call(self.client, self._account_hd_path.address_n, **kwargs)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ write_to = "ape_trezor/version.py"

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

[tool.pytest.ini_options]
Expand Down
6 changes: 2 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from setuptools import find_packages, setup

extras_require = {
Expand Down Expand Up @@ -68,7 +67,7 @@
url="https://github.com/ApeWorX/ape-trezor",
include_package_data=True,
install_requires=[
"eth-ape>=0.7.0,<0.8",
"eth-ape>=0.8.1,<0.9",
"click", # Use same version as eth-ape
"trezor[ethereum]>=0.13.8,<0.14",
# ApeWorx packages
Expand All @@ -82,7 +81,7 @@
"ape_trezor=ape_trezor._cli:cli",
],
},
python_requires=">=3.8,<4",
python_requires=">=3.9,<4",
extras_require=extras_require,
py_modules=["ape_trezor"],
license="Apache-2.0",
Expand All @@ -98,7 +97,6 @@
"Operating System :: MacOS",
"Operating System :: POSIX",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
Expand Down
36 changes: 5 additions & 31 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import json
import tempfile
from contextlib import contextmanager
from pathlib import Path
from tempfile import mkdtemp
from typing import Dict, Optional

import ape
import pytest
import yaml
from ape._cli import cli as root_ape_cli
from ape.managers.config import CONFIG_FILE_NAME
from click.testing import CliRunner
from eth_pydantic_types import HexBytes
from eth_typing import HexAddress, HexStr
Expand All @@ -33,6 +28,11 @@ def config():
return ape.config


@pytest.fixture(scope="session")
def project():
return ape.project


@pytest.fixture(scope="session")
def key_file_data():
return {"address": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", "hdpath": "m/44'/60'/0'/0/0"}
Expand Down Expand Up @@ -98,29 +98,3 @@ def hd_path():
@pytest.fixture(scope="session")
def account_hd_path():
return HDPath("m/44'/60'/0'/1")


@pytest.fixture(scope="session")
def temp_config(config):
@contextmanager
def func(data: Dict, package_json: Optional[Dict] = None):
with tempfile.TemporaryDirectory() as temp_dir_str:
temp_dir = Path(temp_dir_str)

config._cached_configs = {}
config_file = temp_dir / CONFIG_FILE_NAME
config_file.touch()
config_file.write_text(yaml.dump(data))
config.load(force_reload=True)

if package_json:
package_json_file = temp_dir / "package.json"
package_json_file.write_text(json.dumps(package_json))

with config.using_project(temp_dir):
yield temp_dir

config_file.unlink()
config._cached_configs = {}

return func
7 changes: 3 additions & 4 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def test_add(mock_client, runner, cli, accounts, clean, mock_client_factory, cap
assert log_warning == expected


def test_add_specify_hd_path(mock_client, runner, cli, accounts, clean, mock_client_factory):
def test_add_specify_hd_path(mock_client, runner, cli, clean, mock_client_factory):
mock_client.get_account_path.return_value = ZERO_ADDRESS
hd_path = "m/44'/1'/0'/0"
result = runner.invoke(cli, ["add", NEW_ACCOUNT_ALIAS, "--hd-path", hd_path], input="0\n")
Expand All @@ -60,12 +60,11 @@ def test_add_specify_hd_path(mock_client, runner, cli, accounts, clean, mock_cli


def test_add_uses_hd_path_from_config(
mock_client, temp_config, runner, cli, clean, mock_client_factory, accounts
mock_client, project, runner, cli, clean, mock_client_factory, accounts
):
mock_client.get_account_path.return_value = ZERO_ADDRESS
hd_path = "m/1'/60'/0'/0"
data = {"trezor": {"hd_path": hd_path}}
with temp_config(data):
with project.temp_config(trezor={"hd_path": hd_path}):
result = runner.invoke(cli, ["add", NEW_ACCOUNT_ALIAS], input="0\n")
assert result.exit_code == 0, result.output
assert mock_client_factory.call_args[0][0].path == hd_path
Expand Down

0 comments on commit f181cdb

Please sign in to comment.