Skip to content

Commit

Permalink
chore: upgrade to 0.7
Browse files Browse the repository at this point in the history
  • Loading branch information
antazoey committed Dec 20, 2023
1 parent 7d753c2 commit 7fbff68
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 51 deletions.
49 changes: 20 additions & 29 deletions ape_safe/_cli/pending.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import click
import rich
from ape.api import AccountAPI
from ape.cli import NetworkBoundCommand, get_user_selected_account, network_option
from ape.cli import ConnectedProviderCommand, get_user_selected_account, network_option
from ape.exceptions import SignatureError
from ape.types import AddressType
from click.exceptions import BadOptionUsage
Expand All @@ -25,17 +25,15 @@ def pending():
"""


@pending.command("list", cls=NetworkBoundCommand)
@pending.command("list", cls=ConnectedProviderCommand)
@safe_cli_ctx
@network_option()
@safe_option
@click.option("--verbose", is_flag=True)
def _list(cli_ctx: SafeCliContext, network, safe, verbose) -> None:
def _list(cli_ctx: SafeCliContext, safe, verbose) -> None:
"""
View pending transactions for a Safe
"""

_ = network # Needed for NetworkBoundCommand
txns = list(safe.client.get_transactions(starting_nonce=safe.next_nonce, confirmed=False))
if not txns:
rich.print("There are no pending transactions.")
Expand All @@ -50,17 +48,19 @@ def _list(cli_ctx: SafeCliContext, network, safe, verbose) -> None:

all_items = txns_by_nonce.items()
total_items = len(all_items)
max_op_len = len("rejection")
for root_idx, (nonce, tx_list) in enumerate(all_items):
tx_len = len(tx_list)
for idx, tx in enumerate(tx_list):
title = f"Transaction {nonce}"
is_rejection = not tx.value and not tx.data and tx.to == tx.safe
operation_name = tx.operation.name if tx.data else "transfer"
if is_rejection:
title = f"{title} rejection"
else:
title = f"{title} {operation_name}"
operation_name = "rejection"

# Add spacing (unless verbose) so columns are aligned.
spaces = (max(0, max_op_len - len(operation_name))) * " " if verbose else ""
title = f"{title} {operation_name}{spaces}"
confirmations = tx.confirmations
rich.print(
f"{title} "
Expand All @@ -71,7 +71,7 @@ def _list(cli_ctx: SafeCliContext, network, safe, verbose) -> None:
if verbose:
fields = ("to", "value", "data", "base_gas", "gas_price")
data = {}
for field_name, value in tx.dict().items():
for field_name, value in tx.model_dump(by_alias=True, mode="json").items():
if field_name not in fields:
continue

Expand Down Expand Up @@ -124,22 +124,19 @@ def _handle_execute_cli_arg(ctx, param, val):
)


@pending.command(cls=NetworkBoundCommand)
@pending.command(cls=ConnectedProviderCommand)
@safe_cli_ctx
@network_option()
@safe_option
@click.option("--data", type=HexBytes, help="Transaction data", default=HexBytes(""))
@click.option("--gas-price", type=int, help="Transaction gas price")
@click.option("--value", type=int, help="Transaction value", default=0)
@click.option("--to", "receiver", type=AddressType, help="Transaction receiver")
@click.option("--nonce", type=int, help="Transaction nonce")
@click.option("--execute", callback=_handle_execute_cli_arg)
def propose(cli_ctx, network, safe, data, gas_price, value, receiver, nonce, execute):
def propose(cli_ctx, ecosystem, safe, data, gas_price, value, receiver, nonce, execute):
"""
Create a new transaction
"""
_ = network # Needed for NetworkBoundCommand
ecosystem = cli_ctx.chain_manager.provider.network.ecosystem
nonce = safe.new_nonce if nonce is None else nonce
txn = ecosystem.create_transaction(
value=value, data=data, gas_price=gas_price, nonce=nonce, receiver=receiver
Expand Down Expand Up @@ -215,14 +212,12 @@ def _load_submitter(ctx, param, val):
return None


@pending.command(cls=NetworkBoundCommand)
@pending.command(cls=ConnectedProviderCommand)
@safe_cli_ctx
@network_option()
@safe_option
@txn_ids_argument
@click.option("--execute", callback=_handle_execute_cli_arg)
def approve(cli_ctx: SafeCliContext, network, safe, txn_ids, execute):
_ = network # Needed for NetworkBoundCommand
def approve(cli_ctx: SafeCliContext, safe, txn_ids, execute):
submitter: Optional[AccountAPI] = execute if isinstance(execute, AccountAPI) else None
pending_transactions = list(
safe.client.get_transactions(confirmed=False, starting_nonce=safe.next_nonce)
Expand All @@ -235,7 +230,7 @@ def approve(cli_ctx: SafeCliContext, network, safe, txn_ids, execute):
# Not a specified txn.
continue

safe_tx = safe.create_safe_tx(**txn.dict(by_alias=True))
safe_tx = safe.create_safe_tx(**txn.model_dump(by_alias=True, mode="json"))
num_confirmations = len(txn.confirmations)
signatures_added = {}

Expand Down Expand Up @@ -270,14 +265,14 @@ def approve(cli_ctx: SafeCliContext, network, safe, txn_ids, execute):
cli_ctx.abort_txns_not_found(txn_ids)


@pending.command(cls=NetworkBoundCommand)
@pending.command(cls=ConnectedProviderCommand)
@safe_cli_ctx
@network_option()
@safe_option
@txn_ids_argument
# NOTE: Doesn't use --execute because we don't need BOOL values.
@click.option("--submitter", callback=_load_submitter)
def execute(cli_ctx, network, safe, txn_ids, submitter):
def execute(cli_ctx, safe, txn_ids, submitter):
"""
Execute a transaction
"""
Expand All @@ -300,7 +295,7 @@ def execute(cli_ctx, network, safe, txn_ids, submitter):


def _execute(safe: SafeAccount, txn: UnexecutedTxData, submitter: AccountAPI):
safe_tx = safe.create_safe_tx(**txn.dict(by_alias=True))
safe_tx = safe.create_safe_tx(**txn.model_dump(mode="json", by_alias=True))
signatures = {c.owner: _rsv_to_message_signature(c.signature) for c in txn.confirmations}

# NOTE: We have a hack that allows bytes in the mapping, hence type ignore
Expand All @@ -309,17 +304,15 @@ def _execute(safe: SafeAccount, txn: UnexecutedTxData, submitter: AccountAPI):
submitter.call(exc_tx)


@pending.command(cls=NetworkBoundCommand)
@pending.command(cls=ConnectedProviderCommand)
@safe_cli_ctx
@network_option()
@safe_option
@txn_ids_argument
def reject(cli_ctx: SafeCliContext, network, safe, txn_ids):
"""
Reject one or more pending transactions
"""

_ = network # Needed for NetworkBoundCommand
pending_transactions = safe.client.get_transactions(
confirmed=False, starting_nonce=safe.next_nonce
)
Expand Down Expand Up @@ -352,16 +345,14 @@ def reject(cli_ctx: SafeCliContext, network, safe, txn_ids):
cli_ctx.abort_txns_not_found(txn_ids)


@pending.command(cls=NetworkBoundCommand)
@pending.command(cls=ConnectedProviderCommand)
@safe_cli_ctx
@network_option()
@safe_option
@click.argument("txn_id")
def show_confs(cli_ctx, network, safe, txn_id):
def show_confs(cli_ctx, safe, txn_id):
"""
Show existing confirmations
"""
_ = network # Needed for NetworkBoundCommand

if txn_id.isnumeric():
nonce = int(txn_id)
Expand Down
20 changes: 12 additions & 8 deletions ape_safe/accounts.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import json
import os
from pathlib import Path
from typing import Dict, Iterable, Iterator, List, Mapping, Optional, Tuple, Type, Union, cast
from typing import Any, Dict, Iterable, Iterator, List, Mapping, Optional, Tuple, Type, Union, cast

from ape.api import AccountAPI, AccountContainerAPI, ReceiptAPI, TransactionAPI
from ape.api.address import BaseAddress
Expand All @@ -10,7 +10,7 @@
from ape.exceptions import ProviderNotConnectedError
from ape.logging import logger
from ape.managers.accounts import AccountManager, TestAccountManager
from ape.types import AddressType, HexBytes, MessageSignature, SignableMessage
from ape.types import AddressType, HexBytes, MessageSignature
from ape.utils import ZERO_ADDRESS, cached_property
from ape_ethereum.transactions import TransactionType
from eip712.common import create_safe_tx_def
Expand Down Expand Up @@ -206,11 +206,13 @@ def contract(self) -> ContractInstance:
if fallback_signatures < contract_signatures:
return safe_contract # for some reason this never gets hit

contract_type = safe_contract.contract_type.dict()
fallback_type = self.fallback_handler.contract_type.dict()
contract_type = safe_contract.contract_type.model_dump(by_alias=True, mode="json")
fallback_type = self.fallback_handler.contract_type.model_dump(
by_alias=True, mode="json"
)
contract_type["abi"].extend(fallback_type["abi"])
return self.chain_manager.contracts.instance_at(
self.address, contract_type=ContractType.parse_obj(contract_type)
self.address, contract_type=ContractType.model_validate(contract_type)
)

else:
Expand All @@ -219,7 +221,7 @@ def contract(self) -> ContractInstance:
@cached_property
def fallback_handler(self) -> Optional[ContractInstance]:
slot = keccak(text="fallback_manager.handler.address")
value = self.provider.get_storage_at(self.address, slot)
value = self.provider.get_storage(self.address, slot)
address = self.network_manager.ecosystem.decode_address(value[-20:])
return (
self.chain_manager.contracts.instance_at(address) if address != ZERO_ADDRESS else None
Expand Down Expand Up @@ -304,7 +306,7 @@ def new_nonce(self):
# No pending transactions. Use next on-chain nonce.
return self.next_nonce

def sign_message(self, msg: SignableMessage) -> Optional[MessageSignature]:
def sign_message(self, msg: Any, **signer_options) -> Optional[MessageSignature]:
raise NotImplementedError("Safe accounts do not support message signing!")

@property
Expand Down Expand Up @@ -345,7 +347,9 @@ def create_safe_tx(self, txn: Optional[TransactionAPI] = None, **safe_tx_kwargs)

def pending_transactions(self) -> Iterator[Tuple[SafeTx, List[SafeTxConfirmation]]]:
for executed_tx in self.client.get_transactions(confirmed=False):
yield self.create_safe_tx(**executed_tx.dict(by_alias=True)), executed_tx.confirmations
yield self.create_safe_tx(
**executed_tx.model_dump(mode="json", by_alias=True)
), executed_tx.confirmations

@property
def local_signers(self) -> List[AccountAPI]:
Expand Down
10 changes: 5 additions & 5 deletions ape_safe/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def __init__(
@property
def safe_details(self) -> SafeDetails:
response = self._get(f"safes/{self.address}")
return SafeDetails.parse_obj(response.json())
return SafeDetails.model_validate(response.json())

def get_next_nonce(self) -> int:
return self.safe_details.nonce
Expand All @@ -90,10 +90,10 @@ def _all_transactions(self) -> Iterator[SafeApiTxData]:
# TODO: Replace with `model_validate()` after ape 0.7.
# NOTE: Using construct because of pydantic v2 back import validation error.
if "isExecuted" in txn and txn["isExecuted"]:
yield ExecutedTxData.parse_obj(txn)
yield ExecutedTxData.model_validate(txn)

else:
yield UnexecutedTxData.parse_obj(txn)
yield UnexecutedTxData.model_validate(txn)

url = data.get("next")

Expand All @@ -102,7 +102,7 @@ def get_confirmations(self, safe_tx_hash: SafeTxID) -> Iterator[SafeTxConfirmati
while url:
response = self._get(url)
data = response.json()
yield from map(SafeTxConfirmation.parse_obj, data.get("results"))
yield from map(SafeTxConfirmation.model_validate, data.get("results"))
url = data.get("next")

def post_transaction(
Expand All @@ -119,7 +119,7 @@ def post_transaction(
)
post_dict: Dict = {"signature": signature.hex()}

for key, value in tx_data.dict(by_alias=True).items():
for key, value in tx_data.model_dump(by_alias=True, mode="json").items():
if isinstance(value, HexBytes):
post_dict[key] = value.hex()
elif isinstance(value, OperationType):
Expand Down
2 changes: 1 addition & 1 deletion ape_safe/client/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def __init__(self, contract: ContractInstance):
@property
def safe_details(self) -> SafeDetails:
slot = keccak(text="fallback_manager.handler.address")
value = self.provider.get_storage_at(self.contract.address, slot)
value = self.provider.get_storage(self.contract.address, slot)
fallback_address = self.network_manager.ecosystem.decode_address(value[-20:])

return SafeDetails(
Expand Down
2 changes: 1 addition & 1 deletion ape_safe/multisend.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def contract(self) -> ContractInstance:
# All versions have this ABI
contract = self.chain_manager.contracts.instance_at(
multisend_address,
contract_type=ContractType.parse_obj(MULTISEND_CONTRACT_TYPE),
contract_type=ContractType.model_validate(MULTISEND_CONTRACT_TYPE),
)

if contract.code != MULTISEND_CODE:
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@
include_package_data=True,
install_requires=[
"eth-ape>=0.6.27,<0.7.0",
"eip712>=0.2.2,<0.3.0",
"requests>=2.31.0,<3",
"eip712", # Use same version as eth-ape
"click", # Use same version as eth-ape
"pydantic<2", # TODO: Rm constraint on Ape 0.7.
"pydantic", # Use same version as eth-ape
"eth-utils", # Use same version as eth-ape
],
entry_points={
Expand Down
6 changes: 4 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,15 @@ def safe(safe_data_file):

@pytest.fixture
def token(deployer: SafeAccount):
contract = ContractType.parse_file(contracts_directory / "Token.json")
text = (contracts_directory / "Token.json").read_text()
contract = ContractType.model_validate_json(text)
return deployer.deploy(ContractContainer(contract))


@pytest.fixture
def vault(deployer: SafeAccount, token):
vault = ContractContainer(ContractType.parse_file(contracts_directory / "VyperVault.json"))
text = (contracts_directory / "VyperVault.json").read_text()
vault = ContractContainer(ContractType.model_validate_json(text))
return deployer.deploy(vault, token)


Expand Down
6 changes: 3 additions & 3 deletions tests/test_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def test_swap_owner(safe, accounts, OWNERS, mode):
safe_tx_hash = add_0x_prefix(f"{pending_txns[0].safe_tx_hash}")

safe_tx_data = pending_txns[0]
safe_tx = safe.create_safe_tx(**safe_tx_data.dict(by_alias=True))
safe_tx = safe.create_safe_tx(**safe_tx_data.model_dump(by_alias=True, mode="json"))

# Ensure client confirmations works
client_confs = list(safe.client.get_confirmations(safe_tx_hash))
Expand Down Expand Up @@ -98,7 +98,7 @@ def test_add_owner(safe, accounts, OWNERS, mode):

# `safe_tx` is in mock client, extract it and execute it successfully this time
safe_tx_data = next(safe.client.get_transactions(confirmed=False))
safe_tx = safe.create_safe_tx(**safe_tx_data.dict(by_alias=True))
safe_tx = safe.create_safe_tx(**safe_tx_data.model_dump(by_alias=True, mode="json"))
receipt = safe.submit_safe_tx(safe_tx)

assert receipt.events == [
Expand Down Expand Up @@ -146,7 +146,7 @@ def exec_transaction():

# `safe_tx` is in mock client, extract it and execute it successfully this time
safe_tx_data = next(safe.client.get_transactions(confirmed=False))
safe_tx = safe.create_safe_tx(**safe_tx_data.dict(by_alias=True))
safe_tx = safe.create_safe_tx(**safe_tx_data.model_dump(by_alias=True, mode="json"))
receipt = safe.submit_safe_tx(safe_tx)

expected_events = [
Expand Down

0 comments on commit 7fbff68

Please sign in to comment.