class CoinSync::Importers::BitBayAPI

Constants

BASE_URL
MAX_TIME_DIFFERENCE
OP_FEE
OP_PURCHASE
OP_SALE
POLISH_TIMEZONE
TRANSACTION_TYPES

Public Class Methods

new(config, params = {}) click to toggle source
Calls superclass method CoinSync::Importers::Base::new
# File lib/coinsync/importers/bitbay_api.rb, line 73
def initialize(config, params = {})
  super

  # required permissions:
  # * for balance checks:
  #   - "Crypto deposit" (shown as "Get and create cryptocurrency addresses" + "Funds deposit")
  #   - "Updating a wallets list" (shown as "Pobieranie rachunków")
  # * for transaction history:
  #   - "History" (shown as "Fetch history of transactions")

  @public_key = params['api_public_key']
  @secret_key = params['api_private_key']
end

Public Instance Methods

can_import?(type) click to toggle source
# File lib/coinsync/importers/bitbay_api.rb, line 87
def can_import?(type)
  @public_key && @secret_key && [:balances, :transactions].include?(type)
end
import_balances() click to toggle source
# File lib/coinsync/importers/bitbay_api.rb, line 126
def import_balances
  info = fetch_info

  info['balances'].select { |k, v|
    v['available'].to_f > 0 || v['locked'].to_f > 0
  }.map { |k, v|
    Balance.new(
      CryptoCurrency.new(k),
      available: BigDecimal.new(v['available']),
      locked: BigDecimal.new(v['locked'])
    )
  }
end
import_transactions(filename) click to toggle source
# File lib/coinsync/importers/bitbay_api.rb, line 91
def import_transactions(filename)
  info = fetch_info

  currencies = info['balances'].keys
  transactions = []

  currencies.each do |currency|
    sleep 1  # rate limiting

    # TODO: does this limit really work? (no way to test it really and docs don't mention a max value)
    response = make_request('history', currency: currency, limit: 10000)

    case response
    when Net::HTTPSuccess
      json = JSON.parse(response.body)

      if !json.is_a?(Array)
        raise "BitBay API importer: Invalid response: #{response.body}"
      end

      transactions.concat(json)
    when Net::HTTPBadRequest
      raise "BitBay API importer: Bad request: #{response}"
    else
      raise "BitBay API importer: Bad response: #{response}"
    end
  end

  transactions.each_with_index { |tx, i| tx['i'] = i }
  transactions.sort_by! { |tx| [tx['time'], -tx['i']] }
  transactions.each_with_index { |tx, i| tx.delete('i') }

  File.write(filename, JSON.pretty_generate(transactions))
end
read_transaction_list(source) click to toggle source
# File lib/coinsync/importers/bitbay_api.rb, line 140
def read_transaction_list(source)
  json = JSON.parse(source.read)

  matching = []
  transactions = []

  json.each do |hash|
    entry = HistoryEntry.new(hash)

    next unless TRANSACTION_TYPES.include?(entry.type)

    if !matching.empty?
      must_match = matching.any? { |e| (e.date - entry.date).abs > MAX_TIME_DIFFERENCE }
      transaction = process_matched(matching, must_match)
      transactions << transaction if transaction
    end

    matching << entry
  end

  if !matching.empty?
    transactions << process_matched(matching, true)
  end

  transactions
end

Private Instance Methods

fetch_info() click to toggle source
# File lib/coinsync/importers/bitbay_api.rb, line 219
def fetch_info
  response = make_request('info')

  case response
  when Net::HTTPSuccess
    json = JSON.parse(response.body)

    if json['success'] != 1 || json['code'] || json['balances'].nil?
      raise "BitBay API importer: Invalid response: #{response.body}"
    end

    json
  when Net::HTTPBadRequest
    raise "BitBay API importer: Bad request: #{response}"
  else
    raise "BitBay API importer: Bad response: #{response}"
  end
end
make_request(method, params = {}) click to toggle source
# File lib/coinsync/importers/bitbay_api.rb, line 201
def make_request(method, params = {})
  (@public_key && @secret_key) or raise "Public and secret API keys must be provided"

  url = URI(BASE_URL)

  params['method'] = method
  params['moment'] = Time.now.to_i

  param_string = URI.encode_www_form(params)
  hmac = OpenSSL::HMAC.hexdigest('sha512', @secret_key, param_string)

  Request.post(url) do |request|
    request.body = param_string
    request['API-Key'] = @public_key
    request['API-Hash'] = hmac
  end
end
process_matched(matching, must_match) click to toggle source
# File lib/coinsync/importers/bitbay_api.rb, line 170
def process_matched(matching, must_match)
  if matching.length % 3 == 0
    purchases = matching.select { |tx| tx.type == OP_PURCHASE }
    sales = matching.select { |tx| tx.type == OP_SALE }
    fees = matching.select { |tx| tx.type == OP_FEE }

    if purchases.length == sales.length && purchases.length == fees.length
      bought_currency = (purchases + fees).map(&:currency).uniq
      sold_currency = sales.map(&:currency).uniq

      if bought_currency.length == 1 && sold_currency.length == 1
        matching.clear

        return Transaction.new(
          exchange: 'BitBay',
          bought_currency: bought_currency.first,
          sold_currency: sold_currency.first,
          time: (purchases + sales + fees).map(&:date).last,
          bought_amount: (purchases + fees).map(&:amount).reduce(&:+),
          sold_amount: -sales.map(&:amount).reduce(&:+)
        )
      end
    end
  end

  if must_match
    raise "BitBay API importer error: Couldn't match some history lines: " +
      matching.map { |m| "\n#{m.inspect}" }.join
  end
end