diff --git a/autonity_cli/auth.py b/autonity_cli/auth.py index 038d18f..c8bf46b 100644 --- a/autonity_cli/auth.py +++ b/autonity_cli/auth.py @@ -4,11 +4,13 @@ import click import trezorlib.ethereum as trezor_eth from eth_account import Account -from eth_account._utils.legacy_transactions import encode_transaction +from eth_account._utils.legacy_transactions import ( + encode_transaction, + serializable_unsigned_transaction_from_dict, +) from eth_account.datastructures import SignedTransaction from eth_account.messages import encode_defunct from eth_account.signers.local import LocalAccount -from eth_account.typed_transactions.typed_transaction import TypedTransaction from eth_account.types import TransactionDictType from eth_typing import ChecksumAddress from eth_utils.conversions import to_int @@ -92,28 +94,48 @@ def device_info(self, features: Features) -> str: def sign_transaction(self, params: "TxParams") -> SignedTransaction: assert "chainId" in params assert "gas" in params - assert "maxFeePerGas" in params - assert "maxPriorityFeePerGas" in params assert "nonce" in params assert "to" in params assert "value" in params - v_int, r_bytes, s_bytes = trezor_eth.sign_tx_eip1559( - self.client, - self.path, - nonce=params["nonce"], - gas_limit=params["gas"], - to=str(params["to"]), - value=params["value"], - data=HexBytes(params["data"]) if "data" in params else HexBytes(b""), - chain_id=params["chainId"], - max_gas_fee=int(params["maxFeePerGas"]), - max_priority_fee=int(params["maxPriorityFeePerGas"]), - ) + data_bytes = HexBytes(params["data"] if "data" in params else b"") + try: + if "gasPrice" in params and params["gasPrice"]: + v_int, r_bytes, s_bytes = trezor_eth.sign_tx( + self.client, + self.path, + nonce=cast(int, params["nonce"]), + gas_price=cast(int, params["gasPrice"]), + gas_limit=params["gas"], + to=cast(str, params["to"]), + value=cast(int, params["value"]), + data=data_bytes, + chain_id=params["chainId"], + ) + else: + assert "maxFeePerGas" in params + assert "maxPriorityFeePerGas" in params + v_int, r_bytes, s_bytes = trezor_eth.sign_tx_eip1559( + self.client, + self.path, + nonce=cast(int, params["nonce"]), + gas_limit=params["gas"], + to=cast(str, params["to"]), + value=cast(int, params["value"]), + data=data_bytes, + chain_id=params["chainId"], + max_gas_fee=int(params["maxFeePerGas"]), + max_priority_fee=int(params["maxPriorityFeePerGas"]), + ) + except Cancelled as exc: # user cancelled optional passphrase prompt + raise click.Abort() from exc r_int = to_int(r_bytes) s_int = to_int(s_bytes) - filtered_params = dict((k, v) for (k, v) in params.items() if k != "from") - tx_unsigned = TypedTransaction.from_dict( - cast(TransactionDictType, filtered_params) + filtered_tx = dict((k, v) for (k, v) in params.items() if k not in ("from")) + # In a LegacyTransaction, "type" is not a valid field. See EIP-2718. + if "type" in filtered_tx and filtered_tx["type"] == "0x0": + filtered_tx.pop("type") + tx_unsigned = serializable_unsigned_transaction_from_dict( + cast(TransactionDictType, filtered_tx) ) tx_encoded = encode_transaction(tx_unsigned, vrs=(v_int, r_int, s_int)) txhash = keccak(tx_encoded) diff --git a/autonity_cli/commands/tx.py b/autonity_cli/commands/tx.py index 4f88c64..745651f 100644 --- a/autonity_cli/commands/tx.py +++ b/autonity_cli/commands/tx.py @@ -4,7 +4,6 @@ from click import ClickException, Path, argument, group, option from eth_account.datastructures import SignedTransaction -from eth_typing import HexStr from hexbytes import HexBytes from web3 import Web3 @@ -55,11 +54,6 @@ def tx_group() -> None: @option( "--data", "-d", help="compiled contract code OR method signature and parameters." ) -@option( - "--legacy", - is_flag=True, - help="if set, transaction type is 0x0 (pre-EIP1559), otherwise type is 0x2.", -) def make( rpc_endpoint: Optional[str], ntn: bool, @@ -156,12 +150,6 @@ def make( tx = finalize_tx_from_args(w3, rpc_endpoint, tx, from_addr) - # If the --legacy flag was given, explicitly set the type, - # otherwise have web3 determine it. - - if legacy: - tx["type"] = HexStr("0x0") - print(to_json(tx)) diff --git a/pyproject.toml b/pyproject.toml index a810bd6..e62b8fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,9 +47,10 @@ allow-direct-references = true [tool.hatch.envs.default] description = "The standard dev, build, and test environment" +dependencies = ["pyright"] [tool.hatch.envs.default.scripts] -test = ["unit-tests", "script-tests"] +test = ["unit-tests", "script-tests", "check-types"] unit-tests = "python -m unittest discover {args:tests}" script-tests = [ "rm -rf test_*", @@ -60,6 +61,8 @@ script-tests = [ "hatch run ./scripts/test_account", "hatch run ./scripts/test_token", ] +# Keep in default env so it can be used from `github` and `local` envs. +check-types = "pyright {args}" [tool.hatch.envs.github] description = "Develop and build against autonity.py from Github" @@ -78,22 +81,15 @@ post-install-commands = [ [tool.hatch.envs.lint] description = "Run code linters" -dependencies = [ - "black", - "check-wheel-contents", - "ruff", - "pyright", - "wheel-inspect", -] +dependencies = ["black", "check-wheel-contents", "ruff", "wheel-inspect"] [tool.hatch.envs.lint.scripts] -all = ["check-code", "check-wheel", "check-types"] +all = ["check-code", "check-wheel"] check-code = ["ruff check {args:.}", "black --check {args:.}"] check-wheel = [ "hatch build", "check-wheel-contents dist/autonity_cli-$(hatch version)-py3-none-any.whl", ] -check-types = "pyright {args}" fix-code = "ruff check --fix {args:.}" format = [ "black {args:.}", diff --git a/typings/trezorlib/ethereum.pyi b/typings/trezorlib/ethereum.pyi index ea9afaa..9177b57 100644 --- a/typings/trezorlib/ethereum.pyi +++ b/typings/trezorlib/ethereum.pyi @@ -12,6 +12,20 @@ def get_address( encoded_network: Optional[bytes] = None, chunkify: bool = False, ) -> str: ... +def sign_tx( + client: TrezorClient, + n: Address, + nonce: int, + gas_price: int, + gas_limit: int, + to: str, + value: int, + data: Optional[bytes] = None, + chain_id: Optional[int] = None, + tx_type: Optional[int] = None, + definitions: Optional[messages.EthereumDefinitions] = None, + chunkify: bool = False, +) -> Tuple[int, bytes, bytes]: ... def sign_tx_eip1559( client: TrezorClient, n: Address,