From 97e347034d67182cef35be62638fae0a0c86e7cf Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Mon, 16 Sep 2024 16:22:05 -0400 Subject: [PATCH 1/3] feat: add load_vyi and loads_vyi create an ABIContractFactory from a vyi file --- boa/interpret.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/boa/interpret.py b/boa/interpret.py index 88c55842..2622f232 100644 --- a/boa/interpret.py +++ b/boa/interpret.py @@ -8,6 +8,7 @@ import vvm import vyper +from vyper.ast.parse import parse_to_ast from vyper.cli.vyper_compile import get_search_paths from vyper.compiler.input_bundle import ( ABIInput, @@ -17,6 +18,7 @@ ) from vyper.compiler.phases import CompilerData from vyper.compiler.settings import Settings, anchor_settings +from vyper.semantics.analysis.module import analyze_module from vyper.semantics.types.module import ModuleT from vyper.utils import sha256sum @@ -193,6 +195,7 @@ def loads( def load_abi(filename: str, *args, name: str = None, **kwargs) -> ABIContractFactory: if name is None: name = Path(filename).stem + # TODO: pass filename to ABIContractFactory with open(filename) as fp: return loads_abi(fp.read(), *args, name=name, **kwargs) @@ -253,6 +256,29 @@ def _compile(): return _disk_cache.caching_lookup(cache_key, _compile) +def load_vyi(filename: str, name: str = None) -> ABIContractFactory: + if name is None: + name = Path(filename).stem + with open(filename) as fp: + return loads_vyi(fp.read(), name=name, filename=filename) + + +def loads_vyi(source_code: str, name: str = None, filename: str = None): + global _search_path + + ast = parse_to_ast(source_code) + + if name is None: + name = "VyperContract.vyi" + + search_paths = get_search_paths(_search_path) + input_bundle = FilesystemInputBundle(search_paths) + + module_t = analyze_module(ast, input_bundle, is_interface=True) + abi = module_t.interface.to_toplevel_abi_dict() + return ABIContractFactory(name, abi, filename=filename) + + def from_etherscan( address: Any, name: str = None, uri: str = None, api_key: str = None ): From 6b56b433aa51ddb0d0db8dfb2677ee3cf9560c87 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Mon, 16 Sep 2024 22:52:26 -0400 Subject: [PATCH 2/3] add tests --- boa/__init__.py | 2 ++ tests/unitary/contracts/vyper/test_vyi.py | 37 +++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 tests/unitary/contracts/vyper/test_vyi.py diff --git a/boa/__init__.py b/boa/__init__.py index 2f1b1d74..3374f0a5 100644 --- a/boa/__init__.py +++ b/boa/__init__.py @@ -13,9 +13,11 @@ load, load_abi, load_partial, + load_vyi, loads, loads_abi, loads_partial, + loads_vyi, ) from boa.network import NetworkEnv from boa.precompile import precompile diff --git a/tests/unitary/contracts/vyper/test_vyi.py b/tests/unitary/contracts/vyper/test_vyi.py new file mode 100644 index 00000000..44a2bd0e --- /dev/null +++ b/tests/unitary/contracts/vyper/test_vyi.py @@ -0,0 +1,37 @@ +import pytest +import boa + +FOO_CONTRACT = """ +@external +def foo() -> uint256: + return 5 +""" + +FOO_INTERFACE = """ +@external +def foo() -> uint256: + ... +""" + +@pytest.fixture +def foo_contract(): + return boa.loads(FOO_CONTRACT) + +@pytest.fixture +def foo_interface(foo_contract): + return boa.loads_vyi(FOO_INTERFACE).at(foo_contract.address) + +# from file +@pytest.fixture +def foo_interface2(foo_contract, tmp_path): + p = tmp_path / "foo.vyi" + with p.open("w") as f: + f.write(FOO_INTERFACE) + return boa.load_vyi(p).at(foo_contract.address) + + +def test_foo_interface(foo_interface): + assert foo_interface.foo() == 5 + +def test_foo_interface2(foo_interface2): + assert foo_interface2.foo() == 5 From 9efd375759e8551c07e3618ba3e15a69a7ac8754 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Wed, 18 Sep 2024 15:56:25 -0400 Subject: [PATCH 3/3] fix lint --- tests/unitary/contracts/vyper/test_vyi.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/unitary/contracts/vyper/test_vyi.py b/tests/unitary/contracts/vyper/test_vyi.py index 44a2bd0e..8269c9b2 100644 --- a/tests/unitary/contracts/vyper/test_vyi.py +++ b/tests/unitary/contracts/vyper/test_vyi.py @@ -1,4 +1,5 @@ import pytest + import boa FOO_CONTRACT = """ @@ -13,14 +14,17 @@ def foo() -> uint256: ... """ + @pytest.fixture def foo_contract(): return boa.loads(FOO_CONTRACT) + @pytest.fixture def foo_interface(foo_contract): return boa.loads_vyi(FOO_INTERFACE).at(foo_contract.address) + # from file @pytest.fixture def foo_interface2(foo_contract, tmp_path): @@ -33,5 +37,6 @@ def foo_interface2(foo_contract, tmp_path): def test_foo_interface(foo_interface): assert foo_interface.foo() == 5 + def test_foo_interface2(foo_interface2): assert foo_interface2.foo() == 5