Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat etherscan api #492

Merged
merged 4 commits into from
May 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions brownie/network/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,8 @@ def from_explorer(
as_proxy_for : str, optional
Address of the implementation contract, if `address` is a proxy contract.
The generated object will send transactions to `address`, but use the ABI
and NatSpec of `as_proxy_for`.
and NatSpec of `as_proxy_for`. This field is only required when the
block explorer API does not provide an implementation address.
owner : Account, optional
Contract owner. If set, transactions without a `from` field will be
performed using this account.
Expand All @@ -596,18 +597,21 @@ def from_explorer(
else:
# if the source is not available, try to fetch only the ABI
try:
data = _fetch_from_explorer(address, "getabi", True)
data_abi = _fetch_from_explorer(address, "getabi", True)
except ValueError as exc:
_unverified_addresses.add(address)
raise exc
abi = json.loads(data["result"].strip())
abi = json.loads(data_abi["result"].strip())
name = "UnknownContractName"
warnings.warn(
f"{address}: Was able to fetch the ABI but not the source code. "
"Some functionality will not be available.",
BrownieCompilerWarning,
)

if as_proxy_for is None and data["result"][0].get("Implementation"):
as_proxy_for = _resolve_address(data["result"][0]["Implementation"])

# if this is a proxy, fetch information for the implementation contract
if as_proxy_for is not None:
implementation_contract = Contract.from_explorer(as_proxy_for)
Expand Down Expand Up @@ -639,7 +643,14 @@ def from_explorer(
"enabled": bool(int(data["result"][0]["OptimizationUsed"])),
"runs": int(data["result"][0]["Runs"]),
}
build = compile_and_format(sources, solc_version=str(version), optimizer=optimizer)

evm_version = data["result"][0].get("EVMVersion", "Default")
if evm_version == "Default":
evm_version = None

build = compile_and_format(
sources, solc_version=str(version), optimizer=optimizer, evm_version=evm_version
)
build = build[name]
if as_proxy_for is not None:
build.update(abi=abi, natspec=implementation_contract._build.get("natspec"))
Expand Down
6 changes: 3 additions & 3 deletions brownie/project/compiler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from copy import deepcopy
from hashlib import sha1
from pathlib import Path
from typing import Dict, Optional, Union
from typing import Dict, Optional

from eth_utils import remove_0x_prefix
from semantic_version import Version
Expand Down Expand Up @@ -49,7 +49,7 @@ def compile_and_format(
solc_version: Optional[str] = None,
optimize: bool = True,
runs: int = 200,
evm_version: int = None,
evm_version: Optional[str] = None,
silent: bool = True,
allow_paths: Optional[str] = None,
interface_sources: Optional[Dict[str, str]] = None,
Expand Down Expand Up @@ -143,7 +143,7 @@ def generate_input_json(
contract_sources: Dict[str, str],
optimize: bool = True,
runs: int = 200,
evm_version: Union[int, str, None] = None,
evm_version: Optional[str] = None,
language: str = "Solidity",
interface_sources: Optional[Dict[str, str]] = None,
remappings: Optional[list] = None,
Expand Down
2 changes: 1 addition & 1 deletion docs/api-network.rst
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ New ``Contract`` objects are created with one of the following class methods.
Create a new ``Contract`` object from source code fetched from a block explorer such as `EtherScan <https://etherscan.io/>`_ or `Blockscout <https://blockscout.com/>`_.

* ``address``: Address of the contract.
* ``as_proxy_for``: Address of the implementation contract, if ``address`` is a proxy contract. The generated object sends transactions to ``address``, but uses the ABI and NatSpec of ``as_proxy_for``.
* ``as_proxy_for``: Address of the implementation contract, if ``address`` is a proxy contract. The generated object sends transactions to ``address``, but uses the ABI and NatSpec of ``as_proxy_for``. This field is only required when the block explorer API does not provide an implementation address.
* ``owner``: An optional :func:`Account <brownie.network.account.Account>` instance. If given, transactions to the contract are sent broadcasted from this account by default.

If the deployed bytecode was generated using a compatible compiler version, Brownie will attempt to recompile it locally. If successful, most debugging functionality will be available.
Expand Down
3 changes: 2 additions & 1 deletion tests/network/contract/test_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,8 @@ def test_as_proxy_for(network):
as_proxy_for="0x97BD4Cc841FC999194174cd1803C543247a014fe",
)
implementation = Contract("0x97BD4Cc841FC999194174cd1803C543247a014fe")
assert original.abi != proxy.abi

assert original.abi == proxy.abi
assert original.address == proxy.address

assert proxy.abi == implementation.abi
Expand Down