Web3.py – Issues Connecting to Etherscan Ropsten API via Web3.py

ropstentestrpc-to-ropstenweb3.py

I am developing a simple application that transfers tokens between users. The token in an ERC20 standard token.

I am really new to the web3 and ethereum development world and I am confused by quite a few things. It would be nice I someone could show where my mistake is.

The contract for the token in deployed on the ropsten testnet and I wanted to call balanceOf() and transfer() functions. However, calling the balanceOf() function in form .call().balanceOf() gives an error:

File "/home/blah/blah/transactions.py", line 26, in <module>
    CONTRACT.call().balanceOf("0x70d704ab702097427Bba427492c86493e8B7597b") File "/usr/local/lib/python3.5/dist-packages/web3/contract.py", line 772, in call_contract_function
    return_data = contract.web3.eth.call(call_transaction)   File "/usr/local/lib/python3.5/dist-packages/web3/eth.py", line 266, in call
    formatted_transaction = formatters.input_transaction_formatter(self, transaction)   File "/usr/local/lib/python3.5/dist-packages/eth_utils/string.py", line 71, in inner
    return fn(*text_args, **text_kwargs)   File "/usr/local/lib/python3.5/dist-packages/eth_utils/string.py", line 85, in inner
    return force_obj_to_text(fn(*args, **kwargs))   File "/usr/local/lib/python3.5/dist-packages/web3/formatters.py", line 125, in input_transaction_formatter
    'from': eth.coinbase,   File "/usr/local/lib/python3.5/dist-packages/eth_utils/string.py", line 85, in inner
    return force_obj_to_text(fn(*args, **kwargs))   File "/usr/local/lib/python3.5/dist-packages/web3/eth.py", line 70, in coinbase
    return self.web3._requestManager.request_blocking("eth_coinbase", [])   File "/usr/local/lib/python3.5/dist-packages/web3/providers/manager.py", line 30, in request_blocking
    response = json.loads(force_text(response_raw))   File "/usr/lib/python3.5/json/__init__.py", line 319, in loads
    return _default_decoder.decode(s)   File "/usr/lib/python3.5/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())   File "/usr/lib/python3.5/json/decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

I am not sure if this is an error regarding HTTPProvider not connecting to the "https://ropsten.etherscan.io", or is the url that I have used to the HTTPProvider not correct for the ropsten testnet, or some other issue. I have double checked the contract address as well as the contract ABI. Or is it some problem regarding lack of gas/ether associated with account?

I tried testing another similar contract on the private testnet, and the same code was working well.

Best Answer

[This might be] an error regarding HTTPProvider not connecting to the "https://ropsten.etherscan.io"

That's correct, you cannot use the etherscan.io API as a JSON-RPC server.

Instead, I'd recommend running an Ethereum node locally that is synced with Ropsten, similar to how (I presume) you ran the private testnet.

One way to do that would be:

parity --chain ropsten

You can then connect with:

from web3 import Web3, HTTPProvider
web3 = Web3(HTTPProvider("http://localhost:8545"))
assert web3.isConnected()

Naturally, you'll need to create an account before the balanceOf() call will work. For the transfer() function to work, you'll also need to send the account ropsten ether.

API Comparison

Let's look at how each API sends the latest block number.

Etherscan

To get the current block number with the etherscan.io API, you would use a GET call, specifying eth_blockNumber as the action parameter.

eth_blockNumber
Returns the number of most recent block

https://ropsten.etherscan.io/api?module=proxy&action=eth_blockNumber&apikey=YourApiKeyToken

like so:

curl "https://ropsten.etherscan.io/api?module=proxy&action=eth_blockNumber"

Ethereum JSON-RPC server

In contrast, JSON-RPC specifies the API as a POST call, with eth_blockNumber sent as the method parameter, like so:

// Request
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":83}'

// Result
{
  "id":83,
  "jsonrpc": "2.0",
  "result": "0x4b7" // 1207
}