Skip to content
/ ape Public
forked from ApeWorX/ape

Commit a79ae0a

Browse files
authored
feat: support upstream providers (#258)
1 parent 5917c19 commit a79ae0a

File tree

8 files changed

+34
-15
lines changed

8 files changed

+34
-15
lines changed

src/ape/api/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
TransactionAPI,
1212
TransactionStatusEnum,
1313
TransactionType,
14+
UpstreamProvider,
1415
Web3Provider,
1516
)
1617

@@ -35,5 +36,6 @@
3536
"TransactionAPI",
3637
"TransactionStatusEnum",
3738
"TransactionType",
39+
"UpstreamProvider",
3840
"Web3Provider",
3941
]

src/ape/api/networks.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ def __getitem__(self, network_name: str) -> "NetworkAPI":
7878
return self._try_get_network(network_name)
7979

8080
def __getattr__(self, network_name: str) -> "NetworkAPI":
81+
network_name = network_name.replace("_", "-")
8182
return self._try_get_network(network_name)
8283

8384
def add_network(self, network_name: str, network: "NetworkAPI"):
@@ -257,11 +258,7 @@ def providers(self): # -> Dict[str, Partial[ProviderAPI]]
257258
request_header=self.request_header,
258259
)
259260

260-
if len(providers) > 0:
261-
return providers
262-
263-
else:
264-
raise NetworkError("No network providers found")
261+
return providers
265262

266263
def get_provider(
267264
self,

src/ape/api/providers.py

+14-2
Original file line numberDiff line numberDiff line change
@@ -185,12 +185,10 @@ def gas_price(self) -> int:
185185
...
186186

187187
@property
188-
@abstractmethod
189188
def priority_fee(self) -> int:
190189
raise NotImplementedError("priority_fee is not implemented by this provider")
191190

192191
@property
193-
@abstractmethod
194192
def base_fee(self) -> int:
195193
raise NotImplementedError("base_fee is not implemented by this provider")
196194

@@ -320,3 +318,17 @@ def send_transaction(self, txn: TransactionAPI) -> ReceiptAPI:
320318
txn_hash = self._web3.eth.send_raw_transaction(txn.encode())
321319
receipt = self.get_transaction(txn_hash.hex())
322320
return receipt
321+
322+
323+
class UpstreamProvider(ProviderAPI):
324+
"""
325+
A provider that can also be set as another provider's upstream.
326+
"""
327+
328+
@property
329+
@abstractmethod
330+
def connection_str(self) -> str:
331+
"""
332+
The str used by downstream providers to connect to this one.
333+
For example, the URL for HTTP-based providers.
334+
"""

src/ape_ethereum/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@ def networks():
2020
for network_name, network_params in NETWORKS.items():
2121
yield "ethereum", network_name, create_network_type(*network_params)
2222

23-
# NOTE: This works for `geth --dev` as it gets chain_id from itself
23+
# NOTE: This works for development providers, as they get chain_id from themselves
2424
yield "ethereum", "development", NetworkAPI
25+
yield "ethereum", "mainnet-fork", NetworkAPI

src/ape_geth/providers.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from web3.middleware import geth_poa_middleware
1717
from web3.types import NodeInfo
1818

19-
from ape.api import ReceiptAPI, TransactionAPI, Web3Provider
19+
from ape.api import ReceiptAPI, TransactionAPI, UpstreamProvider, Web3Provider
2020
from ape.api.config import ConfigItem
2121
from ape.exceptions import ContractLogicError, ProviderError, TransactionError, VirtualMachineError
2222
from ape.logging import logger
@@ -134,13 +134,17 @@ def __init__(self):
134134
)
135135

136136

137-
class GethProvider(Web3Provider):
137+
class GethProvider(Web3Provider, UpstreamProvider):
138138
_geth: Optional[EphemeralGeth] = None
139139

140140
@property
141141
def uri(self) -> str:
142142
return getattr(self.config, self.network.ecosystem.name)[self.network.name]["uri"]
143143

144+
@property
145+
def connection_str(self) -> str:
146+
return self.uri
147+
144148
def connect(self):
145149
self._web3 = Web3(HTTPProvider(self.uri))
146150

src/ape_networks/_cli.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,13 @@ def make_sub_tree(data: Dict, create_tree: Callable) -> Tree:
3737
ecosystem_tree = make_sub_tree(ecosystem, Tree)
3838
_networks = ecosystem["networks"]
3939
for network in _networks:
40-
network_tree = make_sub_tree(network, ecosystem_tree.add)
4140
providers = network["providers"]
42-
for provider in providers:
43-
make_sub_tree(provider, network_tree.add)
41+
if providers:
42+
network_tree = make_sub_tree(network, ecosystem_tree.add)
43+
for provider in providers:
44+
make_sub_tree(provider, network_tree.add)
4445

45-
echo_rich_text(ecosystem_tree)
46+
if _networks:
47+
echo_rich_text(ecosystem_tree)
4648
elif output_format == OutputFormat.YAML:
4749
click.echo(networks.networks_yaml.strip())

tests/integration/cli/test_networks.py

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
- name: geth
4646
isDefault: true
4747
- name: test
48+
- name: mainnet-fork
4849
"""
4950

5051

tests/integration/cli/test_run.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
@skip_projects(["script"])
77
def test_run_no_scripts_dir(ape_cli, runner, project):
88
result = runner.invoke_using_test_network(ape_cli, ["run", BAD_COMMAND])
9-
assert result.exit_code == 1
9+
assert result.exit_code == 1, result.output
1010
assert "No 'scripts/' directory detected to run script" in result.output
1111

1212

0 commit comments

Comments
 (0)