Skip to content

Commit

Permalink
Moves Etherscan API key to env var
Browse files Browse the repository at this point in the history
Makes the Etherscan API key name explicit as we'll now also have Infura
one. Also moves it to an environment variable for consistency with web3
and Infura.
Also adds a documentation note on the API keys, fixes #9
  • Loading branch information
AndreMiras committed Mar 21, 2020
1 parent 22eb591 commit eabd7d6
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 29 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ etheroll = Etheroll(chain_id, contract_address)

Find out more in [docs/Examples.md](docs/Examples.md).

## API keys
Both Etherscan and Infura require API keys which are retrieved from the following environment variables:
- `ETHERSCAN_API_KEY` (consumed by pyetheroll directly)
- `WEB3_INFURA_PROJECT_ID` (consumed by [web3.py](https://github.com/ethereum/web3.py))

## Install

[Latest stable release](https://github.com/AndreMiras/pyetheroll/tree/master):
Expand Down
3 changes: 2 additions & 1 deletion pyetheroll/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
ROUND_DIGITS = 2
DEFAULT_GAS_PRICE_GWEI = 4
DEFAULT_GAS_PRICE_WEI = int(DEFAULT_GAS_PRICE_GWEI * 1e9)
DEFAULT_API_KEY_TOKEN = "YourApiKeyToken"
DEFAULT_ETHERSCAN_API_KEY = "YourApiKeyToken"
DEFAULT_INFURA_PROJECT_ID = "7c841c560b1e4660a9683507cb27b2f8"


class ChainID(Enum):
Expand Down
31 changes: 12 additions & 19 deletions pyetheroll/etheroll.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,7 @@
from web3 import Web3
from web3.contract import Contract

from pyetheroll.constants import (
DEFAULT_API_KEY_TOKEN,
DEFAULT_GAS_PRICE_WEI,
ROUND_DIGITS,
ChainID,
)
from pyetheroll.constants import DEFAULT_GAS_PRICE_WEI, ROUND_DIGITS, ChainID
from pyetheroll.etherscan_utils import (
ChainEtherscanAccountFactory,
ChainEtherscanContractFactory,
Expand All @@ -27,7 +22,7 @@
HTTPProviderFactory,
TransactionDebugger,
)
from pyetheroll.utils import timestamp2datetime
from pyetheroll.utils import get_etherscan_api_key, timestamp2datetime

REQUESTS_CACHE_PARAMS = {
"cache_name": "requests_cache",
Expand Down Expand Up @@ -83,7 +78,6 @@ class Etheroll:

def __init__(
self,
api_key: str = DEFAULT_API_KEY_TOKEN,
chain_id: ChainID = ChainID.MAINNET,
contract_address: str = None,
):
Expand All @@ -96,7 +90,7 @@ def __init__(
# self.provider = EthereumTesterProvider(ethereum_tester)
self.provider = HTTPProviderFactory.create(self.chain_id)
self.web3 = Web3(self.provider)
self.etherscan_api_key = api_key
self.etherscan_api_key = get_etherscan_api_key()
ChainEtherscanContract = ChainEtherscanContractFactory.create(
self.chain_id
)
Expand All @@ -111,7 +105,8 @@ def __init__(
address=self.contract_address, api_key=self.etherscan_api_key
)
self.etherscan_contract_api.http.headers = update_user_agent(
self.etherscan_contract_api.http.headers)
self.etherscan_contract_api.http.headers
)
self.contract_abi = json.loads(
self.etherscan_contract_api.get_abi()
)
Expand All @@ -130,22 +125,18 @@ def __init__(

@classmethod
def get_or_create(
cls,
api_key: str = DEFAULT_API_KEY_TOKEN,
chain_id: ChainID = ChainID.MAINNET,
contract_address: str = None,
cls, chain_id: ChainID = ChainID.MAINNET, contract_address: str = None,
):
"""
Gets or creates the Etheroll object.
Also recreates the object if one init property changed.
"""
contract_address = contract_address or cls.CONTRACT_ADDRESSES[chain_id]
if cls._etheroll is None or (
cls._etheroll.etherscan_api_key,
cls._etheroll.chain_id,
cls._etheroll.contract_address,
) != (api_key, chain_id, contract_address):
cls._etheroll = cls(api_key, chain_id, contract_address)
) != (chain_id, contract_address):
cls._etheroll = cls(chain_id, contract_address)
return cls._etheroll

def definitions(self, contract_abi, typ):
Expand Down Expand Up @@ -284,7 +275,8 @@ def get_transaction_page(
address=address, api_key=self.etherscan_api_key
)
etherscan_account_api.http.headers = update_user_agent(
etherscan_account_api.http.headers)
etherscan_account_api.http.headers
)
sort = "desc"
try:
transactions = etherscan_account_api.get_transaction_page(
Expand Down Expand Up @@ -612,7 +604,8 @@ def get_balance(self, address):
address=address, api_key=self.etherscan_api_key
)
etherscan_account_api.http.headers = update_user_agent(
etherscan_account_api.http.headers)
etherscan_account_api.http.headers
)
balance_wei = int(etherscan_account_api.get_balance())
balance_eth = round(balance_wei / 1e18, ROUND_DIGITS)
return balance_eth
16 changes: 10 additions & 6 deletions pyetheroll/transaction_debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
from eth_utils import decode_hex, function_abi_to_4byte_selector
from web3 import HTTPProvider, Web3

from pyetheroll.constants import DEFAULT_API_KEY_TOKEN, ChainID
from pyetheroll.constants import ChainID
from pyetheroll.etherscan_utils import ChainEtherscanContractFactory
from pyetheroll.utils import get_etherscan_api_key, get_infura_project_id


def decode_contract_call(contract_abi: list, call_data: str):
Expand All @@ -30,10 +31,14 @@ class HTTPProviderFactory:
# ChainID.MAINNET: 'https://api.myetherapi.com/eth',
# ChainID.MAINNET: 'https://api.infura.io/v1/jsonrpc/mainnet',
# ChainID.MAINNET: 'https://api.mycryptoapi.com/eth',
ChainID.MAINNET: "https://mainnet.infura.io",
ChainID.MAINNET: (
f"https://mainnet.infura.io/v3/{get_infura_project_id()}"
),
# ChainID.ROPSTEN: 'https://api.myetherapi.com/rop',
# ChainID.ROPSTEN: 'https://api.infura.io/v1/jsonrpc/ropsten',
ChainID.ROPSTEN: "https://ropsten.infura.io",
ChainID.ROPSTEN: (
f"https://ropsten.infura.io/v3/{get_infura_project_id()}"
),
}

@classmethod
Expand All @@ -48,13 +53,12 @@ def __init__(self, contract_abi):
self.methods_infos = None

@staticmethod
def get_contract_abi(
chain_id, contract_address, api_key: str = DEFAULT_API_KEY_TOKEN
) -> dict:
def get_contract_abi(chain_id, contract_address) -> dict:
"""
Given a contract address returns the contract ABI from Etherscan,
refs #2
"""
api_key = get_etherscan_api_key()
ChainEtherscanContract = ChainEtherscanContractFactory.create(chain_id)
api = ChainEtherscanContract(address=contract_address, api_key=api_key)
json_abi = api.get_abi()
Expand Down
17 changes: 16 additions & 1 deletion pyetheroll/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import os
from datetime import datetime

from pyetheroll.constants import ROUND_DIGITS
from pyetheroll.constants import (
DEFAULT_ETHERSCAN_API_KEY,
DEFAULT_INFURA_PROJECT_ID,
ROUND_DIGITS,
)


class EtherollUtils:
Expand Down Expand Up @@ -34,3 +39,13 @@ def timestamp2datetime(timestamp: str) -> datetime:
base = 16
date_time = datetime.utcfromtimestamp(int(timestamp, base))
return date_time


def get_etherscan_api_key():
"""Returns ETHERSCAN_API_KEY from environment variable."""
return os.environ.get("ETHERSCAN_API_KEY", DEFAULT_ETHERSCAN_API_KEY)


def get_infura_project_id():
"""Returns WEB3_INFURA_PROJECT_ID from environment variable."""
return os.environ.get("WEB3_INFURA_PROJECT_ID", DEFAULT_INFURA_PROJECT_ID)
4 changes: 2 additions & 2 deletions tests/test_etheroll.py
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ def test_get_log_bet_events(self):
"&topic2=0x"
"00000000000000000000000046044beaa1e985c67767e04de58181de5daaa00f"
"&topic0_2_opr=and&",
headers={'User-Agent': 'https://github.com/AndreMiras/pyetheroll'},
headers={"User-Agent": "https://github.com/AndreMiras/pyetheroll"},
)
expected_calls = [expected_call]
assert m_get.call_args_list == expected_calls
Expand Down Expand Up @@ -655,7 +655,7 @@ def test_get_log_result_events(self):
"&topic3=0x"
"00000000000000000000000046044beaa1e985c67767e04de58181de5daaa00f"
"&topic0_3_opr=and&",
headers={'User-Agent': 'https://github.com/AndreMiras/pyetheroll'},
headers={"User-Agent": "https://github.com/AndreMiras/pyetheroll"},
)
expected_calls = [expected_call]
assert m_get.call_args_list == expected_calls
Expand Down

0 comments on commit eabd7d6

Please sign in to comment.