-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
00c2e03
commit ebb75f4
Showing
29 changed files
with
608 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
"""Test fixture for deploying local anvil chain.""" | ||
from __future__ import annotations | ||
|
||
import subprocess | ||
import time | ||
from typing import Iterator | ||
|
||
import pytest | ||
from eth_typing import URI | ||
from web3 import Web3 | ||
from web3.middleware import geth_poa | ||
from web3.types import RPCEndpoint | ||
|
||
|
||
@pytest.fixture(scope="function") | ||
def local_chain() -> Iterator[str]: | ||
"""Launch a local anvil chain for testing and kill the anvil chain after. | ||
Returns | ||
------- | ||
Iterator[str] | ||
Yields the local anvil chain URI | ||
""" | ||
anvil_port = 9999 | ||
host = "127.0.0.1" # localhost | ||
|
||
# Assuming anvil command is accessible in path | ||
# running into issue with contract size without --code-size-limit arg | ||
|
||
# Using context manager here seems to make CI hang, so explicitly killing process at the end of yield | ||
# pylint: disable=consider-using-with | ||
anvil_process = subprocess.Popen( | ||
["anvil", "--silent", "--host", "127.0.0.1", "--port", str(anvil_port), "--code-size-limit", "9999999999"] | ||
) | ||
|
||
local_chain_ = "http://" + host + ":" + str(anvil_port) | ||
|
||
# TODO Hack, wait for anvil chain to initialize | ||
time.sleep(3) | ||
|
||
yield local_chain_ | ||
|
||
# Kill anvil process at end | ||
anvil_process.kill() | ||
|
||
|
||
@pytest.fixture(scope="function") | ||
def w3(local_chain) -> Web3: # pylint: disable=redefined-outer-name | ||
"""gets a Web3 instance connected to the local chain. | ||
Parameters | ||
---------- | ||
local_chain : str | ||
A local anvil chain. | ||
Returns | ||
------- | ||
Web3 | ||
A web3.py instance. | ||
""" | ||
|
||
return initialize_web3_with_http_provider(local_chain) | ||
|
||
|
||
def initialize_web3_with_http_provider( | ||
ethereum_node: URI | str, request_kwargs: dict | None = None, reset_provider: bool = False | ||
) -> Web3: | ||
"""Initialize a Web3 instance using an HTTP provider and inject a geth Proof of Authority (poa) middleware. | ||
Arguments | ||
--------- | ||
ethereum_node: URI | str | ||
Address of the http provider | ||
request_kwargs: dict | ||
The HTTPProvider uses the python requests library for making requests. | ||
If you would like to modify how requests are made, | ||
you can use the request_kwargs to do so. | ||
Notes | ||
----- | ||
The geth_poa_middleware is required to connect to geth --dev or the Goerli public network. | ||
It may also be needed for other EVM compatible blockchains like Polygon or BNB Chain (Binance Smart Chain). | ||
See more `here <https://web3py.readthedocs.io/en/stable/middleware.html#proof-of-authority>`_. | ||
""" | ||
if request_kwargs is None: | ||
request_kwargs = {} | ||
provider = Web3.HTTPProvider(ethereum_node, request_kwargs) | ||
web3 = Web3(provider) | ||
web3.middleware_onion.inject(geth_poa.geth_poa_middleware, layer=0) | ||
if reset_provider: | ||
# TODO: Check that the user is running on anvil, raise error if not | ||
_ = web3.provider.make_request(method=RPCEndpoint("anvil_reset"), params=[]) | ||
return web3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
"""Types for foundry-rs.""" | ||
from typing import Any, Literal, TypedDict | ||
|
||
from web3.types import ABI | ||
|
||
|
||
class FoundryByteCode(TypedDict): | ||
"""Foundry""" | ||
|
||
object: str | ||
sourceMap: str | ||
linkReference: Any | ||
|
||
|
||
class FoundryDeployedByteCode(TypedDict): | ||
"""Foundry""" | ||
|
||
object: str | ||
sourceMap: str | ||
linkReference: Any | ||
|
||
|
||
class FoundryCompiler(TypedDict): | ||
"""Foundry""" | ||
|
||
version: str | ||
|
||
|
||
class FoundryMetadata(TypedDict, total=False): | ||
"""Foundry""" | ||
|
||
compiler: FoundryCompiler | ||
language: Literal["Solidity", "Vyper"] | ||
|
||
|
||
class FoundryJson(TypedDict): | ||
"""Foundry""" | ||
|
||
abi: ABI | ||
bytecode: FoundryByteCode | ||
deployedBytecode: FoundryDeployedByteCode | ||
methodIdentifiers: dict[str, str] | ||
rawMetadata: str | ||
metadata: FoundryMetadata | ||
ast: Any | ||
id: int |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
"""Utilities for working with foundry-rs.""" | ||
from typing import TypeGuard | ||
|
||
from pypechain.foundry.types import FoundryJson | ||
|
||
|
||
def is_foundry_json(val: object) -> TypeGuard[FoundryJson]: | ||
"""Determines whether a json object is a FoundryJson.""" | ||
required_keys = {"abi", "bytecode", "deployedBytecode", "methodIdentifiers", "rawMetadata", "metadata", "ast", "id"} | ||
return isinstance(val, dict) and required_keys.issubset(val.keys()) | ||
|
||
|
||
def get_bytecode_from_foundry_json(json_abi: FoundryJson) -> str: | ||
"""Gets the bytecode from a foundry json file.""" | ||
return json_abi.get("bytecode").get("object") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
"""Types for solc.""" | ||
|
||
from typing import TypedDict | ||
|
||
from web3.types import ABI | ||
|
||
|
||
class SolcContract(TypedDict): | ||
"""Foundry""" | ||
|
||
abi: ABI | ||
bin: str | ||
metadata: str | ||
|
||
|
||
class SolcJson(TypedDict): | ||
"""Foundry""" | ||
|
||
contracts: dict[str, SolcContract] | ||
version: str |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
"""Utilities for working with solc.""" | ||
from typing import TypeGuard | ||
|
||
from pypechain.solc.types import SolcJson | ||
|
||
|
||
def is_solc_json(val: object) -> TypeGuard[SolcJson]: | ||
"""Determines whether a json object is a SolcJson.""" | ||
return ( | ||
isinstance(val, dict) | ||
and "contracts" in val | ||
and isinstance(val["contracts"], dict) | ||
and all( | ||
isinstance(contract, dict) and "abi" in contract and "bin" in contract and "metadata" in contract | ||
for contract in val["contracts"].values() | ||
) | ||
and "version" in val | ||
) | ||
|
||
|
||
def get_bytecode_from_solc_json(json_abi: SolcJson) -> str: | ||
"""Gets the bytecode from a foundry json file.""" | ||
# assume one contract right now | ||
contract = list(json_abi.get("contracts").values())[0] | ||
binary = contract.get("bin") | ||
return f"0x{binary}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,4 @@ | ||
{{contract_name | lower}}_abi: ABI = cast(ABI, {{abi}}) | ||
{{contract_name | lower}}_abi: ABI = cast(ABI, {{abi}}) | ||
{% if bytecode %}# pylint: disable=line-too-long | ||
{{contract_name | lower}}_bytecode = HexStr("{{bytecode}}") | ||
{%- endif -%} |
Oops, something went wrong.