cns 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3567b16b6d9cf9dac846e37b985b35c92566980b0f6a30e9e1a0ce54a70172f
4
- data.tar.gz: 9f8b82cbb5b7da80a3272cbaba1bd705e32067c11611e9d0ecfcf239749a1fb0
3
+ metadata.gz: e3b7d92c5d0783aab6b1400ba4bd7e397e4f7391cfbf83d1d7faf5a8c52349aa
4
+ data.tar.gz: 43aa372a6d6f6d148f17c33065e8f0550647a2b0b78f213b00363c7ea2f74828
5
5
  SHA512:
6
- metadata.gz: 00c63ac5f9dab19932c42c201eb2a4d6504e0cf4e58094cf10be206f00d1af8f49a630adfd89c11cd6b24acc3de03814fbd1927fc82d9d0060cc60648b01754c
7
- data.tar.gz: 32fcc4a3703e86a6c00d936cbd10f7dc0bf39be48962867ea7786320189e74a862b3d78ed08a964f13134ab3206920ff5f901741b5b0f26c33cde41406b601fe
6
+ metadata.gz: 22fb5e905b0469a4022c278d643bcf06b11afab7a011329775ab3cffee92bccfeb9392c676c993569ddd7404e090ab8d2a469c1aabfff4c833b873053f3f7435
7
+ data.tar.gz: 0d7531ba08be4fe655a578475f4752d80330e41930b5d5d7732463838539357ae2936e6d11bcbe9bbd112508190404b523bceed6d4f1475853eb9f3b1b29c9e2
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cns (0.1.0)
4
+ cns (0.1.1)
5
5
  curb
6
6
  faraday
7
7
  google-cloud-bigquery
data/lib/cns.rb CHANGED
@@ -1,6 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require('thor')
4
+ require('cns/apide')
5
+ require('cns/apies')
6
+ require('cns/apifr')
7
+ require('cns/apigm')
8
+ require('cns/apimt')
9
+ require('cns/apius')
10
+ require('cns/bigquery1')
11
+ require('cns/bigquery2')
12
+ require('cns/bigquery3')
13
+ require('cns/bigquery4')
14
+ require('cns/bitcoinde')
15
+ require('cns/etherscan1')
16
+ require('cns/etherscan2')
17
+ require('cns/greymass1')
18
+ require('cns/greymass2')
19
+ require('cns/kraken')
20
+ require('cns/paymium')
21
+ require('cns/therock')
4
22
  require('cns/version')
5
23
 
6
24
  module Cns
@@ -18,7 +36,7 @@ module Cns
18
36
  option :h, type: :hash, default: {}, desc: 'configuracao ajuste reposicionamento temporal'
19
37
  # carrega transacoes novas no bigquery
20
38
  def work
21
- p('Bct::Bigquery.new(options).processa_tudo')
39
+ Bigquery.new(options).processa_tudo
22
40
  end
23
41
 
24
42
  desc 'show', 'mostra resumo transacoes'
@@ -26,7 +44,7 @@ module Cns
26
44
  option :t, type: :boolean, default: false, desc: 'mostra transacoes todas ou somente novas'
27
45
  # mostra resumo transacoes
28
46
  def show
29
- p('Bct::Bigquery.new(options).mostra_tudo')
47
+ Bigquery.new(options).mostra_tudo
30
48
  end
31
49
 
32
50
  default_task :show
@@ -0,0 +1,240 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('openssl')
4
+ require('base64')
5
+ require('curb')
6
+ require('json')
7
+
8
+ # @author Hernani Rodrigues Vaz
9
+ module Cns
10
+ # classe para processar dados no bitcoinde
11
+ class Apide
12
+ # @return [String] API key
13
+ attr_reader :aky
14
+ # @return [String] API secret
15
+ attr_reader :asc
16
+ # @return [String] API url base
17
+ attr_reader :urb
18
+
19
+ # @param [String] pky API key
20
+ # @param [String] psc API secret
21
+ # @param [Hash] ops parametrizacao base da API
22
+ # @return [Apide] API bitcoinde base
23
+ def initialize(
24
+ pky: ENV['BITCOINDE_API_KEY'],
25
+ psc: ENV['BITCOINDE_API_SECRET'],
26
+ ops: { www: 'https://api.bitcoin.de', ver: 4 }
27
+ )
28
+ @aky = pky
29
+ @asc = psc
30
+ @urb = "#{ops[:www]}/v#{ops[:ver]}"
31
+ end
32
+
33
+ # @example
34
+ # {
35
+ # data: {
36
+ # balances: {
37
+ # btc: { total_amount: '0.00000000000000000000', available_amount: '0', reserved_amount: '0' },
38
+ # bch: { total_amount: '0.00000000000000000000', available_amount: '0', reserved_amount: '0' },
39
+ # btg: { total_amount: '0.00000000000000000000', available_amount: '0', reserved_amount: '0' },
40
+ # eth: { total_amount: '0.00000000000000000000', available_amount: '0', reserved_amount: '0' },
41
+ # bsv: { total_amount: '0.00000000000000000000', available_amount: '0', reserved_amount: '0' },
42
+ # ltc: { total_amount: '0.00000000000000000000', available_amount: '0', reserved_amount: '0' }
43
+ # },
44
+ # encrypted_information: { uid: '0y...', bic_short: '0y...', bic_full: '0y...' }
45
+ # },
46
+ # errors: [],
47
+ # credits: 23
48
+ # }
49
+ # @return [Hash] saldos no bitcoinde
50
+ def account
51
+ api_get('account')[:data][:balances]
52
+ end
53
+
54
+ # @example
55
+ # {
56
+ # trades: [{
57
+ # trade_id: 'XUWWD3',
58
+ # trading_pair: 'btceur',
59
+ # is_external_wallet_trade: false,
60
+ # type: 'sell',
61
+ # amount_currency_to_trade: '0.1',
62
+ # price: 430,
63
+ # volume_currency_to_pay: 43,
64
+ # volume_currency_to_pay_after_fee: 42.79,
65
+ # amount_currency_to_trade_after_fee: 0.099,
66
+ # fee_currency_to_pay: 0.22,
67
+ # fee_currency_to_trade: '0.00100000',
68
+ # created_at: '2014-03-22T08:14:48+01:00',
69
+ # successfully_finished_at: '2014-03-25T14:03:22+01:00',
70
+ # state: 1,
71
+ # is_trade_marked_as_paid: true,
72
+ # trade_marked_as_paid_at: '2014-03-22T08:20:01+01:00',
73
+ # payment_method: 1,
74
+ # my_rating_for_trading_partner: 'positive',
75
+ # trading_partner_information: {
76
+ # username: 'emax2000',
77
+ # is_kyc_full: false,
78
+ # trust_level: 'bronze',
79
+ # amount_trades: 4,
80
+ # rating: 100,
81
+ # bank_name: 'CASSA DI RISPARMIO DI CIVITAVECCHIA SPA',
82
+ # bic: 'CRFIIT2CXXX',
83
+ # seat_of_bank: 'IT'
84
+ # }
85
+ # }, {}],
86
+ # page: { current: 1, last: 2 },
87
+ # errors: [],
88
+ # credits: 22
89
+ # }
90
+ # @param [Integer] pag pagina dos dados a obter
91
+ # @param [Array] ary lista acumuladora dos dados a obter
92
+ # @return [Array<Hash>] lista trades no bitcoinde
93
+ def trades(pag = 0, ary = [])
94
+ r = api_get('trades', state: 1, page: pag + 1)
95
+ ary += r[:trades]
96
+ r[:page][:current] < r[:page][:last] ? trades(pag + 1, ary) : ary
97
+ rescue StandardError
98
+ ary
99
+ end
100
+
101
+ # @example
102
+ # {
103
+ # deposits: [{}, {}],
104
+ # page: { current: 1, last: 1 },
105
+ # errors: [],
106
+ # credits: 23
107
+ # }
108
+ # @param (see trades)
109
+ # @return [Array<Hash>] lista depositos no bitcoinde
110
+ def deposits(pag = 0, ary = [])
111
+ r = api_get('btc/deposits', state: 2, page: pag + 1)
112
+ ary += r[:deposits].map { |h| deposit_hash(h) }
113
+ r[:page][:current] < r[:page][:last] ? deposits(pag + 1, ary) : ary
114
+ rescue StandardError
115
+ ary
116
+ end
117
+
118
+ # @example
119
+ # {
120
+ # withdrawals: [{}, {}],
121
+ # page: { current: 1, last: 2 },
122
+ # errors: [],
123
+ # credits: 23
124
+ # }
125
+ # @param (see trades)
126
+ # @return [Array<Hash>] lista withdrawals no bitcoinde
127
+ def withdrawals(pag = 0, ary = [])
128
+ r = api_get('btc/withdrawals', state: 1, page: pag + 1)
129
+ ary += r[:withdrawals].map { |h| withdrawal_hash(h) }
130
+ r[:page][:current] < r[:page][:last] ? withdrawals(pag + 1, ary) : ary
131
+ rescue StandardError
132
+ ary
133
+ end
134
+
135
+ # @example
136
+ # {
137
+ # withdrawal_id: '136605',
138
+ # address: '1K9YMDDrmMV25EoYNqi7KUEK57Kn3TCNUJ',
139
+ # amount: '0.120087',
140
+ # network_fee: '0',
141
+ # comment: '',
142
+ # created_at: '2014-02-05T13:01:09+01:00',
143
+ # txid: '6264fe528116fcb87c812a306ca8409eecfec8fa941546c86f98984b882c8042',
144
+ # transferred_at: '2014-02-05T13:05:17+01:00',
145
+ # state: 1
146
+ # }
147
+ # @param [Hash] hwi dados duma withdrawal
148
+ # @return [Hash] withdrawal unifirmizada
149
+ def withdrawal_hash(hwi)
150
+ {
151
+ id: hwi[:address],
152
+ tp: 'out',
153
+ qtxt: 'btc',
154
+ fee: hwi[:network_fee],
155
+ time: Time.parse(hwi[:transferred_at]),
156
+ qt: hwi[:amount],
157
+ lgid: Integer(hwi[:withdrawal_id])
158
+ }
159
+ end
160
+
161
+ # @example
162
+ # {
163
+ # deposit_id: '177245',
164
+ # txid: '84f9e85bc5709cd471e3d58a7d0f42d2c4a7bbd888cabf844e200efbf0a7fda2',
165
+ # address: '1KK6HhG3quojFS4CY1mPcbyrjQ8BMDQxmT',
166
+ # amount: '0.13283',
167
+ # confirmations: 6,
168
+ # state: 2,
169
+ # created_at: '2014-01-31T22:01:30+01:00'
170
+ # }
171
+ # @param [Hash] hde dados dum deposit
172
+ # @return [Hash] deposit uniformizado
173
+ def deposit_hash(hde)
174
+ {
175
+ id: hde[:address],
176
+ tp: 'deposit',
177
+ qtxt: 'btc',
178
+ fee: '0',
179
+ time: Time.parse(hde[:created_at]),
180
+ qt: hde[:amount],
181
+ lgid: Integer(hde[:deposit_id])
182
+ }
183
+ end
184
+
185
+ private
186
+
187
+ # HTTP GET request for public bitcoinde API queries.
188
+ def api_get(uri, **ops)
189
+ t = url("#{urb}/#{uri}", ops)
190
+ resposta(Curl.get(t) { |r| r.headers = hdrs('GET', t, nonce, {}) })
191
+ end
192
+
193
+ # HTTP POST request for private bitcoinde API queries involving user credentials.
194
+ def api_post(uri, **ops)
195
+ # pedidos POST HTTP nao levam parametros no URL - somente no header e ordenados
196
+ resposta(Curl.post("#{urb}/#{uri}") { |r| r.headers = hdrs('POST', "#{urb}/#{uri}", nonce, ops.sort) })
197
+ end
198
+
199
+ # @return [String] URL do pedido formatado com todos os parametros
200
+ def url(uri, ops)
201
+ ops.empty? ? uri : "#{uri}?#{URI.encode_www_form(ops)}"
202
+ end
203
+
204
+ # @return [Hash] headers necessarios para pedido HTTP
205
+ def hdrs(typ, qry, non, ops)
206
+ {
207
+ 'X-API-KEY': aky,
208
+ 'X-API-NONCE': non,
209
+ 'X-API-SIGNATURE': auth(typ, qry, non, URI.encode_www_form(ops))
210
+ }
211
+ end
212
+
213
+ # @return [String] assinarura codificada dos pedidos HTTP
214
+ def auth(typ, qry, non, par)
215
+ raise(ArgumentError, 'API Key is not set') unless aky
216
+ raise(ArgumentError, 'API Secret is not set') unless asc
217
+
218
+ OpenSSL::HMAC.hexdigest('sha256', asc, [typ, qry, aky, non, Digest::MD5.hexdigest(par)].join('#'))
219
+ end
220
+
221
+ # @return [Integer] continually-increasing unsigned integer nonce from the current Unix Time
222
+ def nonce
223
+ Integer(Float(Time.now) * 1e6)
224
+ end
225
+
226
+ # @return [Hash] resposta do pedido HTTP
227
+ def resposta(http)
228
+ http.response_code == 200 ? JSON.parse(http.body, symbolize_names: true) : http.status
229
+ rescue JSON::ParserError,
230
+ EOFError,
231
+ Errno::ECONNRESET,
232
+ Errno::EINVAL,
233
+ Net::HTTPBadResponse,
234
+ Net::HTTPHeaderSyntaxError,
235
+ Net::ProtocolError,
236
+ Timeout::Error => e
237
+ "Erro da API bitcoinde #{e.inspect}"
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('faraday')
4
+ require('json')
5
+
6
+ # @author Hernani Rodrigues Vaz
7
+ module Cns
8
+ # classe para acesso dados blockchain ETH
9
+ class Apies
10
+ # @return [String] apikey a juntar aos pedidos HTTP url:
11
+ attr_reader :key
12
+ # @return [String] base URL to use as a prefix for all requests
13
+ attr_reader :url
14
+
15
+ # @param [String] chv apikey a juntar aos pedidos HTTP url:
16
+ # @param [String] www base URL to use as a prefix for all requests
17
+ # @return [Apies] API etherscan base
18
+ def initialize(chv: ENV['ETHERSCAN_API_KEY'], www: 'https://api.etherscan.io/')
19
+ @key = chv
20
+ @url = www
21
+ end
22
+
23
+ # @return [<Symbol>] adapter for the connection - default :net_http
24
+ def adapter
25
+ @adapter ||= Faraday.default_adapter
26
+ end
27
+
28
+ # @return [<Faraday::Connection>] connection object with an URL & adapter
29
+ def conn
30
+ @conn ||=
31
+ Faraday.new(url: url) do |c|
32
+ c.request(:url_encoded)
33
+ c.adapter(adapter)
34
+ end
35
+ end
36
+
37
+ # @example
38
+ # [
39
+ # { account: '0x...', balance: '4000000000000000000' },
40
+ # { account: '0x...', balance: '87000000000000000000' }
41
+ # ]
42
+ # @param [String] ads lista enderecos carteiras ETH (max 20)
43
+ # @return [Array<Hash>] devolve lista com dados & saldo de carteiras ETH
44
+ def account(ads)
45
+ raise(Erro, 'maximo de 20 enderecos') if ads.size > 20
46
+
47
+ get(action: 'balancemulti', address: ads.join(','), tag: 'latest')[:result]
48
+ end
49
+
50
+ # @example
51
+ # [
52
+ # {
53
+ # blockNumber: '4984535',
54
+ # timeStamp: '1517094794',
55
+ # hash: '0x...',
56
+ # nonce: '10',
57
+ # blockHash: '0x...',
58
+ # transactionIndex: '17',
59
+ # from: '0x...',
60
+ # to: '0x...',
61
+ # value: '52627271000000000000',
62
+ # gas: '21000',
63
+ # gasPrice: '19000000000',
64
+ # isError: '0',
65
+ # txreceipt_status: '1',
66
+ # input: '0x',
67
+ # contractAddress: '',
68
+ # gasUsed: '21000',
69
+ # cumulativeGasUsed: '566293',
70
+ # confirmations: '5848660'
71
+ # },
72
+ # {}
73
+ # ]
74
+ # @param [String] add endereco carteira ETH
75
+ # @param [Hash] arg argumentos trabalho
76
+ # @option arg [Integer] :start_block starting blockNo to retrieve results
77
+ # @option arg [Integer] :end_block ending blockNo to retrieve results
78
+ # @option arg [String] :sort asc -> ascending order, desc -> descending order
79
+ # @option arg [Integer] :page to get paginated results
80
+ # @option arg [Integer] :offset max records to return
81
+ # @return [Array<Hash>] lista de transacoes
82
+ def norml_tx(add, **arg)
83
+ raise(Erro, 'endereco tem de ser definido') if add.nil? || add.empty?
84
+
85
+ ledger(**arg.merge(action: 'txlist', address: add))
86
+ end
87
+
88
+ # @example registo duplicado
89
+ # [
90
+ # {
91
+ # blockNumber: '3967652',
92
+ # timeStamp: '1499081515',
93
+ # hash: '0x registo duplicado com todos os dados iguais',
94
+ # nonce: '3',
95
+ # blockHash: '0x00a49e999036dc13dc6c4244bb1d51d3146fe7f00bfb500a7624d82e299c7328',
96
+ # from: '0xd0a6e6c54dbc68db5db3a091b171a77407ff7ccf',
97
+ # contractAddress: '0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0',
98
+ # to: '0x...',
99
+ # value: '0',
100
+ # tokenName: 'EOS',
101
+ # tokenSymbol: 'EOS',
102
+ # tokenDecimal: '18',
103
+ # transactionIndex: '83',
104
+ # gas: '173399',
105
+ # gasPrice: '21000000000',
106
+ # gasUsed: '173398',
107
+ # input: 'deprecated',
108
+ # cumulativeGasUsed: '7484878',
109
+ # confirmations: '3442641'
110
+ # },
111
+ # {}
112
+ # ]
113
+ # @param add (see norml_tx)
114
+ # @param [String] cdd token address (nil to get a list of all ERC20 transactions)
115
+ # @param arg (see norml_tx)
116
+ # @option arg (see norml_tx)
117
+ # @return [Array<Hash>] lista de token transfer events
118
+ def token_tx(add, cdd = nil, **arg)
119
+ raise(Erro, 'contrato ou endereco tem de estar definido') if (cdd || add).nil? || (cdd || add).empty?
120
+
121
+ # registos duplicados aparecem em token events (ver exemplo acima)
122
+ # -quando ha erros na blockchain (acho)
123
+ # -quando ha token events identicos no mesmo block (acho)
124
+ ledger(**arg.merge(action: 'tokentx', address: add, contractaddress: cdd))
125
+ end
126
+
127
+ # @param [Integer] pag pagina das transacoes a devolver
128
+ # @param [Array<Hash>] ary lista acumuladora das transacoes a devolver
129
+ # @param arg (see norml_tx)
130
+ # @option arg (see norml_tx)
131
+ # @return [Array<Hash>] devolve lista de transacoes/token transfer events
132
+ def ledger(pag = 0, ary = [], **arg)
133
+ r = get(**arg.merge(page: pag + 1, offset: 10_000))[:result]
134
+ ary += r
135
+ r.count < 10_000 ? ary : ledger(pag + 1, ary, **arg)
136
+ rescue StandardError
137
+ ary
138
+ end
139
+
140
+ private
141
+
142
+ # @example
143
+ # {
144
+ # status: '1',
145
+ # message: 'OK',
146
+ # result: []
147
+ # }
148
+ # @return [Hash] resultado do HTTP request
149
+ def get(**arg)
150
+ JSON.parse(
151
+ (conn.get('api') do |o|
152
+ o.headers = { content_type: 'application/json', accept: 'application/json', user_agent: 'etherscan;ruby' }
153
+ o.params = arg.merge(module: 'account', apikey: key).reject { |_, v| v.nil? }
154
+ end).body,
155
+ symbolize_names: true
156
+ )
157
+ rescue StandardError
158
+ { result: [] }
159
+ end
160
+ end
161
+ end