cns 0.1.0 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('bigdecimal/util')
4
+
5
+ # @author Hernani Rodrigues Vaz
6
+ module Cns
7
+ # classe para processar transacoes trades/ledger do bitcoinde
8
+ class Bitcoinde
9
+ # @return [Apius] API bitcoinde
10
+ attr_reader :api
11
+ # @return [Array<Hash>] todos os dados bigquery
12
+ attr_reader :bqd
13
+ # @return [Thor::CoreExt::HashWithIndifferentAccess] opcoes trabalho
14
+ attr_reader :ops
15
+
16
+ # @param [Hash] dad todos os dados bigquery
17
+ # @param [Thor::CoreExt::HashWithIndifferentAccess] pop opcoes trabalho
18
+ # @option pop [Hash] :h ({}) configuracao dias ajuste reposicionamento temporal
19
+ # @option pop [Boolean] :v (false) mostra dados transacoes trades & ledger?
20
+ # @option pop [Boolean] :t (false) mostra transacoes todas ou somente novas?
21
+ # @return [Bitcoinde] API bitcoinde - obter saldos & transacoes trades e ledger
22
+ def initialize(dad, pop)
23
+ @api = Apice.new
24
+ @bqd = dad
25
+ @ops = pop
26
+ end
27
+
28
+ # @return [Array<Hash>] lista trades bitcoinde novos
29
+ def trades
30
+ @trades ||= exd[:tt].select { |h| kyt.include?(h[:trade_id]) }
31
+ end
32
+
33
+ # @return [Array<Hash>] lista ledger (deposits + withdrawals) bitcoinde novos
34
+ def ledger
35
+ @ledger ||= exd[:tl].select { |h| kyl.include?(h[:txid]) }
36
+ end
37
+
38
+ # @return [String] texto saldos & transacoes & ajuste dias
39
+ def mostra_resumo
40
+ puts("\nBITCOINDE\ntipo bitcoinde bigquery")
41
+ exd[:sl].each { |k, v| puts(formata_saldos(k, v)) }
42
+ mostra_totais
43
+
44
+ mostra_trades
45
+ mostra_ledger
46
+ return if trades.empty?
47
+
48
+ puts("\nstring ajuste dias dos trades\n-h=#{kyt.map { |e| "#{e}:0" }.join(' ')}")
49
+ end
50
+
51
+ # @return [Hash] dados exchange bitcoinde - saldos & trades & deposits & withdrawals
52
+ def exd
53
+ @exd ||= {
54
+ sl: api.account_de,
55
+ tt: api.trades_de,
56
+ tl: api.deposits_de + api.withdrawals_de
57
+ }
58
+ end
59
+
60
+ # @return [Array<String>] lista txid dos trades novos
61
+ def kyt
62
+ @kyt ||= exd[:tt].map { |h| h[:trade_id] }.flatten - (ops[:t] ? [] : bqd[:nt].map { |e| e[:txid] })
63
+ end
64
+
65
+ # @return [Array<Integer>] lista txid dos ledger novos
66
+ def kyl
67
+ @kyl ||= exd[:tl].map { |h| h[:txid] }.flatten - (ops[:t] ? [] : bqd[:nl].map { |e| e[:txid] })
68
+ end
69
+
70
+ # @example (see Apice#account_de)
71
+ # @param [String] moe codigo bitcoinde da moeda
72
+ # @param [Hash] hsx saldo bitcoinde da moeda
73
+ # @return [String] texto formatado saldos
74
+ def formata_saldos(moe, hsx)
75
+ b = bqd[:sl][moe.downcase.to_sym].to_d
76
+ e = hsx[:total_amount].to_d
77
+ format(
78
+ '%<mo>-5.5s %<ex>21.9f %<bq>21.9f %<ok>3.3s',
79
+ mo: moe.upcase,
80
+ ex: e,
81
+ bq: b,
82
+ ok: e == b ? 'OK' : 'NOK'
83
+ )
84
+ end
85
+
86
+ # @example (see Apice#trades_de)
87
+ # @param (see Bigquery#det_val1)
88
+ # @return [String] texto formatado trade
89
+ def formata_trades(htx)
90
+ format(
91
+ '%<ky>-6.6s %<dt>19.19s %<dp>10.10s %<ty>-5.5s %<mo>-8.8s %<vl>18.8f %<co>8.2f',
92
+ ky: htx[:trade_id],
93
+ dt: Time.parse(htx[:successfully_finished_at]),
94
+ dp: Time.parse(htx[:trade_marked_as_paid_at]),
95
+ ty: htx[:type],
96
+ mo: htx[:trading_pair].upcase,
97
+ vl: htx[:amount_currency_to_trade].to_d,
98
+ co: htx[:volume_currency_to_pay].to_d
99
+ )
100
+ end
101
+
102
+ # @example (see Apice#deposits_unif_de)
103
+ # @example (see Apice#withdrawals_unif_de)
104
+ # @param (see Bigquery#del_val)
105
+ # @return [String] texto formatado ledger
106
+ def formata_ledger(hlx)
107
+ format(
108
+ '%<ky>6i %<dt>19.19s %<ty>-10.10s %<mo>-3.3s %<pr>19.8f %<vl>18.8f',
109
+ ky: hlx[:txid],
110
+ dt: hlx[:time],
111
+ ty: hlx[:tp],
112
+ mo: hlx[:moe].upcase,
113
+ pr: hlx[:qt].to_d,
114
+ vl: hlx[:fee].to_d
115
+ )
116
+ end
117
+
118
+ # @return [String] texto numero de transacoes
119
+ def mostra_totais
120
+ a = exd[:tt].count
121
+ b = bqd[:nt].count
122
+ c = exd[:tl].count
123
+ d = bqd[:nl].count
124
+
125
+ puts("TRADES #{format('%<a>20i %<b>21i %<o>3.3s', a: a, b: b, o: a == b ? 'OK' : 'NOK')}")
126
+ puts("LEDGER #{format('%<c>20i %<d>21i %<o>3.3s', c: c, d: d, o: c == d ? 'OK' : 'NOK')}")
127
+ end
128
+
129
+ # @return [String] texto transacoes trades
130
+ def mostra_trades
131
+ return unless ops[:v] && !trades.empty?
132
+
133
+ puts("\ntrades data hora dt criacao tipo par qtd eur")
134
+ trades.sort { |a, b| Time.parse(b[:successfully_finished_at]) <=> Time.parse(a[:successfully_finished_at]) }
135
+ .each { |h| puts(formata_trades(h)) }
136
+ end
137
+
138
+ # @return [String] texto transacoes ledger
139
+ def mostra_ledger
140
+ return unless ops[:v] && !ledger.empty?
141
+
142
+ puts("\nledger data hora tipo moe quantidade custo")
143
+ ledger.sort { |a, b| b[:time] <=> a[:time] }.each { |h| puts(formata_ledger(h)) }
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('bigdecimal/util')
4
+
5
+ # @author Hernani Rodrigues Vaz
6
+ module Cns
7
+ # chaves a eliminar da API - resultado deve ser ignirado pois muda a cada pedido API feito
8
+ DL = %i[cumulativeGasUsed confirmations].freeze
9
+
10
+ # (see Etherscan)
11
+ class Etherscan
12
+ # @return [Apibc] API blockchains
13
+ attr_reader :api
14
+ # @return [Array<Hash>] todos os dados bigquery
15
+ attr_reader :bqd
16
+ # @return [Thor::CoreExt::HashWithIndifferentAccess] opcoes trabalho
17
+ attr_reader :ops
18
+
19
+ # @param [Hash] dad todos os dados bigquery
20
+ # @param [Thor::CoreExt::HashWithIndifferentAccess] pop opcoes trabalho
21
+ # @option pop [Hash] :h ({}) configuracao dias ajuste reposicionamento temporal
22
+ # @option pop [Boolean] :v (false) mostra dados transacoes normais & tokens?
23
+ # @return [Etherscan] API etherscan - processar transacoes normais e tokens
24
+ def initialize(dad, pop)
25
+ @api = Apibc.new
26
+ @bqd = dad
27
+ @ops = pop
28
+ end
29
+
30
+ # @return [Array<Hash>] lista transacoes normais novas
31
+ def novtx
32
+ @novtx ||= bcd.map { |e| e[:tx].select { |n| idt.include?(n[:itx]) } }.flatten
33
+ end
34
+
35
+ # @return [Array<Hash>] lista transacoes token novas
36
+ def novkx
37
+ @novkx ||= bcd.map { |e| e[:kx].select { |n| idk.include?(n[:itx]) } }.flatten
38
+ end
39
+
40
+ # @return [Array<String>] lista dos meus enderecos
41
+ def lax
42
+ @lax ||= bqd[:wb].map { |h| h[:ax] }
43
+ end
44
+
45
+ # @return [Array<Hash>] todos os dados etherscan - saldos & transacoes
46
+ def bcd
47
+ @bcd ||= api.account_es(lax).map { |e| base_bc(e) }
48
+ end
49
+
50
+ # @return [Array<Hash>] todos os dados juntos bigquery & etherscan
51
+ def dados
52
+ @dados ||= bqd[:wb].map { |b| bq_bc(b, bcd.select { |s| b[:ax] == s[:ax] }.first) }
53
+ end
54
+
55
+ # @return [Array<Integer>] lista indices transacoes normais novas
56
+ def idt
57
+ @idt ||= (bcd.map { |e| e[:tx].map { |n| n[:itx] } }.flatten - (ops[:t] ? [] : bqd[:nt].map { |t| t[:itx] }))
58
+ end
59
+
60
+ # @return [Array<Integer>] lista indices transacoes token novas
61
+ def idk
62
+ @idk ||= (bcd.map { |e| e[:kx].map { |n| n[:itx] } }.flatten - (ops[:t] ? [] : bqd[:nk].map { |t| t[:itx] }))
63
+ end
64
+
65
+ # @example (see Apibc#account_es)
66
+ # @param [Hash] abc account etherscan
67
+ # @return [Hash] dados etherscan - address, saldo & transacoes
68
+ def base_bc(abc)
69
+ a = abc[:account]
70
+ {
71
+ ax: a,
72
+ sl: (abc[:balance].to_d / 10**18).round(10),
73
+ tx: filtrar_tx(a, api.norml_es(a)),
74
+ kx: filtrar_tx(a, api.token_es(a))
75
+ }
76
+ end
77
+
78
+ # @param [Hash] wbq wallet bigquery
79
+ # @param [Hash] hbc dados etherscan - address, saldo & transacoes
80
+ # @return [Hash] dados juntos bigquery & etherscan
81
+ def bq_bc(wbq, hbc)
82
+ {
83
+ id: wbq[:id],
84
+ ax: wbq[:ax],
85
+ bs: wbq[:sl],
86
+ bt: bqd[:nt].select { |t| t[:iax] == wbq[:ax] },
87
+ bk: bqd[:nk].select { |t| t[:iax] == wbq[:ax] },
88
+ es: hbc[:sl],
89
+ et: hbc[:tx],
90
+ ek: hbc[:kx]
91
+ }
92
+ end
93
+
94
+ # @param add (see Apibc#norml_es)
95
+ # @param [Array<Hash>] ary lista transacoes/token events
96
+ # @return [Array<Hash>] lista transacoes/token events filtrada
97
+ def filtrar_tx(add, ary)
98
+ # elimina transferencia from: (lax) to: (add) - esta transferencia aparece em from: (add) to: (lax)
99
+ # elimina chaves irrelevantes (DL) & adiciona chave indice itx & adiciona identificador da carteira iax
100
+ ary.delete_if { |h| h[:to] == add && lax.include?(h[:from]) }
101
+ .map { |h| h.delete_if { |k, _| DL.include?(k) }.merge(itx: Integer(h[:blockNumber]), iax: add) }
102
+ end
103
+
104
+ # @return [Array<Hash>] lista ordenada transacoes normais novas
105
+ def sortx
106
+ novtx.sort { |a, b| a[:itx] <=> b[:itx] }
107
+ end
108
+
109
+ # @return [Array<Hash>] lista ordenada transacoes token novas
110
+ def sorkx
111
+ novkx.sort { |a, b| a[:itx] <=> b[:itx] }
112
+ end
113
+
114
+ # @return [Array<Hash>] lista ordenada transacoes (normais & token) novas
115
+ def sorax
116
+ (novtx + novkx).sort { |a, b| a[:itx] <=> b[:itx] }
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @author Hernani Rodrigues Vaz
4
+ module Cns
5
+ # classe para processar transacoes do etherscan
6
+ class Etherscan
7
+ # @return [String] texto carteiras & transacoes & ajuste dias
8
+ def mostra_resumo
9
+ return unless dados.count.positive?
10
+
11
+ puts("\nid address etherscan nm tk bigquery nm tk")
12
+ dados.each { |e| puts(formata_carteira(e)) }
13
+ mostra_transacao_norml
14
+ mostra_transacao_token
15
+ mostra_configuracao_ajuste_dias
16
+ end
17
+
18
+ # @param [Hash] hjn dados juntos bigquery & etherscan
19
+ # @return [String] texto formatado duma carteira
20
+ def formata_carteira(hjn)
21
+ format(
22
+ '%<s1>-6.6s %<s2>-32.32s ',
23
+ s1: hjn[:id],
24
+ s2: formata_endereco(hjn[:ax], 32)
25
+ ) + formata_valores(hjn)
26
+ end
27
+
28
+ # @param (see formata_carteira)
29
+ # @return [String] texto formatado valores duma carteira
30
+ def formata_valores(hjn)
31
+ format(
32
+ '%<v1>11.6f %<n1>2i %<n3>2i %<v2>12.6f %<n2>2i %<n4>2i %<ok>-3s',
33
+ v1: hjn[:es],
34
+ n1: hjn[:et].count,
35
+ n3: hjn[:ek].count,
36
+ v2: hjn[:bs],
37
+ n2: hjn[:bt].count,
38
+ n4: hjn[:bk].count,
39
+ ok: ok?(hjn) ? 'OK' : 'NOK'
40
+ )
41
+ end
42
+
43
+ # @param (see formata_carteira)
44
+ # @return [Boolean] carteira tem transacoes novas(sim=NOK, nao=OK)?
45
+ def ok?(hjn)
46
+ hjn[:bs] == hjn[:es] && hjn[:bt].count == hjn[:et].count && hjn[:bk].count == hjn[:ek].count
47
+ end
48
+
49
+ # @example ether address inicio..fim
50
+ # 0x10f3a0cf0b534c..c033cf32e8a03586
51
+ # @param add (see filtrar_tx)
52
+ # @param [Integer] max chars a mostrar
53
+ # @return [String] endereco formatado
54
+ def formata_endereco(add, max)
55
+ i = Integer((max - 2) / 2)
56
+ e = (max <= 20 ? bqd[:wb].select { |s| s[:ax] == add }.first : nil) || { id: add }
57
+ max < 7 ? 'erro' : "#{e[:id][0, i - 3]}..#{add[-i - 3..]}"
58
+ end
59
+
60
+ # @example (see Apibc#norml_es)
61
+ # @param [Hash] htx transacao normal etherscan
62
+ # @return [String] texto formatado transacao normal etherscan
63
+ def formata_transacao_norml(htx)
64
+ format(
65
+ '%<bn>9i %<fr>-20.20s %<to>-20.20s %<dt>10.10s %<vl>17.6f',
66
+ bn: htx[:blockNumber],
67
+ fr: formata_endereco(htx[:from], 20),
68
+ to: formata_endereco(htx[:to], 20),
69
+ dt: Time.at(Integer(htx[:timeStamp])),
70
+ vl: (htx[:value].to_d / 10**18).round(10)
71
+ )
72
+ end
73
+
74
+ # @example (see Apibc#token_es)
75
+ # @param [Hash] hkx transacao token etherscan
76
+ # @return [String] texto formatado transacao token etherscan
77
+ def formata_transacao_token(hkx)
78
+ format(
79
+ '%<bn>9i %<fr>-20.20s %<to>-20.20s %<dt>10.10s %<vl>11.3f %<sy>-5.5s',
80
+ bn: hkx[:blockNumber],
81
+ fr: formata_endereco(hkx[:from], 20),
82
+ to: formata_endereco(hkx[:to], 20),
83
+ dt: Time.at(Integer(hkx[:timeStamp])),
84
+ vl: (hkx[:value].to_d / 10**18).round(10),
85
+ sy: hkx[:tokenSymbol]
86
+ )
87
+ end
88
+
89
+ # @return [String] texto transacoes normais
90
+ def mostra_transacao_norml
91
+ return unless ops[:v] && novtx.count.positive?
92
+
93
+ puts("\ntx normal from to data valor")
94
+ sortx.each { |e| puts(formata_transacao_norml(e)) }
95
+ end
96
+
97
+ # @return [String] texto transacoes token
98
+ def mostra_transacao_token
99
+ return unless ops[:v] && novkx.count.positive?
100
+
101
+ puts("\ntx token from to data valor")
102
+ sorkx.each { |e| puts(formata_transacao_token(e)) }
103
+ end
104
+
105
+ # @return [String] texto configuracao ajuste dias das transacoes (normais & token)
106
+ def mostra_configuracao_ajuste_dias
107
+ return unless (novtx.count + novkx.count).positive?
108
+
109
+ puts("\nstring ajuste dias\n-h=#{sorax.map { |e| "#{e[:blockNumber]}:0" }.join(' ')}")
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('bigdecimal/util')
4
+
5
+ # @author Hernani Rodrigues Vaz
6
+ module Cns
7
+ # (see Greymass)
8
+ class Greymass
9
+ # @return [Apibc] API blockchains
10
+ attr_reader :api
11
+ # @return [Array<Hash>] todos os dados bigquery
12
+ attr_reader :bqd
13
+ # @return [Thor::CoreExt::HashWithIndifferentAccess] opcoes trabalho
14
+ attr_reader :ops
15
+
16
+ # @param [Hash] dad todos os dados bigquery
17
+ # @param [Thor::CoreExt::HashWithIndifferentAccess] pop opcoes trabalho
18
+ # @option pop [Hash] :h ({}) configuracao dias ajuste reposicionamento temporal
19
+ # @option pop [Boolean] :v (false) mostra dados transacoes?
20
+ # @option pop [Boolean] :t (false) mostra transacoes todas ou somente novas?
21
+ # @return [Greymass] API greymass - processar transacoes
22
+ def initialize(dad, pop)
23
+ @api = Apibc.new
24
+ @bqd = dad
25
+ @ops = pop
26
+ end
27
+
28
+ # @return [Array<Hash>] lista transacoes novas
29
+ def novax
30
+ @novax ||= bcd.map { |e| e[:tx].select { |s| idt.include?(s[:itx]) } }.flatten
31
+ end
32
+
33
+ # @return [Array<String>] lista dos meus enderecos
34
+ def lax
35
+ @lax ||= bqd[:wb].map { |h| h[:ax] }
36
+ end
37
+
38
+ # @return [Array<Hash>] todos os dados greymass - saldos & transacoes
39
+ def bcd
40
+ @bcd ||= bqd[:wb].map { |e| base_bc(e) }
41
+ end
42
+
43
+ # @return [Array<Hash>] todos os dados juntos bigquery & greymass
44
+ def dados
45
+ @dados ||= bqd[:wb].map { |b| bq_bc(b, bcd.select { |s| b[:ax] == s[:ax] }.first) }
46
+ end
47
+
48
+ # @return [Array<Integer>] lista indices transacoes novas
49
+ def idt
50
+ @idt ||= (bcd.map { |e| e[:tx].map { |n| n[:itx] } }.flatten - (ops[:t] ? [] : bqd[:nt].map { |t| t[:itx] }))
51
+ end
52
+
53
+ # @example (see Apibc#account_gm)
54
+ # @param [Hash] wbq wallet bigquery
55
+ # @return [Hash] dados greymass - address, saldo & transacoes
56
+ def base_bc(wbq)
57
+ a = wbq[:ax]
58
+ {
59
+ ax: a,
60
+ sl: greymass_sl(a).inject(:+),
61
+ tx: filtrar_tx(a, api.ledger_gm(a))
62
+ }
63
+ end
64
+
65
+ # @param wbq (see base_bc)
66
+ # @param [Hash] hbc dados greymass - address, saldo & transacoes
67
+ # @return [Hash] dados juntos bigquery & greymass
68
+ def bq_bc(wbq, hbc)
69
+ {
70
+ id: wbq[:id],
71
+ ax: wbq[:ax],
72
+ bs: wbq[:sl],
73
+ bt: bqd[:nt].select { |t| t[:iax] == wbq[:ax] },
74
+ es: hbc[:sl],
75
+ et: hbc[:tx]
76
+ }
77
+ end
78
+
79
+ # @param (see filtrar_tx)
80
+ # @return [Array<BigDecimal>] lista recursos - liquido, net, spu
81
+ def greymass_sl(add)
82
+ v = api.account_gm(add)
83
+ [
84
+ v[:core_liquid_balance].to_d,
85
+ v[:total_resources][:net_weight].to_d,
86
+ v[:total_resources][:cpu_weight].to_d
87
+ ]
88
+ end
89
+
90
+ # @param add (see Apibc#account_gm)
91
+ # @param [Array<Hash>] ary lista transacoes
92
+ # @return [Array<Hash>] lista transacoes filtrada
93
+ def filtrar_tx(add, ary)
94
+ # elimina transferencia from: (lax) to: (add) - esta transferencia aparece em from: (add) to: (lax)
95
+ # adiciona chave indice itx & adiciona identificador da carteira iax
96
+ ary.delete_if { |h| act_data(h)[:to] == add && lax.include?(act_data(h)[:from]) }
97
+ .map { |h| h.merge(itx: h[:global_action_seq], iax: add) }
98
+ end
99
+
100
+ # @return [Array<Hash>] lista ordenada transacoes novas
101
+ def sorax
102
+ novax.sort { |a, b| b[:itx] <=> a[:itx] }
103
+ end
104
+ end
105
+ end