Packages

Etherscan.io API wrapper for Elixir. Provides access to ethereum blockchain data.

Current section

Files

Jump to
etherscan lib etherscan.ex
Raw

lib/etherscan.ex

defmodule Etherscan do
@moduledoc """
Documentation for Etherscan.
"""
@api_base "https://api.etherscan.io/api"
@api_key ""
@ether_val 1000000000000000000
@balance_address_limit 20
@account_transaction_params [:startblock, :endblock, :sort, :page, :offset]
@blocks_mined_params [:blocktype, :page, :offset]
#
# Accounts. See - https://etherscan.io/apis#accounts
#
@doc """
Get ether balance for a single `address`. `address` can be a list of
multiple `addresses`, up to a maximum of 20 `addresses`.
If given an `address`, returns balance in ether.
If given a list of `addresses`, returns a list of balances.
"""
def get_balance(address) when is_binary(address) do
params = account_balance_params(address)
call_api("account", "balance", params)
|> to_eth()
end
def get_balance(addresses) when is_list(addresses) and length(addresses) <= @balance_address_limit do
params = account_balance_params(addresses)
call_api("account", "balancemulti", params)
|> format_account_balance()
end
@doc """
*BETA*
Get a list of 'Normal' transactions by `address`. Returns up to a maximum
of the last 10000 transactions only.
```
params = %{
page: 1, // Page number
offset: 10, // Max records returned
sort: "asc", // Sort returned records
startblock: 0, // Start block number
endblock: 99999999 // End block number
}
```
"""
# TODO: Returned 'isError' values: 0=No Error, 1=Got Error
def get_transactions(address, params \\ %{}) do
params = account_transaction_params(address, params)
call_api("account", "txlist", params)
end
@doc """
*BETA*
Get a list of 'Internal' transactions by `address`. Returns up to a maximum
of the last 10000 transactions only.
```
params = %{
page: 1, // Page number
offset: 10, // Max records returned
sort: "asc", // Sort returned records
startblock: 0, // Start block number
endblock: 99999999 // End block number
}
```
"""
# TODO: Returned 'isError' values: 0=No Error, 1=Got Error
def get_internal_transactions(address, params \\ %{}) do
params = account_transaction_params(address, params)
call_api("account", "txlistinternal", params)
end
@doc """
Get a list of 'Internal Transactions' by `transaction_hash`. Returns up to
a maximum of the last 10000 transactions only.
"""
# TODO: Returned 'isError' values: 0=Ok, 1=Rejected/Cancelled
def get_internal_transactions_by_hash(transaction_hash) do
params = internal_transaction_params(transaction_hash)
call_api("account", "txlistinternal", params)
end
@doc """
Get a list of blocks mined by `address`.
```
params = %{
page: 1, // Page number
offset: 10 // Max records returned
}
```
"""
def get_blocks_mined(address, params \\ %{}) do
params = blocks_mined_params(address, params)
call_api("account", "getminedblocks", params)
end
@doc """
Get a list of uncles mined by `address`.
```
params = %{
page: 1, // Page number
offset: 10 // Max records returned
}
```
"""
def get_uncles_mined(address, params \\ %{}) do
params = uncles_mined_params(address, params)
call_api("account", "getminedblocks", params)
end
@doc """
Get the ERC20 token balance of the `address` for token at `token_address`.
"""
def get_token_balance(address, token_address) do
params = token_balance_params(address, token_address)
call_api("account", "tokenbalance", params)
end
#
# Blocks. See - https://etherscan.io/apis#blocks
#
@doc """
*BETA*
Get block and uncle rewards by `block_number`.
Returns a map of data:
```
%{
"blockMiner" => "0xc8ebccc5f5689fa8659d83713341e5ad19349448",
"blockNumber" => "4",
"blockReward" => "5156250000000000000",
"timeStamp" => "1438270077",
"uncleInclusionReward" => "156250000000000000",
"uncles" => [%{
"blockreward" => "3125000000000000000",
"miner" => "0x5088d623ba0fcf0131e0897a91734a4d83596aa0",
"unclePosition" => "0"
}]
}
```
"""
def get_block_and_uncle_rewards(block_number) do
params = block_and_uncle_reward_params(block_number)
call_api("block", "getblockreward", params)
end
#
# Contracts. See - https://etherscan.io/apis#contracts
#
@doc """
Get contract ABI for contracts with verified source code, by `address`.
See - https://etherscan.io/contractsVerified
"""
def get_contract_abi(address) do
params = contract_abi_params(address)
call_api("contract", "getabi", params)
end
#
# Stats. See - https://etherscan.io/apis#stats
#
@doc """
Get total supply of ether.
"""
def get_eth_supply do
call_api("stats", "ethsupply")
|> to_eth()
end
@doc """
Get ether price.
"""
def get_eth_price do
call_api("stats", "ethprice")
end
@doc """
Get total supply of ERC20 token, by `token_address`.
"""
def get_token_supply(token_address) do
params = token_supply_params(token_address)
call_api("stats", "tokensupply", params)
end
#
# Transactions. See - https://etherscan.io/apis#transactions
#
@doc """
*BETA*
Check contract execution status (if there was an error during
contract execution) by `transaction_hash`.
"""
# TODO: Returned 'isError' values: 0=Pass, 1=Error during Contract Execution
def get_contract_execution_status(transaction_hash) do
params = contract_execution_status_params(transaction_hash)
call_api("transaction", "getstatus", params)
end
#
# Account Params
#
defp account_balance_params(address) when is_binary(address) do
%{
tag: "latest",
address: address
}
end
defp account_balance_params(addresses) when is_list(addresses) do
%{
tag: "latest",
address: Enum.join(addresses, ",")
}
end
defp account_transaction_params(address, params) do
params
|> Map.take(@account_transaction_params)
|> Map.put(:address, address)
end
defp internal_transaction_params(transaction_hash) do
%{txhash: transaction_hash}
end
defp blocks_mined_params(address, params) do
params
|> Map.take(@blocks_mined_params)
|> Map.put(:address, address)
end
defp uncles_mined_params(address, params) do
params
|> Map.take(@blocks_mined_params)
|> Map.put(:blocktype, "uncles")
|> Map.put(:address, address)
end
defp token_balance_params(address, token_address) do
%{
tag: "latest",
address: address,
contractaddress: token_address
}
end
#
# Block Params
#
defp block_and_uncle_reward_params(block_number) do
%{blockno: block_number}
end
#
# Contract Params
#
defp contract_abi_params(address) do
%{address: address}
end
#
# Token Params
#
defp token_supply_params(token_address) do
%{contractaddress: token_address}
end
#
# Transaction Params
#
defp contract_execution_status_params(transaction_hash) do
%{txhash: transaction_hash}
end
#
# Api
#
defp call_api(module, action, params \\ %{}) do
build_query(module, action, params)
|> build_path()
|> HTTPoison.get!([], [recv_timeout: 10000])
|> Map.get(:body)
|> Poison.decode!
|> Map.get("result")
end
defp build_path(query), do: @api_base <> "?" <> query
defp build_query(module, action, params) do
params
|> Map.put(:action, action)
|> Map.put(:module, module)
|> Map.put(:apikey, @api_key)
|> URI.encode_query
end
defp to_eth(value) when is_integer(value), do: value / @ether_val
defp to_eth(value) when is_binary(value) do
value
|> String.to_integer
|> to_eth()
end
defp format_account_balance(accounts) when is_list(accounts) do
Enum.map(accounts, &format_account_balance/1)
end
defp format_account_balance(account) do
balance =
account
|> Map.get("balance")
|> to_eth()
Map.put(account, "balance", balance)
end
end