Module: Etherscan

Defined in:
lib/etherscan-lite.rb,
lib/etherscan-lite/base.rb,
lib/etherscan-lite/misc.rb,
lib/etherscan-lite/proxy.rb,
lib/etherscan-lite/account.rb,
lib/etherscan-lite/contract.rb

Overview

add (shared) “global” config

Defined Under Namespace

Classes: Configuration

Constant Summary collapse

BASE =
'https://api.etherscan.io/api'

Class Method Summary collapse

Class Method Details

.call(src) ⇒ Object

get response as (parsed) json (hash table)



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/etherscan-lite/base.rb', line 5

def self.call( src )   ## get response as (parsed) json (hash table)


  headers = {
    # 'User-Agent' => "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36",

    'User-Agent' => "ruby v#{RUBY_VERSION}",
   }

  response = Webclient.get( src, headers: headers )

  if response.status.ok?
    puts "#{response.status.code} #{response.status.message} -  content_type: #{response.content_type}, content_length: #{response.content_length}"

    data = response.json

    ## note:  "unwrap" result - and auto-check status/message e.g.

    ##   {"status"=>"1",

    ##    "message"=>"OK",

    ##    "result"=>  ..

    ##    }

    ##

    ## An API call that encounters an error  will return 0 as its status code and display the cause of the error under the result field.

    ## {

    ##   "status":"0",

    ##   "message":"NOTOK",

    ##   "result":"Max rate limit reached, please use API Key for higher rate limit"

    ## }


    ##

    #  note: add special error handling case for no transaction found!!

    # ==> [8] query 0x01c59869B44F3Fc5420dbB9166a735CdC020E9Ae...

    # [debug] GET /api?module=account&action=txlist&address=...

    # 200 OK -  content_type: application/json, content_length: 172

    # !! ETHERSCAN API ERROR:

    # 0 No transactions found - []


    if data['status'] == '0' && data['message'] == 'No transactions found' && data['result'].empty?
      data['result']
    elsif data['status'] == '1' && data['message'] == 'OK'
      ## puts "#{data['status']} #{data['message']}"

      data['result']
    else
      puts "!! ETHERSCAN API ERROR:"
      puts "#{data['status']} #{data['message']} - #{data['result']}"
      exit 1
    end
  else
    puts "!! HTTP ERROR:"
    puts "#{response.status.code} #{response.status.message}"
    exit 1
  end
end

.configObject



43
# File 'lib/etherscan-lite.rb', line 43

def self.config()    @config ||= Configuration.new;  end

.configure {|config| ... } ⇒ Object

lets you use

Ethersan.configure do |config|
   config.key = 'xxxx'
end

Yields:



42
# File 'lib/etherscan-lite.rb', line 42

def self.configure() yield( config ); end

.getblockbynumber(**kwargs) ⇒ Object



40
41
42
43
# File 'lib/etherscan-lite/proxy.rb', line 40

def self.getblockbynumber( **kwargs )
  ## note: requires proxy_call!!! - different return / response format in json!!

  proxy_call( getblockbynumber_url( **kwargs ) )
end

.getblockbynumber_url(blocknumber:, transactions: false) ⇒ Object

eth_getBlockByNumber

  Returns information about a block by block number.
    see https://docs.etherscan.io/api-endpoints/geth-parity-proxy#eth_getblockbynumber

the boolean value to show full transaction objects.
   when true, returns full transaction objects and their information,
   when false only returns a list of transactions.


32
33
34
35
36
37
38
# File 'lib/etherscan-lite/proxy.rb', line 32

def self.getblockbynumber_url( blocknumber:, transactions: false )
  src = "#{BASE}?module=proxy&action=eth_getBlockByNumber" +
         "&tag=#{blocknumber}" +    ## note - must be a hexstring !!! e.g. 0x10d4f

         "&boolean=#{transactions}" +   ## " note:must be true or false

         "&apikey=#{config.key}"
  src
end

.getcontractcreation(**kwargs) ⇒ Object



16
17
18
# File 'lib/etherscan-lite/contract.rb', line 16

def self.getcontractcreation( **kwargs )
  call( getcontractcreation_url( **kwargs ) )
end

.getcontractcreation_url(contractaddresses:) ⇒ Object

Get Contract Creator and Creation Tx Hash

Returns a contract's deployer address and transaction hash

it was created, up to 5 at a time.

see https://docs.etherscan.io/api-endpoints/contracts#get-contract-creator-and-creation-tx-hash


9
10
11
12
13
14
# File 'lib/etherscan-lite/contract.rb', line 9

def self.getcontractcreation_url( contractaddresses: )
  src = "#{BASE}?module=contract&action=getcontractcreation" +
          "&contractaddresses=#{contractaddresses.join(',')}" +
          "&apikey=#{config.key}"
  src
end

.getcontractdetails(contractaddress:) ⇒ Object

all-in-one helper for getting contract details

note: requires (collects data via) three api calls


9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/etherscan-lite/misc.rb', line 9

def self.getcontractdetails( contractaddress: )

  delay_in_s = 0.5
  puts "   sleeping #{delay_in_s} sec(s)..."
  sleep( delay_in_s )
  data = getcontractcreation( contractaddresses: [contractaddress] )
  ## pp data


  # [{"contractAddress"=>"0x16f5a35647d6f03d5d3da7b35409d65ba03af3b2",

  #   "contractCreator"=>"0xc352b534e8b987e036a93539fd6897f53488e56a",

  #   "txHash"=>"0xc82aa34310c310463eb9fe7835471f7317ac4b5008034a78c93b2a8a237be228"}]


  ## reuse hash from repsone - why? why not?

  details = data[0]

  puts "   sleeping #{delay_in_s} sec(s)..."
  sleep( delay_in_s )
  data2 = gettransactionbyhash( txhash: details['txHash'] )
  ## puts

  ## pp data2

  #  {"blockHash"=>"0x07f9b4846ee2702da8d18b9eeead15912d977acc8886ab9bf5d760914cb37670",

  #  "blockNumber"=>"0x3f17d2",

  # "from"=>"0xa97f8ffc8f8e354475880448334e4e99a0e7212f",

  #  "gas"=>"0x2c51d3",

  # "gasPrice"=>"0x53c53dc33",

  # "hash"=>"0x79d48c41b99f0ac8f735dbf4d048165542576862df2b05a80be9a4dbe233a623",

  details['blockNumber']  = data2['blockNumber']

  puts "   sleeping #{delay_in_s} sec(s)..."
  sleep( delay_in_s )
  data3 = getblockbynumber( blocknumber: data2['blockNumber'] )
  ## puts

  ## pp data3


  details['timestamp'] = data3['timestamp']
  details
end

.gettransactionbyhash(**kwargs) ⇒ Object



19
20
21
22
# File 'lib/etherscan-lite/proxy.rb', line 19

def self.gettransactionbyhash( **kwargs )
  ## note: requires proxy_call!!! - different return / response format in json!!

  proxy_call( gettransactionbyhash_url( **kwargs ) )
end

.gettransactionbyhash_url(txhash:) ⇒ Object

eth_getTransactionByHash

Returns the information about a transaction requested

by transaction hash.

see https://docs.etherscan.io/api-endpoints/geth-parity-proxy#eth_gettransactionbyhash


12
13
14
15
16
17
# File 'lib/etherscan-lite/proxy.rb', line 12

def self.gettransactionbyhash_url( txhash: )
  src = "#{BASE}?module=proxy&action=eth_getTransactionByHash" +
        "&txhash=#{txhash}" +
        "&apikey=#{config.key}"
  src
end

.proxy_call(src) ⇒ Object

get response as (parsed) json (hash table)



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/etherscan-lite/base.rb', line 58

def self.proxy_call( src )   ## get response as (parsed) json (hash table)


  headers = {
    # 'User-Agent' => "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36",

    'User-Agent' => "ruby v#{RUBY_VERSION}",
   }

  response = Webclient.get( src, headers: headers )

  if response.status.ok?
    puts "#{response.status.code} #{response.status.message} -  content_type: #{response.content_type}, content_length: #{response.content_length}"

  ### check for {"jsonrpc"=>"2.0",

  ##  "id"=>1,

  ##   "result"=> ... }

    data = response.json
    ## pp data


    if data['result']
      data['result']
    elsif data['error']
      puts "!! ETHERSCAN API (PROXY JSON-RPC) ERROR:"
      puts "#{data['error']}"
      exit 1
    else
      puts "!! ETHERSCAN API (PROXY JSON-RPC) ERROR:"
      puts "  No response on request"
      exit 1
    end
  else
    puts "!! HTTP ERROR:"
    puts "#{response.status.code} #{response.status.message}"
    exit 1
  end
end

.tokennfttx(**kwargs) ⇒ Object



97
98
99
# File 'lib/etherscan-lite/account.rb', line 97

def self.tokennfttx( **kwargs )
  call( tokennfttx_url( **kwargs ) )
end

.tokennfttx_url(address: nil, contractaddress: nil, startblock: 0, endblock: 99999999, page: 1, offset: 10, sort: 'desc') ⇒ Object

Get a list of ‘ERC721 - Token Transfer Events’ by Address

Returns the list of ERC-721 ( NFT ) tokens transferred by an address,
  with optional filtering by token contract.
Usage:
- ERC-721 transfers from an address, specify the address parameter
- ERC-721 transfers from a contract address, specify the contract address parameter
- ERC-721 transfers from an address filtered by a token contract, specify both address and contract address parameters.

see docs.etherscan.io/api-endpoints/accounts#get-a-list-of-erc721-token-transfer-events-by-address



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/etherscan-lite/account.rb', line 75

def self.tokennfttx_url( address: nil,
                         contractaddress: nil,
                         startblock: 0,
                         endblock: 99999999,
                         page: 1,
                         offset: 10,
                         sort: 'desc' )

  src = "#{BASE}?module=account&action=tokennfttx" +
        "&startblock=#{startblock}" +
        "&endblock=#{endblock}" +
        "&page=#{page}" +
        "&offset=#{offset}" +
        "&sort=#{sort}" +
        "&apikey=#{config.key}"

  ## optional

  src +=  "&address=#{address}"                   if address
  src +=  "&contractaddress=#{contractaddress}"   if contractaddress
  src
end

.tokentx(**kwargs) ⇒ Object



61
62
63
# File 'lib/etherscan-lite/account.rb', line 61

def self.tokentx( **kwargs )
  call( tokentx_url( **kwargs ) )
end

.tokentx_url(address: nil, contractaddress: nil, startblock: 0, endblock: 99999999, page: 1, offset: 10, sort: 'desc') ⇒ Object

Get a list of ‘ERC20 - Token Transfer Events’ by Address

Returns the list of ERC-20 tokens transferred by an address,
    with optional filtering by token contract.
Usage:
- ERC-20 transfers from an address, specify the address parameter
- ERC-20 transfers from a contract address, specify the contract address parameter
- ERC-20 transfers from an address filtered by a token contract, specify both address and contract address parameters.

see docs.etherscan.io/api-endpoints/accounts#get-a-list-of-erc20-token-transfer-events-by-address



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/etherscan-lite/account.rb', line 39

def self.tokentx_url( address: nil,
                      contractaddress: nil,
                     startblock: 0,
                     endblock: 99999999,
                     page: 1,
                     offset: 10,
                     sort: 'desc' )

  src = "#{BASE}?module=account&action=tokentx" +
         "&startblock=#{startblock}" +
         "&endblock=#{endblock}" +
         "&page=#{page}" +
         "&offset=#{offset}" +
         "&sort=#{sort}" +
         "&apikey=#{config.key}"

  ## optional

  src +=  "&address=#{address}"                   if address
  src +=  "&contractaddress=#{contractaddress}"   if contractaddress
  src
end

.txlist(**kwargs) ⇒ Object



25
26
27
# File 'lib/etherscan-lite/account.rb', line 25

def self.txlist( **kwargs )
   call( txlist_url( **kwargs ) )
end

.txlist_url(address:, startblock: 0, endblock: 99999999, page: 1, offset: 10, sort: 'desc') ⇒ Object

Get a list of ‘Normal’ Transactions By Address

Returns the list of transactions performed by an address,
 with optional pagination.

see docs.etherscan.io/api-endpoints/accounts#get-a-list-of-normal-transactions-by-address



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/etherscan-lite/account.rb', line 7

def self.txlist_url( address:,
                     startblock: 0,
                     endblock: 99999999,
                     page: 1,
                     offset: 10,
                     sort: 'desc' )

  src = "#{BASE}?module=account&action=txlist" +
         "&address=#{address}" +
         "&startblock=#{startblock}" +
         "&endblock=#{endblock}" +
         "&page=#{page}" +
         "&offset=#{offset}" +
         "&sort=#{sort}" +
         "&apikey=#{config.key}"
  src
end