module CiBlockIo

Constants

VERSION

Public Class Methods

method_missing(m, *args, &block) click to toggle source
# File lib/ci_block_io.rb, line 49
def self.method_missing(m, *args, &block)      

  method_name = m.to_s

  if ['withdraw', 'withdraw_from_address', 'withdraw_from_addresses', 'withdraw_from_user', 'withdraw_from_users', 'withdraw_from_label', 'withdraw_from_labels'].include?(m.to_s) then
    # need to withdraw from an address
    self.withdraw(args.first, m.to_s)
  elsif ['sweep_from_address'].include?(m.to_s) then
    # need to sweep from an address
    self.sweep(args.first, m.to_s)
  else
    params = get_params(args.first)
    self.api_call([method_name, params])
  end

end
mock(method_name, response) click to toggle source
# File lib/ci_block_io.rb, line 28
def self.mock(method_name, response)
  @mock_response[method_name.to_s] = response
end
set_options(args = {}) click to toggle source
# File lib/ci_block_io.rb, line 32
def self.set_options(args = {})
  # initialize BlockIo
  @api_key = args[:api_key]
  @pin = args[:pin]

  @encryptionKey = Helper.pinToAesKey(@pin) if !@pin.nil?

  hostname = args[:hostname] || "block.io"
  @base_url = "https://" << hostname << "/api/VERSION/API_CALL/?api_key="

  @client = HTTPClient.new
  @client.tcp_keepalive = true
  @client.ssl_config.ssl_version = :auto

  @version = args[:version] || 2 # default version is 2
end
sweep(args = {}, method_name = 'sweep_from_address') click to toggle source
# File lib/ci_block_io.rb, line 105
def self.sweep(args = {}, method_name = 'sweep_from_address')
  # sweep coins from a given address + key

  raise Exception.new("No private_key provided.") unless args.has_key?(:private_key)

  key = Key.from_wif(args[:private_key])

  args[:public_key] = key.public_key # so Block.io can match things up
  args.delete(:private_key) # the key must never leave this machine

  params = get_params(args)

  response = self.api_call([method_name, params])

  if response['data'].has_key?('reference_id') then
    # Block.io's asking us to provide some client-side signatures, let's get to it

    # let's sign all the inputs we can
    inputs = response['data']['inputs']
    Helper.signData(inputs, [key])

    # the response object is now signed, let's stringify it and finalize this withdrawal
    response = self.api_call(['sign_and_finalize_sweep',{:signature_data => Oj.dump(response['data'])}])

    # if we provided all the required signatures, this transaction went through
    # otherwise Block.io responded with data asking for more signatures
    # the latter will be the case for dTrust addresses
  end

  return response

end
withdraw(args = {}, method_name = 'withdraw') click to toggle source
# File lib/ci_block_io.rb, line 66
def self.withdraw(args = {}, method_name = 'withdraw')
  # validate arguments for withdrawal of funds TODO

  raise CiBlockIoWithdrawException.new("PIN not set. Use BlockIo.set_options(:api_key=>'API KEY',:pin=>'SECRET PIN',:version=>'API VERSION')") if @pin.nil?

  params = get_params(args)

  params << "&pin=" << @pin if @version == 1 # Block.io handles the Secret PIN in the legacy API (v1)

  response = self.api_call([method_name, params])

  if response['data'].has_key?('reference_id') then
    # Block.io's asking us to provide some client-side signatures, let's get to it

    # extract the passphrase
    encrypted_passphrase = response['data']['encrypted_passphrase']['passphrase']

    # let's get our private key
    key = Helper.extractKey(encrypted_passphrase, @encryptionKey)

    raise CiBlockIoWithdrawException.new('Public key mismatch for requested signer and ourselves. Invalid Secret PIN detected.') if key.public_key != response['data']['encrypted_passphrase']['signer_public_key']

    # let's sign all the inputs we can
    inputs = response['data']['inputs']

    Helper.signData(inputs, [key])

    # the response object is now signed, let's stringify it and finalize this withdrawal
    response = self.api_call(['sign_and_finalize_withdrawal',{:signature_data => Oj.dump(response['data'])}])

    # if we provided all the required signatures, this transaction went through
    # otherwise Block.io responded with data asking for more signatures
    # the latter will be the case for dTrust addresses
  end

  return response

end

Private Class Methods

api_call(endpoint) click to toggle source
# File lib/ci_block_io.rb, line 141
def self.api_call(endpoint)
  return @mock_response[endpoint[0]] if @mock_response.keys.include?(endpoint[0])

  body = nil
  base_url = @base_url.gsub('API_CALL',endpoint[0]).gsub('VERSION', 'v'+@version.to_s)
  return nil if base_url.nil? || @api_key.nil?

  response = @client.post(base_url + @api_key, endpoint[1])

  body = Oj.load(response.body)
  if endpoint[0] == 'withdraw'
    raise CiBlockIoWithdrawException.new(body['data']['error_message']) if !body['status'].eql?('success')
  else
    raise CiBlockIoNetworkException.new(body['data']['error_message']) if !body['status'].eql?('success')
  end
  body
end
get_params(args = {}) click to toggle source
# File lib/ci_block_io.rb, line 161
def self.get_params(args = {})
  # construct the parameter string
  params = ""
  args = {} if args.nil?

  args.each do |k,v|
    params += '&' if params.length > 0
    params += "#{k.to_s}=#{v.to_s}"
  end

  return params
end