cns 0.1.0 → 0.1.1

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 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