lib/etht/etherscan.rb in etht-0.1.4 vs lib/etht/etherscan.rb in etht-0.1.5

- old
+ new

@@ -1,177 +1,129 @@ # frozen_string_literal: true -require 'faraday' -require 'json' +require('faraday') +require('json') # @author Hernani Rodrigues Vaz module Etht - # class Config - class Config - attr_accessor :key, :secret, :url, :raise_exceptions - attr_writer :logger + # classe para tratar pedidos etherscan com chave API + class Etherscan + attr_reader :key, :url - def logger - @logger ||= Logger.new(STDERR) + # @param [String] :key apikey a juntar aos pedidos HTTP url: + # @param [String] :url base URL to use as a prefix for all requests + # @return [Etherscan] API etherscan base + def initialize(key: ENV['ETHERSCAN_API_KEY'], url: 'https://api.etherscan.io/') + @key = key + @url = url end - end - # class Api - class Api - attr_reader :connection - - def initialize(params = {}) - @connection = Etht::Client.new(params) + # @return [<Symbol>] adapter for the connection - default :net_http + def adapter + @adapter ||= Faraday.default_adapter end - def get(params) - response = connection.get(params) - response['result'] + # manage the default properties and the middleware stack for fulfilling an HTTP request + # + # @return [<Faraday::Connection>] connection object with an URL & adapter + def conn + @conn ||= + Faraday.new(url: url) do |c| + c.request(:url_encoded) + c.adapter(adapter) + end end - end - # class Client - class Client - URL = 'https://api.etherscan.io/' - HEADERS = { 'Content-Type' => 'application/json', 'Accept' => 'application/json' }.freeze + # @return [<Hash>] resultado json do GET HTTP request + def get(**ars) + r = + conn.get('api') do |o| + o.headers = { content_type: 'application/json', accept: 'application/json', user_agent: 'etherscan;ruby' } + o.params = ars.merge({ apikey: key }) + end + raise(Etht::Erro, r) if r.status != 200 - attr_reader :key, :url, :user_agent, :headers, :raise_exceptions - attr_writer :adapter, :conn - - def initialize(params = {}) - @key = params.fetch(:key, Etht.config.key) - @url = params.fetch(:url, Etht.config.url || URL) - @adapter = params.fetch(:adapter, adapter) - @conn = params.fetch(:conn, conn) - @user_agent = params.fetch(:user_agent, "etherscan/#{Etht::VERSION};ruby") - @headers = HEADERS.merge('User-Agent' => @user_agent) - @raise_exceptions = params.fetch(:raise_exceptions, Etht.config.raise_exceptions || true) - yield self if block_given? + JSON(r.body)['result'] end - def get(params = {}) - endpoint = 'api' - merged_params = params.merge({ apikey: key }) - response = conn.get(endpoint) do |req| - req.headers = headers - req.params = merged_params - end - raise Etht::Exception, response if raise_exceptions? && response.status != 200 + # get ether balance for a single address + # + # @param [String] add address for balance + # @return [<String>] devolve saldo + def address_balance(add) + raise(Etht::Erro, 'address must be defined') if add.nil? - JSON(response.body) + get(module: 'account', action: 'balance', address: add, tag: 'latest') end - def conn - @conn ||= Faraday.new(url: @url) do |conn| - conn.request :url_encoded - conn.adapter adapter - end - end + # get ether balance for multiple addresses + # + # @param [String] ads lista de addresses (max 20) + # @return [Array<Hash>] devolve lista com contas & saldo + def multi_address_balance(ads) + raise(Etht::Erro, 'up to 20 accounts in a single batch') if ads.size > 20 - def adapter - @adapter ||= Faraday.default_adapter + get(module: 'account', action: 'balancemulti', address: ads.join(','), tag: 'latest') end - def raise_exceptions? - @raise_exceptions - end - end + # get ERC20-token account balance + # + # @param add (see address_balance) + # @param [String] cdd token contract address + # @return (see address_balance) + def token_balance(add, cdd) + raise(Etht::Erro, 'contract or address must be defined') if (cdd || add).nil? - # class Accounts < Etht::Api - class Accounts < Api - def address_balance(address) - params = { - module: 'account', action: 'balance', - address: address, tag: 'latest' - } - get(params) + get(module: 'account', action: 'tokenbalance', address: add, contractaddress: cdd) end - def multi_address_balance(addresses) - raise Etht::Exception, 'up to 20 accounts in a single batch' if addresses.size > 20 + # get a list of normal transactions by address + # + # @param [String] add address for transactions + # @param [Hash] ars opcoes trabalho + # @option ars [String] :start_block starting blockNo to retrieve results + # @option ars [String] :end_block ending blockNo to retrieve results + # @option ars [String] :sort asc -> ascending order, desc -> descending order + # @option ars [String] :page to get paginated results + # @option ars [String] :offset max records to return + # @return [Array<Hash>] devolve ate max 10000 das ultimas transacoes + def normal_tx(add, **ars) + raise(Etht::Erro, 'address must be defined') if add.nil? - params = { - module: 'account', action: 'balancemulti', - address: addresses.join(','), tag: 'latest' - } - get(params) + transcations('txlist', add, nil, **ars) end - # Get a list of 'Normal' Transactions By Address - # if page is not defined Returns up to 10000 last transactions - # Available args: start_block, end_block, sort, page, offset - # @param sort 'asc' -> ascending order, 'des' -> descending order - # @param start_block starting blockNo to retrieve results - # @param end_block ending blockNo to retrieve results - # @param page Paginated result <page number> - # @param offset max records to return - def normal_transactions(address, args = {}) - action = 'txlist' - transcations(action, address, nil, args) - end + # get a list of ERC20 - token transfer events + # + # @param add (see normal_tx) + # @param [String] cdd token address (nil to get a list of all ERC20 transactions) + # @param ars (see normal_tx) + # @option ars (see normal_tx) + # @return (see normal_tx) + def token_tx(add, cdd = nil, **ars) + raise(Etht::Erro, 'contract or address must be defined') if (cdd || add).nil? - # Get a list of 'Internal' Transactions By Address - # Available args: start_block, end_block, sort, page, offset - def internal_transactions(address, args = {}) - action = 'txlistinternal' - transcations(action, address, nil, args) + transcations('tokentx', add, cdd, **ars) end - # Get a list of "ERC20 - Token Transfer Events" - # @param contract_address Token address (set nil to get a list of all ERC20 transactions) - # @param address Address for ERC20 transactions (optional) - # Available args: start_block, end_block, sort, page, offset - def token_transactions(contract_address, address = nil, args = {}) - raise Etht::Exception, 'contract or address must be defined' if (contract_address || address).nil? - - action = 'tokentx' - transcations(action, address, contract_address, args) - end - private - def transcations(action, address, contract_address, args) - params = { - module: 'account', action: action, - address: address, contractaddress: contract_address, - startblock: args[:start_block], endblock: args[:end_block], - page: args[:page], offset: args[:offset], sort: args[:sort] - }.reject { |_, v| v.nil? } - get(params) + # get a list of transactions + # + # @param [String] act accao a executar + # @param add (see normal_tx) + # @param cdd (see token_tx) + # @param ars (see normal_tx) + # @option ars (see normal_tx) + # @return (see normal_tx) + def transcations(act, add, cdd, **ars) + get(**{ module: 'account', action: act, address: add }.merge({ + contractaddress: cdd, + startblock: ars[:start_block], + endblock: ars[:end_block], + page: ars[:page], + offset: ars[:offset], + sort: ars[:sort] + }.reject { |_, v| v.nil? })) end - end - - # class Tokens < Etht::Api - class Tokens < Api - def total_supply(contract_address) - params = { - module: 'stats', action: 'tokensupply', - contractaddress: contract_address - } - get(params) - end - - def balance(address, contract_address) - params = { - module: 'account', action: 'tokenbalance', - address: address, contractaddress: contract_address - } - get(params) - end - end - - def self.configure - yield config - end - - def self.config - @config ||= Config.new - end - - def self.logger - config.logger - end - - configure do |config| - config.key = ENV['ETHERSCAN_API_KEY'] end end