coinsync 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE.txt +21 -0
- data/README.md +255 -0
- data/bin/coinsync +78 -0
- data/doc/importers.md +201 -0
- data/lib/coinsync.rb +18 -0
- data/lib/coinsync/balance.rb +19 -0
- data/lib/coinsync/balance_task.rb +65 -0
- data/lib/coinsync/build_task.rb +43 -0
- data/lib/coinsync/builder.rb +32 -0
- data/lib/coinsync/config.rb +94 -0
- data/lib/coinsync/crypto_classifier.rb +27 -0
- data/lib/coinsync/currencies.rb +35 -0
- data/lib/coinsync/currency_converter.rb +65 -0
- data/lib/coinsync/currency_converters/all.rb +1 -0
- data/lib/coinsync/currency_converters/base.rb +46 -0
- data/lib/coinsync/currency_converters/cache.rb +34 -0
- data/lib/coinsync/currency_converters/fixer.rb +36 -0
- data/lib/coinsync/currency_converters/nbp.rb +38 -0
- data/lib/coinsync/formatter.rb +44 -0
- data/lib/coinsync/import_task.rb +37 -0
- data/lib/coinsync/importers/all.rb +1 -0
- data/lib/coinsync/importers/ark_voting.rb +121 -0
- data/lib/coinsync/importers/base.rb +35 -0
- data/lib/coinsync/importers/binance_api.rb +210 -0
- data/lib/coinsync/importers/bitbay20.rb +144 -0
- data/lib/coinsync/importers/bitbay_api.rb +224 -0
- data/lib/coinsync/importers/bitcurex.rb +71 -0
- data/lib/coinsync/importers/bittrex_api.rb +81 -0
- data/lib/coinsync/importers/bittrex_csv.rb +75 -0
- data/lib/coinsync/importers/changelly.rb +57 -0
- data/lib/coinsync/importers/circle.rb +58 -0
- data/lib/coinsync/importers/default.rb +90 -0
- data/lib/coinsync/importers/etherdelta.rb +93 -0
- data/lib/coinsync/importers/kraken_api.rb +134 -0
- data/lib/coinsync/importers/kraken_common.rb +137 -0
- data/lib/coinsync/importers/kraken_csv.rb +28 -0
- data/lib/coinsync/importers/kucoin_api.rb +172 -0
- data/lib/coinsync/importers/lisk_voting.rb +110 -0
- data/lib/coinsync/outputs/all.rb +1 -0
- data/lib/coinsync/outputs/base.rb +32 -0
- data/lib/coinsync/outputs/list.rb +123 -0
- data/lib/coinsync/outputs/raw.rb +45 -0
- data/lib/coinsync/outputs/summary.rb +48 -0
- data/lib/coinsync/request.rb +31 -0
- data/lib/coinsync/run_command_task.rb +20 -0
- data/lib/coinsync/source.rb +43 -0
- data/lib/coinsync/source_filter.rb +10 -0
- data/lib/coinsync/table_printer.rb +29 -0
- data/lib/coinsync/transaction.rb +125 -0
- data/lib/coinsync/version.rb +3 -0
- metadata +95 -0
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
require 'csv'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
require_relative 'base'
|
6
|
+
require_relative '../currencies'
|
7
|
+
require_relative '../transaction'
|
8
|
+
|
9
|
+
module CoinSync
|
10
|
+
module Importers
|
11
|
+
class BittrexCSV < Base
|
12
|
+
register_importer :bittrex_csv
|
13
|
+
|
14
|
+
class HistoryEntry
|
15
|
+
TIME_FORMAT = '%m/%d/%Y %H:%M:%S %p %z'
|
16
|
+
|
17
|
+
attr_accessor :uuid, :currency, :asset, :type, :quantity, :limit, :commission, :price,
|
18
|
+
:time_opened, :time_closed
|
19
|
+
|
20
|
+
def initialize(line)
|
21
|
+
@uuid = line[0]
|
22
|
+
@currency, @asset = line[1].split('-').map { |c| CryptoCurrency.new(c) }
|
23
|
+
@type = line[2]
|
24
|
+
@quantity = BigDecimal.new(line[3])
|
25
|
+
@limit = BigDecimal.new(line[4])
|
26
|
+
@commission = BigDecimal.new(line[5])
|
27
|
+
@price = BigDecimal.new(line[6])
|
28
|
+
@time_opened = Time.strptime(line[7] + ' +0000', TIME_FORMAT)
|
29
|
+
@time_closed = Time.strptime(line[8] + ' +0000', TIME_FORMAT)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def read_transaction_list(source)
|
34
|
+
contents = source.read.gsub("\u0000", '').gsub("\r", '')
|
35
|
+
entries = []
|
36
|
+
transactions = []
|
37
|
+
|
38
|
+
CSV.parse(contents, col_sep: ',') do |line|
|
39
|
+
next if line[0] == 'OrderUuid'
|
40
|
+
|
41
|
+
entries << HistoryEntry.new(line)
|
42
|
+
end
|
43
|
+
|
44
|
+
entries.sort_by! { |e| [e.time_closed, e.uuid] }
|
45
|
+
|
46
|
+
entries.each do |entry|
|
47
|
+
case entry.type
|
48
|
+
when 'LIMIT_BUY', 'MARKET_BUY' then
|
49
|
+
transactions << Transaction.new(
|
50
|
+
exchange: 'Bittrex',
|
51
|
+
time: entry.time_closed,
|
52
|
+
bought_amount: entry.quantity,
|
53
|
+
bought_currency: entry.asset,
|
54
|
+
sold_amount: entry.price + entry.commission,
|
55
|
+
sold_currency: entry.currency
|
56
|
+
)
|
57
|
+
when 'LIMIT_SELL', 'MARKET_SELL' then
|
58
|
+
transactions << Transaction.new(
|
59
|
+
exchange: 'Bittrex',
|
60
|
+
time: entry.time_closed,
|
61
|
+
bought_amount: entry.price - entry.commission, # TODO check this
|
62
|
+
bought_currency: entry.currency,
|
63
|
+
sold_amount: entry.quantity,
|
64
|
+
sold_currency: entry.asset
|
65
|
+
)
|
66
|
+
else
|
67
|
+
raise "Bittrex importer error: unexpected entry type '#{entry.type}'"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
transactions
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
require 'csv'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
require_relative 'base'
|
6
|
+
require_relative '../currencies'
|
7
|
+
require_relative '../transaction'
|
8
|
+
|
9
|
+
module CoinSync
|
10
|
+
module Importers
|
11
|
+
class Changelly < Base
|
12
|
+
register_importer :changelly
|
13
|
+
|
14
|
+
class HistoryEntry
|
15
|
+
attr_accessor :status, :date, :exchanged_currency, :exchanged_amount, :received_currency, :received_amount
|
16
|
+
|
17
|
+
def initialize(line)
|
18
|
+
@status = line[0]
|
19
|
+
@date = Time.parse(line[1] + ' +0000')
|
20
|
+
|
21
|
+
amount, name = line[2].gsub(',', '').split(/\s+/)
|
22
|
+
@exchanged_currency = CryptoCurrency.new(name)
|
23
|
+
@exchanged_amount = BigDecimal.new(amount)
|
24
|
+
|
25
|
+
amount, name = line[6].gsub(',', '').split(/\s+/)
|
26
|
+
@received_currency = CryptoCurrency.new(name)
|
27
|
+
@received_amount = BigDecimal.new(amount)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def read_transaction_list(source)
|
32
|
+
csv = CSV.new(source, col_sep: ',')
|
33
|
+
|
34
|
+
transactions = []
|
35
|
+
|
36
|
+
csv.each do |line|
|
37
|
+
next if line[0] == 'Status'
|
38
|
+
|
39
|
+
entry = HistoryEntry.new(line)
|
40
|
+
|
41
|
+
next if entry.status != 'finished'
|
42
|
+
|
43
|
+
transactions << Transaction.new(
|
44
|
+
exchange: 'Changelly',
|
45
|
+
time: entry.date,
|
46
|
+
bought_amount: entry.received_amount,
|
47
|
+
bought_currency: entry.received_currency,
|
48
|
+
sold_amount: entry.exchanged_amount,
|
49
|
+
sold_currency: entry.exchanged_currency
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
transactions.reverse
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
require 'csv'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
require_relative 'base'
|
6
|
+
require_relative '../currencies'
|
7
|
+
require_relative '../transaction'
|
8
|
+
|
9
|
+
module CoinSync
|
10
|
+
module Importers
|
11
|
+
class Circle < Base
|
12
|
+
register_importer :circle
|
13
|
+
|
14
|
+
class HistoryEntry
|
15
|
+
attr_accessor :date, :id, :type, :from_account, :to_account, :from_amount, :from_currency,
|
16
|
+
:to_amount, :to_currency, :status
|
17
|
+
|
18
|
+
def initialize(line)
|
19
|
+
@date = Time.strptime(line[0], '%a %b %d %Y %H:%M:%S GMT+0000 (%Z)')
|
20
|
+
@id = line[1]
|
21
|
+
@type = line[2]
|
22
|
+
@from_account = line[3]
|
23
|
+
@to_account = line[4]
|
24
|
+
@from_amount = BigDecimal.new(line[5].gsub(/[^\d\.]+/, ''))
|
25
|
+
@from_currency = FiatCurrency.new(line[6])
|
26
|
+
@to_amount = BigDecimal.new(line[7].gsub(/[^\d\.]+/, ''))
|
27
|
+
@to_currency = CryptoCurrency.new(line[8])
|
28
|
+
@status = line[9]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def read_transaction_list(source)
|
33
|
+
csv = CSV.new(source, col_sep: ',')
|
34
|
+
|
35
|
+
transactions = []
|
36
|
+
|
37
|
+
csv.each do |line|
|
38
|
+
next if line[0] == 'Date'
|
39
|
+
|
40
|
+
entry = HistoryEntry.new(line)
|
41
|
+
|
42
|
+
next if entry.type != 'deposit'
|
43
|
+
|
44
|
+
transactions << Transaction.new(
|
45
|
+
exchange: 'Circle',
|
46
|
+
bought_currency: entry.to_currency,
|
47
|
+
sold_currency: entry.from_currency,
|
48
|
+
time: entry.date,
|
49
|
+
bought_amount: entry.to_amount,
|
50
|
+
sold_amount: entry.from_amount
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
transactions
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
require 'csv'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
require_relative 'base'
|
6
|
+
require_relative '../currencies'
|
7
|
+
require_relative '../formatter'
|
8
|
+
require_relative '../transaction'
|
9
|
+
|
10
|
+
module CoinSync
|
11
|
+
module Importers
|
12
|
+
class Default < Base
|
13
|
+
register_importer :default
|
14
|
+
|
15
|
+
class HistoryEntry
|
16
|
+
attr_accessor :lp, :exchange, :type, :date, :amount, :asset, :total, :currency
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(config, params = {})
|
20
|
+
super
|
21
|
+
@decimal_separator = config.custom_decimal_separator
|
22
|
+
@formatter = Formatter.new(config)
|
23
|
+
end
|
24
|
+
|
25
|
+
def read_transaction_list(source)
|
26
|
+
csv = CSV.new(source, col_sep: @config.column_separator)
|
27
|
+
|
28
|
+
transactions = []
|
29
|
+
|
30
|
+
csv.each do |line|
|
31
|
+
next if line.empty?
|
32
|
+
next if line.all? { |f| f.to_s.strip == '' }
|
33
|
+
next if line[0] == 'Lp'
|
34
|
+
|
35
|
+
entry = parse_line(line)
|
36
|
+
|
37
|
+
if entry.type.downcase == Transaction::TYPE_PURCHASE.to_s
|
38
|
+
transactions << Transaction.new(
|
39
|
+
exchange: entry.exchange,
|
40
|
+
bought_currency: entry.asset,
|
41
|
+
sold_currency: entry.currency,
|
42
|
+
time: entry.date,
|
43
|
+
bought_amount: entry.amount,
|
44
|
+
sold_amount: entry.total
|
45
|
+
)
|
46
|
+
elsif entry.type.downcase == Transaction::TYPE_SALE.to_s
|
47
|
+
transactions << Transaction.new(
|
48
|
+
exchange: entry.exchange,
|
49
|
+
bought_currency: entry.currency,
|
50
|
+
sold_currency: entry.asset,
|
51
|
+
time: entry.date,
|
52
|
+
bought_amount: entry.total,
|
53
|
+
sold_amount: entry.amount
|
54
|
+
)
|
55
|
+
else
|
56
|
+
raise "Default importer error: unexpected entry type '#{entry.type}'"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
transactions
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def parse_line(line)
|
66
|
+
entry = HistoryEntry.new
|
67
|
+
|
68
|
+
entry.lp = line[0].to_i
|
69
|
+
entry.exchange = line[1]
|
70
|
+
entry.type = line[2]
|
71
|
+
entry.date = Time.parse(line[3])
|
72
|
+
entry.amount = @formatter.parse_decimal(line[4])
|
73
|
+
entry.asset = CryptoCurrency.new(line[5])
|
74
|
+
entry.total = @formatter.parse_decimal(line[6])
|
75
|
+
|
76
|
+
entry.currency = if line[7].to_s.start_with?('$')
|
77
|
+
CryptoCurrency.new(line[7][1..-1])
|
78
|
+
else
|
79
|
+
FiatCurrency.new(line[7])
|
80
|
+
end
|
81
|
+
|
82
|
+
if entry.currency.code.nil? && entry.total > 0
|
83
|
+
raise "Default importer error: Currency must be specified if total value is non-zero"
|
84
|
+
end
|
85
|
+
|
86
|
+
entry
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
require 'csv'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
require_relative 'base'
|
6
|
+
require_relative '../currencies'
|
7
|
+
require_relative '../transaction'
|
8
|
+
|
9
|
+
module CoinSync
|
10
|
+
module Importers
|
11
|
+
# Look up your transactions using DeltaBalances at https://deltabalances.github.io/history.html,
|
12
|
+
# specifying the time range you need, and then download the "Default" CSV in the top-right section
|
13
|
+
|
14
|
+
class EtherDelta < Base
|
15
|
+
register_importer :etherdelta
|
16
|
+
|
17
|
+
ETH = CryptoCurrency.new('ETH')
|
18
|
+
|
19
|
+
class HistoryEntry
|
20
|
+
attr_accessor :type, :trade, :token, :amount, :price, :total, :date, :fee, :fee_token
|
21
|
+
|
22
|
+
def initialize(line)
|
23
|
+
@type = line[0]
|
24
|
+
|
25
|
+
if !['Maker', 'Taker'].include?(@type)
|
26
|
+
raise "EtherDelta importer: incorrect csv format - unexpected '#{@type}' in the first column"
|
27
|
+
end
|
28
|
+
|
29
|
+
@trade = line[1]
|
30
|
+
|
31
|
+
if !['Buy', 'Sell'].include?(@trade)
|
32
|
+
raise "EtherDelta importer: incorrect csv format - unexpected '#{@trade}' in the second column"
|
33
|
+
end
|
34
|
+
|
35
|
+
@token = CryptoCurrency.new(line[2])
|
36
|
+
|
37
|
+
@amount = BigDecimal.new(line[3])
|
38
|
+
@price = BigDecimal.new(line[4])
|
39
|
+
@total = BigDecimal.new(line[5])
|
40
|
+
|
41
|
+
@date = Time.parse(line[6])
|
42
|
+
|
43
|
+
@fee = BigDecimal.new(line[11])
|
44
|
+
@fee_token = CryptoCurrency.new(line[12])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def read_transaction_list(source)
|
49
|
+
csv = CSV.new(source, col_sep: ',')
|
50
|
+
|
51
|
+
transactions = []
|
52
|
+
|
53
|
+
csv.each do |line|
|
54
|
+
next if line[0] == 'Type'
|
55
|
+
|
56
|
+
entry = HistoryEntry.new(line)
|
57
|
+
|
58
|
+
next if entry.amount.round(8) == 0 || entry.total.round(8) == 0
|
59
|
+
|
60
|
+
if entry.trade == 'Buy'
|
61
|
+
if entry.fee_token != ETH
|
62
|
+
raise "EtherDelta importer: Unexpected fee currency: #{entry.fee_token.code}"
|
63
|
+
end
|
64
|
+
|
65
|
+
transactions << Transaction.new(
|
66
|
+
exchange: 'EtherDelta',
|
67
|
+
time: entry.date,
|
68
|
+
bought_amount: entry.amount,
|
69
|
+
bought_currency: entry.token,
|
70
|
+
sold_amount: entry.total + entry.fee,
|
71
|
+
sold_currency: ETH
|
72
|
+
)
|
73
|
+
else
|
74
|
+
if entry.fee_token != entry.token
|
75
|
+
raise "EtherDelta importer: Unexpected fee currency: #{entry.fee_token.code}"
|
76
|
+
end
|
77
|
+
|
78
|
+
transactions << Transaction.new(
|
79
|
+
exchange: 'EtherDelta',
|
80
|
+
time: entry.date,
|
81
|
+
bought_amount: entry.total,
|
82
|
+
bought_currency: ETH,
|
83
|
+
sold_amount: entry.amount + entry.fee,
|
84
|
+
sold_currency: entry.token
|
85
|
+
)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
transactions.sort_by(&:time)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'bigdecimal'
|
3
|
+
require 'json'
|
4
|
+
require 'net/http'
|
5
|
+
require 'openssl'
|
6
|
+
require 'uri'
|
7
|
+
|
8
|
+
require_relative 'base'
|
9
|
+
require_relative 'kraken_common'
|
10
|
+
require_relative '../balance'
|
11
|
+
require_relative '../currencies'
|
12
|
+
require_relative '../request'
|
13
|
+
|
14
|
+
module CoinSync
|
15
|
+
module Importers
|
16
|
+
class KrakenAPI < Base
|
17
|
+
register_importer :kraken_api
|
18
|
+
|
19
|
+
include Kraken::Common
|
20
|
+
|
21
|
+
BASE_URL = "https://api.kraken.com"
|
22
|
+
API_RENEWAL_INTERVAL = 3.0
|
23
|
+
|
24
|
+
def initialize(config, params = {})
|
25
|
+
super
|
26
|
+
@api_key = params['api_key']
|
27
|
+
@secret_api_key = params['private_key']
|
28
|
+
@decoded_secret = Base64.decode64(@secret_api_key) if @secret_api_key
|
29
|
+
end
|
30
|
+
|
31
|
+
def can_import?(type)
|
32
|
+
@api_key && @secret_api_key && [:balances, :transactions].include?(type)
|
33
|
+
end
|
34
|
+
|
35
|
+
def import_transactions(filename)
|
36
|
+
offset = 0
|
37
|
+
entries = []
|
38
|
+
slowdown = false
|
39
|
+
|
40
|
+
loop do
|
41
|
+
response = make_request('/0/private/Ledgers', ofs: offset)
|
42
|
+
print slowdown ? '-' : '.'
|
43
|
+
sleep(2 * API_RENEWAL_INTERVAL) if slowdown # rate limiting
|
44
|
+
|
45
|
+
case response
|
46
|
+
when Net::HTTPSuccess
|
47
|
+
json = JSON.parse(response.body)
|
48
|
+
|
49
|
+
if json['result'].nil? || json['error'].length > 0
|
50
|
+
if json['error'].first == 'EAPI:Rate limit exceeded'
|
51
|
+
slowdown = true
|
52
|
+
print '!'
|
53
|
+
sleep(4 * API_RENEWAL_INTERVAL)
|
54
|
+
next
|
55
|
+
else
|
56
|
+
raise "Kraken importer: Invalid response: #{response.body}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
data = json['result']
|
61
|
+
list = data && data['ledger']
|
62
|
+
|
63
|
+
if !list
|
64
|
+
raise "Kraken importer: No data returned: #{response.body}"
|
65
|
+
end
|
66
|
+
|
67
|
+
break if list.empty?
|
68
|
+
|
69
|
+
entries.concat(list.values)
|
70
|
+
offset += list.length
|
71
|
+
when Net::HTTPBadRequest
|
72
|
+
raise "Kraken importer: Bad request: #{response.body}"
|
73
|
+
else
|
74
|
+
raise "Kraken importer: Bad response: #{response.body}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
File.write(filename, JSON.pretty_generate(entries) + "\n")
|
79
|
+
end
|
80
|
+
|
81
|
+
def import_balances
|
82
|
+
response = make_request('/0/private/Balance')
|
83
|
+
|
84
|
+
case response
|
85
|
+
when Net::HTTPSuccess
|
86
|
+
json = JSON.parse(response.body)
|
87
|
+
|
88
|
+
if !json['error'].empty? || !json['result']
|
89
|
+
raise "Kraken importer: Invalid response: #{response.body}"
|
90
|
+
end
|
91
|
+
|
92
|
+
return json['result'].map { |k, v|
|
93
|
+
[Kraken::LedgerEntry.parse_currency(k), BigDecimal.new(v)]
|
94
|
+
}.select { |currency, amount|
|
95
|
+
amount > 0 && currency.crypto?
|
96
|
+
}.map { |currency, amount|
|
97
|
+
Balance.new(currency, available: amount)
|
98
|
+
}
|
99
|
+
when Net::HTTPBadRequest
|
100
|
+
raise "Kraken importer: Bad request: #{response.body}"
|
101
|
+
else
|
102
|
+
raise "Kraken importer: Bad response: #{response.body}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def read_transaction_list(source)
|
107
|
+
json = JSON.parse(source.read)
|
108
|
+
|
109
|
+
build_transaction_list(json.map { |hash| Kraken::LedgerEntry.from_json(hash) })
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def make_request(path, params = {})
|
115
|
+
(@api_key && @secret_api_key) or raise "Public and secret API keys must be provided"
|
116
|
+
|
117
|
+
nonce = (Time.now.to_f * 1000).to_i
|
118
|
+
|
119
|
+
url = URI(BASE_URL + path)
|
120
|
+
params['nonce'] = nonce
|
121
|
+
|
122
|
+
post_data = URI.encode_www_form(params)
|
123
|
+
string_to_hash = path + OpenSSL::Digest.new('sha256', nonce.to_s + post_data).digest
|
124
|
+
hmac = Base64.strict_encode64(OpenSSL::HMAC.digest('sha512', @decoded_secret, string_to_hash))
|
125
|
+
|
126
|
+
Request.post(url) do |request|
|
127
|
+
request.body = post_data
|
128
|
+
request['API-Key'] = @api_key
|
129
|
+
request['API-Sign'] = hmac
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|