Skip to content

Commit 32623e3

Browse files
authoredFeb 19, 2025··
feat: accounts.resolve_address() method for resolving input into address types (#2521)
1 parent 37173cc commit 32623e3

File tree

4 files changed

+91
-13
lines changed

4 files changed

+91
-13
lines changed
 

‎src/ape/managers/accounts.py

+53-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from collections.abc import Generator, Iterator
33
from contextlib import AbstractContextManager as ContextManager
44
from functools import cached_property, singledispatchmethod
5-
from typing import Optional, Union
5+
from typing import TYPE_CHECKING, Optional, Union
66

77
from eth_utils import is_hex
88

@@ -19,6 +19,9 @@
1919
from ape.utils.basemodel import ManagerAccessMixin
2020
from ape.utils.misc import log_instead_of_fail
2121

22+
if TYPE_CHECKING:
23+
from ape.api.address import BaseAddress
24+
2225
_DEFAULT_SENDERS: list[AccountAPI] = []
2326

2427

@@ -465,3 +468,52 @@ def init_test_account(
465468
self, index: int, address: AddressType, private_key: str
466469
) -> "TestAccountAPI":
467470
return self.test_accounts.init_test_account(index, address, private_key)
471+
472+
def resolve_address(
473+
self, account_id: Union["BaseAddress", AddressType, str, int, bytes]
474+
) -> Optional[AddressType]:
475+
"""
476+
Resolve the given input to an address.
477+
478+
Args:
479+
account_id (:class:~ape.api.address.BaseAddress, str, int, bytes): The input to resolve.
480+
It handles anything that converts to an AddressType like an ENS or a BaseAddress.
481+
It also handles account aliases Ape is aware of, or int or bytes address values.
482+
483+
Returns:
484+
:class:`~ape.types.AddressType` | None
485+
"""
486+
if isinstance(account_id, str) and account_id.startswith("0x"):
487+
# Was given a hex-address string.
488+
if provider := self.network_manager.active_provider:
489+
return provider.network.ecosystem.decode_address(account_id)
490+
else:
491+
# Assume Ethereum-like.
492+
return self.network_manager.ether.decode_address(account_id)
493+
494+
elif not isinstance(account_id, str):
495+
# Was given either an integer, bytes, or a BaseAddress (account or contract).
496+
return self.conversion_manager.convert(account_id, AddressType)
497+
498+
elif isinstance(account_id, str) and account_id in self.aliases:
499+
# Was given an account alias.
500+
account = self.load(account_id)
501+
return account.address
502+
503+
elif (
504+
isinstance(account_id, str)
505+
and account_id.startswith("TEST::")
506+
and account_id[-1].isdigit()
507+
):
508+
# Test account "alias".
509+
account_idx = int(account_id[-1])
510+
return self.test_accounts[account_idx]
511+
512+
elif isinstance(account_id, str) and not is_hex(account_id):
513+
# Was maybe given an ENS name.
514+
try:
515+
return self.conversion_manager.convert(account_id, AddressType)
516+
except ConversionError:
517+
return None
518+
519+
return None

‎src/ape/managers/chain.py

+2-6
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
APINotImplementedError,
2323
BlockNotFoundError,
2424
ChainError,
25-
ConversionError,
2625
ProviderNotConnectedError,
2726
QueryEngineError,
2827
TransactionNotFoundError,
@@ -955,11 +954,8 @@ def get_balance(
955954
if (isinstance(address, str) and not address.startswith("0x")) or not isinstance(
956955
address, str
957956
):
958-
try:
959-
address = self.conversion_manager.convert(address, AddressType)
960-
except ConversionError:
961-
# Try to get the balance anyway; maybe the provider can handle it.
962-
address = address
957+
# Handles accounts, ENS, integers, aliases, everything.
958+
address = self.account_manager.resolve_address(address)
963959

964960
return self.provider.get_balance(address, block_id=block_id)
965961

‎src/ape_console/plugin.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import click
66
from click.testing import CliRunner
7-
from eth_utils import is_hex
87
from IPython import get_ipython
98
from IPython.core.magic import Magics, line_magic, magics_class
109
from rich import print as rich_print
@@ -14,7 +13,6 @@
1413
from ape.exceptions import Abort, ApeException, handle_ape_exception
1514
from ape.logging import logger
1615
from ape.managers.project import LocalProject
17-
from ape.types.address import AddressType
1816
from ape.utils.basemodel import ManagerAccessMixin
1917
from ape.utils.os import clean_path
2018

@@ -67,11 +65,13 @@ def bal(self, line: str = ""):
6765
provider = ape.networks.provider
6866
ecosystem = provider.network.ecosystem
6967
result = eval(line, self.ipython.user_global_ns, self.ipython.user_ns)
70-
if isinstance(result, str) and not is_hex(result):
71-
# Check if is an account alias.
72-
address = ape.accounts.load(result).address
68+
69+
if isinstance(result, str) and result.startswith("0x"):
70+
address = result
71+
7372
else:
74-
address = ape.convert(result, AddressType)
73+
# Handles accounts, ENS, integers, BaseAddress, and aliases.
74+
address = ManagerAccessMixin.account_manager.resolve_address(result) or f"{result}"
7575

7676
decimals = ecosystem.fee_token_decimals
7777
symbol = ecosystem.fee_token_symbol

‎tests/functional/test_accounts.py

+30
Original file line numberDiff line numberDiff line change
@@ -1004,3 +1004,33 @@ def test_call_sign_false(owner, vyper_contract_instance):
10041004
tx = vyper_contract_instance.setNumber.as_transaction(5991)
10051005
with pytest.raises(SignatureError):
10061006
owner.call(tx, sign=False)
1007+
1008+
1009+
def test_resolve_address(owner, keyfile_account, account_manager, vyper_contract_instance):
1010+
# Test test-account alias input.
1011+
actual = account_manager.resolve_address(owner.alias)
1012+
assert actual == owner.address
1013+
1014+
# Test keyfile-account alias input.
1015+
actual = account_manager.resolve_address(keyfile_account.alias)
1016+
assert actual == keyfile_account.address
1017+
1018+
# Test address input.
1019+
actual = account_manager.resolve_address(owner.address)
1020+
assert actual == owner.address
1021+
1022+
# Test account input.
1023+
actual = account_manager.resolve_address(owner)
1024+
assert actual == owner.address
1025+
1026+
# Test contract input.
1027+
actual = account_manager.resolve_address(vyper_contract_instance)
1028+
assert actual == vyper_contract_instance.address
1029+
1030+
# Test int input.
1031+
actual = account_manager.resolve_address(int(owner.address, 16))
1032+
assert actual == owner.address
1033+
1034+
# Test int input.
1035+
actual = account_manager.resolve_address(HexBytes(owner.address))
1036+
assert actual == owner.address

0 commit comments

Comments
 (0)
Please sign in to comment.