cns 2.0.2 → 2.0.3

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: ba101a6a6bbdbb1272e8cc61fe00f03b779b907066dd3c2ac6c29ee2543c8ec5
4
- data.tar.gz: fdb6a8433f4e738851490b07baae241b524326f6917f07e260039ac19d6b5df6
3
+ metadata.gz: 353a19c9f3ae3d6e28ce9495e8d8fdcc989a0ead6915a7d4ba6ad8b03c574971
4
+ data.tar.gz: 9d074553b5857af05315037f2bc6f7e0fd7a7402fe29406986d25720e03ad9f4
5
5
  SHA512:
6
- metadata.gz: 6070637e17f7176b2bb28be217c0a7b1ad1f88066a9fa8befe312a2f687237cfe503f744c14652d2654ad0dfd8b878358286b097a7fd3a966e87fdb37410029c
7
- data.tar.gz: d5de5d4806a1cfd64f349f120532557d3c161f5ddfec78a8972062c181f644906b0f3c8d85287bd9d879d1b2ed4131fcb2d76fde225569a51ca803e3e176a544
6
+ metadata.gz: 620514e54c2e1d9bd29f1d1ad4be69b2bd01690fde7034fad875c6e1b17c7b8e195fe538f9047732701ba040fe9c76b33052500a9af17e17490b6d56ea9aa9ff
7
+ data.tar.gz: 8377df664f22714ef724d58bd34b43c6c0243a5e1e44c4cff444e68fbaf12b209824bf7c00c9e62fcc0b953c53ed5b43aaaa233b2a02cf14874ccd32edecf3ba
data/.rubocop.yml CHANGED
@@ -56,6 +56,9 @@ Style/StringLiterals:
56
56
  Style/NumericLiterals:
57
57
  MinDigits: 5
58
58
 
59
+ Style/ParallelAssignment:
60
+ Enabled: false
61
+
59
62
  # Linting
60
63
  Lint/UselessAssignment:
61
64
  Enabled: true
data/Gemfile.lock CHANGED
@@ -1,11 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cns (2.0.2)
4
+ cns (2.0.3)
5
5
  curb
6
6
  faraday
7
7
  faraday-retry
8
8
  google-cloud-bigquery
9
+ memoist
9
10
  thor
10
11
 
11
12
  GEM
@@ -13,7 +14,7 @@ GEM
13
14
  specs:
14
15
  addressable (2.8.7)
15
16
  public_suffix (>= 2.0.2, < 7.0)
16
- ast (2.4.2)
17
+ ast (2.4.3)
17
18
  backport (1.2.0)
18
19
  base64 (0.2.0)
19
20
  benchmark (0.4.0)
@@ -106,18 +107,19 @@ GEM
106
107
  language_server-protocol (3.17.0.4)
107
108
  lint_roller (1.1.0)
108
109
  logger (1.6.6)
110
+ memoist (0.16.2)
109
111
  mini_mime (1.1.5)
110
112
  multi_json (1.15.0)
111
113
  mutex_m (0.3.0)
112
114
  net-http (0.6.0)
113
115
  uri
114
- nokogiri (1.18.4-x86_64-linux-gnu)
116
+ nokogiri (1.18.5-x86_64-linux-gnu)
115
117
  racc (~> 1.4)
116
118
  observer (0.1.2)
117
119
  os (1.1.4)
118
120
  ostruct (0.6.1)
119
121
  parallel (1.26.3)
120
- parser (3.3.7.1)
122
+ parser (3.3.7.2)
121
123
  ast (~> 2.4.1)
122
124
  racc
123
125
  public_suffix (6.0.1)
@@ -152,8 +154,8 @@ GEM
152
154
  rubocop-ast (>= 1.38.0, < 2.0)
153
155
  ruby-progressbar (~> 1.7)
154
156
  unicode-display_width (>= 2.4.0, < 4.0)
155
- rubocop-ast (1.39.0)
156
- parser (>= 3.3.1.0)
157
+ rubocop-ast (1.41.0)
158
+ parser (>= 3.3.7.2)
157
159
  rubocop-rake (0.7.1)
158
160
  lint_roller (~> 1.1)
159
161
  rubocop (>= 1.72.1)
data/cns.gemspec CHANGED
@@ -38,6 +38,7 @@ Gem::Specification.new do |spec|
38
38
  spec.add_dependency('faraday')
39
39
  spec.add_dependency('faraday-retry')
40
40
  spec.add_dependency('google-cloud-bigquery')
41
+ spec.add_dependency('memoist')
41
42
  spec.add_dependency('thor')
42
43
  spec.metadata['rubygems_mfa_required'] = 'true'
43
44
  end
data/lib/cns/apibc.rb CHANGED
@@ -12,82 +12,86 @@ module Cns
12
12
  GMPS = 100 # Greymass maximum actions per request
13
13
 
14
14
  def initialize
15
- @escn = connection('https://api.etherscan.io')
16
- @gmcn = connection('https://eos.greymass.com')
15
+ @escn = bccn('https://api.etherscan.io')
16
+ @gmcn = bccn('https://eos.greymass.com')
17
17
  @esky = ENV.fetch('ETHERSCAN_API_KEY', nil)
18
18
  end
19
19
 
20
20
  # Get account balances for multiple ETH addresses
21
- # @param [Array<String>] addresses List of ETH addresses (max 20)
21
+ # @param [Array<String>] ads List of ETH addresses (max 20)
22
22
  # @return [Array<Hash>] List of addresses with balances
23
- def account_es(addresses)
24
- return [] if addresses.nil? || addresses.empty?
23
+ def account_es(ads)
24
+ return [] if ads.nil? || ads.empty?
25
25
 
26
26
  # Batch addresses into groups of 20 (Etherscan limit) and fetch balances
27
- addresses.each_slice(20).flat_map do |b|
27
+ ads.each_slice(20).flat_map do |b|
28
28
  res = es_req('balancemulti', b.join(','), 1, tag: 'latest')
29
- res[:status] == '1' ? res[:result] || [] : []
29
+ res[:status] == '1' ? Array(res[:result]) : []
30
30
  end
31
+ rescue StandardError
32
+ []
31
33
  end
32
34
 
33
35
  # Get normal transactions for ETH address
34
- # @param [String] address endereco ETH
36
+ # @param [String] add endereco ETH
35
37
  # @return [Array<Hash>] lista transacoes normais etherscan
36
- def norml_es(address)
37
- pag_es_req('txlist', address)
38
+ def norml_es(add)
39
+ pag_es_req('txlist', add)
38
40
  end
39
41
 
40
42
  # Get internal transactions for ETH address
41
43
  # @param (see norml_es)
42
44
  # @return [Array<Hash>] lista transacoes internas etherscan
43
- def inter_es(address)
44
- pag_es_req('txlistinternal', address)
45
+ def inter_es(add)
46
+ pag_es_req('txlistinternal', add)
45
47
  end
46
48
 
47
49
  # Get mined blocks for ETH address
48
50
  # @param (see norml_es)
49
51
  # @return [Array<Hash>] lista blocos etherscan
50
- def block_es(address)
51
- pag_es_req('getminedblocks', address, blocktype: 'blocks')
52
+ def block_es(add)
53
+ pag_es_req('getminedblocks', add, blocktype: 'blocks')
52
54
  end
53
55
 
54
56
  # Get withdrawals for ETH address
55
57
  # @param (see norml_es)
56
58
  # @return [Array<Hash>] lista blocos etherscan
57
- def withw_es(address)
58
- pag_es_req('txsBeaconWithdrawal', address)
59
+ def withw_es(add)
60
+ pag_es_req('txsBeaconWithdrawal', add)
59
61
  end
60
62
 
61
63
  # Get token transfers for ETH address
62
64
  # @param (see norml_es)
63
65
  # @return [Array<Hash>] lista token transfer events etherscan
64
- def token_es(address)
65
- pag_es_req('tokentx', address)
66
+ def token_es(add)
67
+ pag_es_req('tokentx', add)
66
68
  end
67
69
 
68
70
  # Get EOS account information
69
- # @param [String] address EOS account name
71
+ # @param [String] add EOS account name
70
72
  # @return [Hash] Account details with resources
71
- def account_gm(address)
72
- res = gm_req('/v1/chain/get_account', account_name: address)
73
+ def account_gm(add)
74
+ res = gm_req('/v1/chain/get_account', account_name: add)
73
75
  res[:core_liquid_balance]&.to_d&.positive? ? res : gm_erro
74
76
  end
75
77
 
76
78
  # Get complete transaction history for EOS account
77
79
  # @param (see account_gm)
78
80
  # @return [Array<Hash>] lista completa transacoes greymass
79
- def ledger_gm(address)
81
+ def ledger_gm(add)
80
82
  trx = []
81
83
  pos = 0
82
84
  loop do
83
- res = gm_req('/v1/history/get_actions', account_name: address, pos: pos, offset: GMPS)
84
- bth = res[:actions] || []
85
+ res = gm_req('/v1/history/get_actions', account_name: add, pos: pos, offset: GMPS)
86
+ bth = Array(res[:actions])
85
87
  trx.concat(bth)
86
88
  break if bth.size < GMPS
87
89
 
88
90
  pos += GMPS
89
91
  end
90
92
  trx
93
+ rescue StandardError
94
+ trx
91
95
  end
92
96
 
93
97
  private
@@ -99,7 +103,7 @@ module Cns
99
103
  # @param [Hash] prm Additional request parameters
100
104
  # @return [Hash] Parsed API response
101
105
  def es_req(act, add, pag = 1, prm = {})
102
- parse_json(@escn.get('/api', prm.merge(module: 'account', action: act, address: add, page: pag, apikey: @esky)))
106
+ pjsn(@escn.get('/api', prm.merge(module: 'account', action: act, address: add, page: pag, apikey: @esky)))
103
107
  rescue Faraday::Error
104
108
  {status: '0'}
105
109
  end
@@ -117,13 +121,15 @@ module Cns
117
121
  res = es_req(act, add, pag, prm)
118
122
  break unless res[:status] == '1'
119
123
 
120
- bth = res[:result] || []
124
+ bth = Array(res[:result])
121
125
  trx.concat(bth)
122
126
  break if bth.size < ESPS
123
127
 
124
128
  pag += 1
125
129
  end
126
130
  trx
131
+ rescue StandardError
132
+ trx
127
133
  end
128
134
 
129
135
  # Make a request to the Greymass API
@@ -131,7 +137,7 @@ module Cns
131
137
  # @param [Hash] pyl Request payload
132
138
  # @return [Hash] Parsed API response
133
139
  def gm_req(url, pyl)
134
- parse_json(@gmcn.post(url) { |r| r.body = pyl })
140
+ pjsn(@gmcn.post(url) { |r| r.body = pyl })
135
141
  rescue Faraday::Error
136
142
  gm_erro
137
143
  end
@@ -145,7 +151,7 @@ module Cns
145
151
  # Safely parse JSON response
146
152
  # @param [Faraday::Response] res API response
147
153
  # @return [Hash] Parsed JSON or empty hash on error
148
- def parse_json(res)
154
+ def pjsn(res)
149
155
  return {} if res.nil? || res.body.to_s.empty?
150
156
 
151
157
  JSON.parse(res.body, symbolize_names: true) || {}
@@ -156,7 +162,7 @@ module Cns
156
162
  # Create a Faraday connection with JSON configuration and retry logic
157
163
  # @param [String] url Base URL for the API
158
164
  # @return [Faraday::Connection] Configured Faraday connection
159
- def connection(url)
165
+ def bccn(url)
160
166
  Faraday.new(url) do |c|
161
167
  c.request(:json)
162
168
  c.headers = {accept: 'application/json', user_agent: 'blockchain-api-client'}
data/lib/cns/apice.rb CHANGED
@@ -12,11 +12,13 @@ module Cns
12
12
  API = {de: 'https://api.bitcoin.de/v4', us: 'https://api.kraken.com/0/private'}.freeze
13
13
 
14
14
  def initialize
15
- @curl = Curl::Easy.new
16
- @curl.timeout = 30
17
- @curl.connect_timeout = 10
18
- @curl.follow_location = true
19
- @curl.ssl_verify_peer = true
15
+ @curl =
16
+ Curl::Easy.new.tap do |c|
17
+ c.timeout = 30
18
+ c.connect_timeout = 10
19
+ c.follow_location = true
20
+ c.ssl_verify_peer = true
21
+ end
20
22
  @deky = ENV.fetch('BITCOINDE_API_KEY', nil)
21
23
  @desc = ENV.fetch('BITCOINDE_API_SECRET', nil)
22
24
  @usky = ENV.fetch('KRAKEN_API_KEY', nil)
@@ -27,8 +29,8 @@ module Cns
27
29
  # @return [Hash] saldos no bitcoinde
28
30
  def account_de
29
31
  uri = "#{API[:de]}/account"
30
- run_curl(@curl, uri, headers: hde(uri))
31
- parse_json(@curl).dig(:data, :balances) || {}
32
+ rcrl(@curl, uri, headers: hde(uri))
33
+ pjsn(@curl).dig(:data, :balances) || {}
32
34
  rescue Curl::Err::CurlError
33
35
  {}
34
36
  end
@@ -62,8 +64,8 @@ module Cns
62
64
  def account_us
63
65
  uri = 'Balance'
64
66
  ops = {nonce: nnc}
65
- run_curl(@curl, "#{API[:us]}/#{uri}", method: 'POST', post_data: ops, headers: hus(uri, ops))
66
- parse_json(@curl).fetch(:result, {})
67
+ rcrl(@curl, "#{API[:us]}/#{uri}", method: 'POST', post_data: ops, headers: hus(uri, ops))
68
+ pjsn(@curl).fetch(:result, {})
67
69
  rescue Curl::Err::CurlError
68
70
  {}
69
71
  end
@@ -109,8 +111,8 @@ module Cns
109
111
  # Rate limiting for page requests (2s in Kraken)
110
112
  sleep(@lpag - Time.now + 2) if @lpag && Time.now - @lpag < 2
111
113
  ops = {nonce: nnc, ofs: ofs}
112
- run_curl(@curl, "#{API[:us]}/#{uri}", method: 'POST', post_data: ops, headers: hus(uri, ops))
113
- bth = parse_json(@curl).fetch(:result, {}).fetch(key, []).map { |k, v| us_unif(k, v) }
114
+ rcrl(@curl, "#{API[:us]}/#{uri}", method: 'POST', post_data: ops, headers: hus(uri, ops))
115
+ bth = pjsn(@curl).fetch(:result, {}).fetch(key, []).map { |k, v| us_unif(k, v) }
114
116
  break if bth.empty?
115
117
 
116
118
  ary.concat(bth)
@@ -131,11 +133,11 @@ module Cns
131
133
  pag = 1
132
134
  loop do
133
135
  url = "#{uri}?#{URI.encode_www_form(prm.merge(page: pag))}"
134
- run_curl(@curl, url, headers: hde(url))
135
- res = parse_json(@curl)
136
+ rcrl(@curl, url, headers: hde(url))
137
+ res = pjsn(@curl)
136
138
  bth = res.fetch(key, [])
137
139
  ary.concat(block_given? ? yield(bth) : bth)
138
- break if res[:page]&.[](:current)&.>= res[:page]&.[](:last)
140
+ break if res[:page]&.fetch(:current, 0)&.>= res[:page]&.fetch(:last, 0)
139
141
 
140
142
  pag += 1
141
143
  end
@@ -148,7 +150,7 @@ module Cns
148
150
  # @param [String] method HTTP method (GET or POST)
149
151
  # @param [Hash] post_data Data to send in POST requests
150
152
  # @param [Hash] headers HTTP headers for the request
151
- def run_curl(curl, url, method: 'GET', post_data: nil, headers: {})
153
+ def rcrl(curl, url, method: 'GET', post_data: nil, headers: {})
152
154
  curl.reset
153
155
  curl.url = url
154
156
  curl.http(method)
@@ -160,8 +162,10 @@ module Cns
160
162
  # Safe JSON parsing with error handling
161
163
  # @param [Curl::Easy] res Curl response object
162
164
  # @return [Hash] Parsed JSON or empty hash on error
163
- def parse_json(res)
164
- JSON.parse(res.body_str, symbolize_names: true)
165
+ def pjsn(res)
166
+ return {} if res.nil? || res.body_str.to_s.empty?
167
+
168
+ JSON.parse(res.body_str, symbolize_names: true) || {}
165
169
  rescue JSON::ParserError
166
170
  {}
167
171
  end
data/lib/cns/bigquery.rb CHANGED
@@ -2,11 +2,13 @@
2
2
 
3
3
  require('google/cloud/bigquery')
4
4
  require('bigdecimal/util')
5
+ require('memoist')
5
6
 
6
7
  # @author Hernani Rodrigues Vaz
7
8
  module Cns
8
9
  # classe para processar bigquery
9
10
  class Bigquery
11
+ extend Memoist
10
12
  BD = 'hernanirvaz.coins'
11
13
  FO = File.expand_path("~/#{File.basename($PROGRAM_NAME)}.log")
12
14
  TB = {
@@ -35,16 +37,16 @@ module Cns
35
37
  TL = {
36
38
  ins: 'INSERT',
37
39
  exo: false,
38
- est: '', # ' limit 226',
39
- esi: '', # ' limit 22',
40
- esp: '', # ' limit 72',
41
- esw: '', # ' limit 2320',
42
- esk: '', # ' limit 20',
43
- gmt: '', # ' limit 1091',
44
- ust: '', # ' limit 182',
45
- usl: '', # ' limit 448',
46
- det: '', # ' limit 27',
47
- del: '' # ' limit 16'
40
+ est: '', # limit 228',
41
+ esi: '', # limit 22',
42
+ esp: '', # limit 72',
43
+ esw: '', # limit 2350',
44
+ esk: '', # limit 20',
45
+ gmt: '', # limit 1091',
46
+ ust: '', # limit 182',
47
+ usl: '', # limit 448',
48
+ det: '', # limit 27',
49
+ del: '' # limit 16'
48
50
  }.freeze
49
51
 
50
52
  # @return [Google::Cloud::Bigquery] API bigquery
@@ -67,16 +69,12 @@ module Cns
67
69
 
68
70
  # mostra situacao completa entre kraken/bitcoinde/paymium/therock/etherscan/greymass & bigquery
69
71
  def mtudo
70
- apius.mresumo
71
- apide.mresumo
72
- apies.mresumo
73
- apigm.mresumo
72
+ [apius, apide, apies, apigm].each(&:mresumo)
74
73
  end
75
74
 
76
75
  # mostra situacao completa entre kraken/etherscan & bigquery
77
76
  def mskrk
78
- apius.mresumo
79
- apies.mresumo
77
+ [apius, apies].each(&:mresumo)
80
78
  end
81
79
 
82
80
  # mostra situacao completa entre etherscan & bigquery
@@ -91,34 +89,30 @@ module Cns
91
89
 
92
90
  # insere dados novos kraken/bitcoinde/etherscan/greymass no bigquery
93
91
  def ptudo
94
- puts("#{tct} #{pus}, #{pde}, #{peth}, #{peos}")
92
+ puts("#{tct} #{pus}, #{pde}, #{peth(apies)}, #{peos}")
95
93
  end
96
94
 
97
95
  # insere dados novos kraken/etherscan no bigquery
98
96
  def pwkrk
99
- puts("#{tct} #{pus}, #{peth}")
97
+ puts("#{tct} #{pus}, #{peth(apies)}")
100
98
  end
101
99
 
102
100
  # insere dados novos etherscan no bigquery
103
101
  def pweth
104
- puts("#{tct} #{peth}")
102
+ puts("#{tct} #{peth(apies)}")
105
103
  end
106
104
 
107
105
  # insere dados novos etherscan no bigquery (output to file)
108
106
  def pceth
109
- File.open(FO, mode: 'a') { |o| o.puts("#{tct} #{pethc}") }
107
+ File.open(FO, mode: 'a') { |o| o.puts("#{tct} #{peth(apiec)}") }
110
108
  end
111
109
 
112
110
  private
113
111
 
112
+ # @param [Etherscan] API blockchain ETH
114
113
  # @return [String] linhas & tabelas afetadas
115
- def peth
116
- dmo(apies, %w[ETH], %i[netht nethi nethp nethw nethk])
117
- end
118
-
119
- # @return [String] linhas & tabelas afetadas
120
- def pethc
121
- dmo(apiesc, %w[ETH], %i[netht nethi nethp nethw nethk])
114
+ def peth(api)
115
+ dmo(api, %w[ETH], %i[netht nethi nethp nethw nethk])
122
116
  end
123
117
 
124
118
  # @return [String] linhas & tabelas afetadas
@@ -137,7 +131,7 @@ module Cns
137
131
  end
138
132
 
139
133
  # @return [Etherscan] API blockchain ETH
140
- def apiesg(prx)
134
+ def apieg(prx)
141
135
  Etherscan.new(
142
136
  {
143
137
  wb: sql("SELECT * FROM #{BD}.wet#{prx[-1]} ORDER BY ax"),
@@ -152,28 +146,28 @@ module Cns
152
146
  end
153
147
 
154
148
  # @return [Etherscan] API blockchain ETH
155
- def apies
156
- @apies ||= apiesg('netb')
149
+ memoize def apies
150
+ apieg('netb')
157
151
  end
158
152
 
159
153
  # @return [Etherscan] API blockchain ETH (cron)
160
- def apiesc
161
- @apiesc ||= apiesg('netc')
154
+ memoize def apiec
155
+ apieg('netc')
162
156
  end
163
157
 
164
158
  # @return [Greymass] API blockchain EOS
165
- def apigm
166
- @apigm ||= Greymass.new({wb: sql("select * from #{BD}.weos ORDER BY ax"), nt: sql("select * from #{BD}.neosx#{TL[:gmt]}")}, ops)
159
+ memoize def apigm
160
+ Greymass.new({wb: sql("SELECT * FROM #{BD}.weos ORDER BY ax"), nt: sql("SELECT * FROM #{BD}.neosx#{TL[:gmt]}")}, ops)
167
161
  end
168
162
 
169
163
  # @return [Kraken] API exchange kraken
170
- def apius
171
- @apius ||= Kraken.new({sl: sql("select * from #{BD}.cuss").first, nt: sql("select * from #{BD}.cust#{TL[:ust]}"), nl: sql("select * from #{BD}.cusl#{TL[:usl]}")}, ops)
164
+ memoize def apius
165
+ Kraken.new({sl: sql("SELECT * FROM #{BD}.cuss").first, nt: sql("SELECT * FROM #{BD}.cust#{TL[:ust]}"), nl: sql("SELECT * FROM #{BD}.cusl#{TL[:usl]}")}, ops)
172
166
  end
173
167
 
174
168
  # @return [Bitcoinde] API exchange bitcoinde
175
- def apide
176
- @apide ||= Bitcoinde.new({sl: sql("select * from #{BD}.cdes").first, nt: sql("select * from #{BD}.cdet#{TL[:det]}"), nl: sql("select * from #{BD}.cdel#{TL[:del]}")}, ops)
169
+ memoize def apide
170
+ Bitcoinde.new({sl: sql("SELECT * FROM #{BD}.cdes").first, nt: sql("SELECT * FROM #{BD}.cdet#{TL[:det]}"), nl: sql("SELECT * FROM #{BD}.cdel#{TL[:del]}")}, ops)
177
171
  end
178
172
 
179
173
  # cria job bigquery & verifica execucao
@@ -211,7 +205,7 @@ module Cns
211
205
  def dmo(api, ini, ltb)
212
206
  ini.concat(
213
207
  ltb.filter_map do |i|
214
- n = api.send("nov#{i}")
208
+ n = api.send("novx#{i[-1]}")
215
209
  next if n.empty?
216
210
 
217
211
  format(' %<n>i %<t>s', n: dml(ins_sql(i, n)), t: "#{i}")
data/lib/cns/bitcoinde.rb CHANGED
@@ -1,15 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require('bigdecimal/util')
4
+ require('memoist')
4
5
 
5
6
  # @author Hernani Rodrigues Vaz
6
7
  module Cns
7
8
  # classe para processar transacoes trades/ledger do bitcoinde
8
9
  class Bitcoinde
9
- # @return [Apius] API bitcoinde
10
+ extend Memoist
10
11
  # @return [Array<Hash>] todos os dados bigquery
11
12
  # @return [Thor::CoreExt::HashWithIndifferentAccess] opcoes trabalho
12
- attr_reader :api, :bqd, :ops
13
+ attr_reader :bqd, :ops
13
14
 
14
15
  # @param [Hash] dad todos os dados bigquery
15
16
  # @param [Thor::CoreExt::HashWithIndifferentAccess] pop opcoes trabalho
@@ -24,24 +25,22 @@ module Cns
24
25
  # @return [String] texto saldos & transacoes & ajuste dias
25
26
  def mresumo
26
27
  puts("\nBITCOINDE\ntipo bitcoinde bigquery")
27
- ded[:sl].sort.each { |k, v| puts(fos(k, v)) }
28
+ ced[:sl].sort.each { |k, v| puts(fos(k, v)) }
28
29
  mtotais
29
30
 
30
31
  mtrades
31
32
  mledger
32
- return if novcdet.empty?
33
+ return if novxt.empty?
33
34
 
34
- puts("\nstring ajuste dias dos trades\n-h=#{novcdet.sort_by { |i| -i[:srx] }.map { |o| "#{o[:trade_id]}:0" }.join(' ')}")
35
+ puts("\nstring ajuste dias dos trades\n-h=#{novxt.sort_by { |i| -i[:srx] }.map { |o| "#{o[:trade_id]}:0" }.join(' ')}")
35
36
  end
36
37
 
37
38
  private
38
39
 
39
40
  # mosta contadores transacoes
40
41
  def mtotais
41
- vtt = ded[:tt].count
42
- vnt = bqd[:nt].count
43
- vtl = ded[:tl].count
44
- vnl = bqd[:nl].count
42
+ vtt, vnt = ced[:tt].count, bqd[:nt].count
43
+ vtl, vnl = ced[:tl].count, bqd[:nl].count
45
44
 
46
45
  puts("TRADES #{format('%<a>20i %<b>21i %<o>3.3s', a: vtt, b: vnt, o: vtt == vnt ? 'OK' : 'NOK')}")
47
46
  puts("LEDGER #{format('%<c>20i %<d>21i %<o>3.3s', c: vtl, d: vnl, o: vtl == vnl ? 'OK' : 'NOK')}")
@@ -49,18 +48,18 @@ module Cns
49
48
 
50
49
  # mosta transacoes trades
51
50
  def mtrades
52
- return unless ops[:v] && novcdet.any?
51
+ return unless ops[:v] && novxt.any?
53
52
 
54
53
  puts("\ntrades data hora dt criacao tipo par btc eur")
55
- novcdet.sort_by { |i| -i[:srx] }.each { |o| puts(fot(o)) }
54
+ novxt.sort_by { |i| -i[:srx] }.each { |o| puts(fot(o)) }
56
55
  end
57
56
 
58
57
  # mosta transacoes ledger
59
58
  def mledger
60
- return unless ops[:v] && novcdel.any?
59
+ return unless ops[:v] && novxl.any?
61
60
 
62
61
  puts("\nledger data hora tipo moe quantidade custo")
63
- novcdel.sort_by { |i| -i[:srx] }.each { |o| puts(fol(o)) }
62
+ novxl.sort_by { |i| -i[:srx] }.each { |o| puts(fol(o)) }
64
63
  end
65
64
 
66
65
  # @param [String] moe codigo bitcoinde da moeda
@@ -153,43 +152,43 @@ module Cns
153
152
 
154
153
  # Lazy Bitcoinde API Initialization
155
154
  # @return [Bitcoinde] API - obter saldos & transacoes trades e ledger
156
- def api
157
- @api ||= Apice.new
155
+ memoize def api
156
+ Apice.new
158
157
  end
159
158
 
160
159
  # @return [Hash] dados exchange bitcoinde - saldos & trades & deposits & withdrawals
161
- def ded
162
- @ded ||= {sl: pdea(api.account_de), tt: pdet(api.trades_de), tl: pdel(api.deposits_de + api.withdrawals_de)}
160
+ memoize def ced
161
+ {sl: pdea(api.account_de), tt: pdet(api.trades_de), tl: pdel(api.deposits_de + api.withdrawals_de)}
163
162
  end
164
163
 
165
164
  # @return [Array<String>] indices trades bigquery
166
- def bqkyt
167
- @bqkyt ||= show_all? ? [] : bqd[:nt].map { |t| t[:txid] }
165
+ memoize def bqkyt
166
+ show_all? ? [] : bqd[:nt].map { |t| t[:txid] }
168
167
  end
169
168
 
170
169
  # @return [Array<Integer>] indices ledger bigquery
171
- def bqkyl
172
- @bqkyl ||= show_all? ? [] : bqd[:nl].map { |l| l[:txid] }
170
+ memoize def bqkyl
171
+ show_all? ? [] : bqd[:nl].map { |l| l[:txid] }
173
172
  end
174
173
 
175
174
  # @return [Array<String>] lista txid trades novos
176
- def kyt
177
- @kyt ||= ded[:tt].map { |t| t[:trade_id] } - bqkyt
175
+ memoize def cekyt
176
+ ced[:tt].map { |t| t[:trade_id] } - bqkyt
178
177
  end
179
178
 
180
179
  # @return [Array<Integer>] lista nxid ledger novos
181
- def kyl
182
- @kyl ||= ded[:tl].map { |t| t[:nxid] } - bqkyl
180
+ memoize def cekyl
181
+ ced[:tl].map { |t| t[:nxid] } - bqkyl
183
182
  end
184
183
 
185
184
  # @return [Array<Hash>] lista trades novos bitcoinde
186
- def novcdet
187
- @novcdet ||= ded[:tt].select { |o| kyt.include?(o[:trade_id]) }
185
+ memoize def novxt
186
+ ced[:tt].select { |o| cekyt.include?(o[:trade_id]) }
188
187
  end
189
188
 
190
189
  # @return [Array<Hash>] lista ledgers (deposits + withdrawals) novos bitcoinde
191
- def novcdel
192
- @novcdel ||= ded[:tl].select { |o| kyl.include?(o[:nxid]) }
190
+ memoize def novxl
191
+ ced[:tl].select { |o| cekyl.include?(o[:nxid]) }
193
192
  end
194
193
  end
195
194
  end
data/lib/cns/etherscan.rb CHANGED
@@ -1,47 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require('bigdecimal/util')
4
+ require('memoist')
4
5
 
5
6
  # @author Hernani Rodrigues Vaz
6
7
  module Cns
7
8
  # classe para processar transacoes do etherscan
8
9
  class Etherscan
9
- # @return [Apibc] API blockchains
10
+ extend Memoist
10
11
  # @return [Array<Hash>] todos os dados bigquery
11
12
  # @return [Thor::CoreExt::HashWithIndifferentAccess] opcoes trabalho
12
- attr_reader :api, :bqd, :ops
13
+ attr_reader :bqd, :ops
13
14
 
14
15
  TT = {
15
16
  normal: {
16
- new: :novnetht,
17
+ new: :novxt,
17
18
  format: :foti,
18
19
  header: "\ntx normal from to data valor",
19
20
  sork: :srx,
20
21
  adjk: :hash
21
22
  }.freeze,
22
23
  internal: {
23
- new: :novnethi,
24
+ new: :novxi,
24
25
  format: :foti,
25
26
  header: "\ntx intern from to data valor",
26
27
  sork: :srx,
27
28
  adjk: :hash
28
29
  }.freeze,
29
30
  block: {
30
- new: :novnethp,
31
+ new: :novxp,
31
32
  format: :fop,
32
33
  header: "\ntx block address data valor",
33
34
  sork: :itx,
34
35
  adjk: :blockNumber
35
36
  }.freeze,
36
37
  token: {
37
- new: :novnethk,
38
+ new: :novxk,
38
39
  format: :fok,
39
40
  header: "\ntx token from to data valor moeda",
40
41
  sork: :srx,
41
42
  adjk: :hash
42
43
  }.freeze,
43
44
  withdrawal: {
44
- new: :novnethw,
45
+ new: :novxw,
45
46
  format: :fow,
46
47
  header: "\nwithdrawal validator data valor",
47
48
  sork: :itx,
@@ -82,9 +83,8 @@ module Cns
82
83
 
83
84
  # mosta transacoes novas
84
85
  def mtransacoes_novas
85
- TT.each do |_, c|
86
- ntx = send(c[:new])
87
- next unless ops[:v] && ntx.any?
86
+ TT.each_value do |c|
87
+ next unless ops[:v] && (ntx = send(c[:new])).any?
88
88
 
89
89
  puts(c[:header])
90
90
  ntx.sort_by { |s| -s[c[:sork]] }.each { |t| puts(send(c[:format], t)) }
@@ -323,107 +323,107 @@ module Cns
323
323
  }
324
324
  end
325
325
 
326
+ # Fetch all Etherscan data
327
+ # @return [Hash] saldos & transacoes, indexed by address
328
+ memoize def bcd
329
+ api.account_es(lax).map { |o| bses(o) }.to_h { |h| [h[:ax], h] }
330
+ end
331
+
326
332
  # Lazy Etherscan API Initialization
327
333
  # @return [Apibc] API instance
328
- def api
329
- @api ||= Apibc.new
334
+ memoize def api
335
+ Apibc.new
330
336
  end
331
337
 
332
338
  # @return [Array<String>] lista enderecos
333
- def lax
334
- @lax ||= bqd[:wb].map { |o| o[:ax] }
335
- end
336
-
337
- # Fetch all Etherscan data
338
- # @return [Hash] saldos & transacoes, indexed by address
339
- def esd
340
- @esd ||= api.account_es(lax).map { |o| bses(o) }.each_with_object({}) { |h, a| a[h[:ax]] = h }
339
+ memoize def lax
340
+ bqd[:wb].map { |o| o[:ax] }
341
341
  end
342
342
 
343
343
  # Fetch combined data
344
344
  # @return [Array<Hash>] todos os dados juntos bigquery & etherscan
345
- def dados
346
- @dados ||= bqd[:wb].map { |b| bqes(b, esd[b[:ax]]) }
345
+ memoize def dados
346
+ bqd[:wb].map { |b| bqes(b, bcd[b[:ax]]) }
347
347
  end
348
348
 
349
349
  # @return [Array<Integer>] indices transacoes bigquery
350
- def bqidt
351
- @bqidt ||= show_all? ? [] : bqd[:nt].map { |i| i[:itx] }
350
+ memoize def bqidt
351
+ show_all? ? [] : bqd[:nt].map { |i| i[:itx] }
352
352
  end
353
353
 
354
354
  # @return [Array<Integer>] indices transacoes bigquery
355
- def bqidi
356
- @bqidi ||= show_all? ? [] : bqd[:ni].map { |i| i[:itx] }
355
+ memoize def bqidi
356
+ show_all? ? [] : bqd[:ni].map { |i| i[:itx] }
357
357
  end
358
358
 
359
359
  # @return [Array<Integer>] indices transacoes bigquery
360
- def bqidp
361
- @bqidp ||= show_all? ? [] : bqd[:np].map { |i| i[:itx] }
360
+ memoize def bqidp
361
+ show_all? ? [] : bqd[:np].map { |i| i[:itx] }
362
362
  end
363
363
 
364
364
  # @return [Array<Integer>] indices transacoes bigquery
365
- def bqidw
366
- @bqidw ||= show_all? ? [] : bqd[:nw].map { |i| i[:itx] }
365
+ memoize def bqidw
366
+ show_all? ? [] : bqd[:nw].map { |i| i[:itx] }
367
367
  end
368
368
 
369
369
  # @return [Array<Integer>] indices transacoes bigquery
370
- def bqidk
371
- @bqidk ||= show_all? ? [] : bqd[:nk].map { |i| i[:itx] }
370
+ memoize def bqidk
371
+ show_all? ? [] : bqd[:nk].map { |i| i[:itx] }
372
372
  end
373
373
 
374
374
  # @return [Array<Integer>] indices transacoes novas (etherscan - bigquery)
375
- def idt
376
- @idt ||= esd.values.map { |o| o[:tx].map { |i| i[:itx] } }.flatten - bqidt
375
+ memoize def bcidt
376
+ bcd.values.map { |o| o[:tx].map { |i| i[:itx] } }.flatten - bqidt
377
377
  end
378
378
 
379
379
  # @return [Array<Integer>] indices transacoes novas (etherscan - bigquery)
380
- def idi
381
- @idi ||= esd.values.map { |o| o[:ix].map { |i| i[:itx] } }.flatten - bqidi
380
+ memoize def bcidi
381
+ bcd.values.map { |o| o[:ix].map { |i| i[:itx] } }.flatten - bqidi
382
382
  end
383
383
 
384
384
  # @return [Array<Integer>] indices transacoes novas (etherscan - bigquery)
385
- def idp
386
- @idp ||= esd.values.map { |o| o[:px].map { |i| i[:itx] } }.flatten - bqidp
385
+ memoize def bcidp
386
+ bcd.values.map { |o| o[:px].map { |i| i[:itx] } }.flatten - bqidp
387
387
  end
388
388
 
389
389
  # @return [Array<Integer>] indices transacoes novas (etherscan - bigquery)
390
- def idw
391
- @idw ||= esd.values.map { |o| o[:wx].map { |i| i[:itx] } }.flatten - bqidw
390
+ memoize def bcidw
391
+ bcd.values.map { |o| o[:wx].map { |i| i[:itx] } }.flatten - bqidw
392
392
  end
393
393
 
394
394
  # @return [Array<Integer>] indices transacoes novas (etherscan - bigquery)
395
- def idk
396
- @idk ||= esd.values.map { |o| o[:kx].map { |i| i[:itx] } }.flatten - bqidk
395
+ memoize def bcidk
396
+ bcd.values.map { |o| o[:kx].map { |i| i[:itx] } }.flatten - bqidk
397
397
  end
398
398
 
399
399
  # Get new normal transactions
400
400
  # @return [Array<Hash>] List of new transactions
401
- def novnetht
402
- @novnetht ||= esd.values.map { |o| o[:tx].select { |t| idt.include?(t[:itx]) } }.flatten.uniq { |i| i[:itx] }
401
+ memoize def novxt
402
+ bcd.values.map { |o| o[:tx].select { |t| bcidt.include?(t[:itx]) } }.flatten.uniq { |i| i[:itx] }
403
403
  end
404
404
 
405
405
  # Get new internal transactions
406
406
  # @return [Array<Hash>] List of new transactions
407
- def novnethi
408
- @novnethi ||= esd.values.map { |o| o[:ix].select { |t| idi.include?(t[:itx]) } }.flatten.uniq { |i| i[:itx] }
407
+ memoize def novxi
408
+ bcd.values.map { |o| o[:ix].select { |t| bcidi.include?(t[:itx]) } }.flatten.uniq { |i| i[:itx] }
409
409
  end
410
410
 
411
411
  # Get new produced block transactions
412
412
  # @return [Array<Hash>] List of new transactions
413
- def novnethp
414
- @novnethp ||= esd.values.map { |o| o[:px].select { |t| idp.include?(t[:itx]) } }.flatten.uniq { |i| i[:itx] }
413
+ memoize def novxp
414
+ bcd.values.map { |o| o[:px].select { |t| bcidp.include?(t[:itx]) } }.flatten.uniq { |i| i[:itx] }
415
415
  end
416
416
 
417
417
  # Get new withdrawal transactions
418
418
  # @return [Array<Hash>] List of new transactions
419
- def novnethw
420
- @novnethw ||= esd.values.map { |o| o[:wx].select { |t| idw.include?(t[:itx]) } }.flatten.uniq { |i| i[:itx] }
419
+ memoize def novxw
420
+ bcd.values.map { |o| o[:wx].select { |t| bcidw.include?(t[:itx]) } }.flatten.uniq { |i| i[:itx] }
421
421
  end
422
422
 
423
423
  # Get new token transactions
424
424
  # @return [Array<Hash>] List of new transactions
425
- def novnethk
426
- @novnethk ||= esd.values.map { |o| o[:kx].select { |t| idk.include?(t[:itx]) } }.flatten.uniq { |i| i[:itx] }
425
+ memoize def novxk
426
+ bcd.values.map { |o| o[:kx].select { |t| bcidk.include?(t[:itx]) } }.flatten.uniq { |i| i[:itx] }
427
427
  end
428
428
  end
429
429
  end
data/lib/cns/greymass.rb CHANGED
@@ -1,15 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require('bigdecimal/util')
4
+ require('memoist')
4
5
 
5
6
  # @author Hernani Rodrigues Vaz
6
7
  module Cns
7
8
  # classe para processar transacoes do greymass
8
9
  class Greymass
9
- # @return [Apibc] API blockchains
10
+ extend Memoist
10
11
  # @return [Array<Hash>] todos os dados bigquery
11
12
  # @return [Thor::CoreExt::HashWithIndifferentAccess] opcoes trabalho
12
- attr_reader :api, :bqd, :ops
13
+ attr_reader :bqd, :ops
13
14
 
14
15
  TT = {sork: :itx, adjk: :itx}.freeze
15
16
 
@@ -37,17 +38,17 @@ module Cns
37
38
 
38
39
  # mosta transacoes novas
39
40
  def mtransacoes_novas
40
- return unless ops[:v] && novneost.any?
41
+ return unless ops[:v] && novxt.any?
41
42
 
42
43
  puts("\nsequence num from to accao data valor moeda")
43
- novneost.sort_by { |s| -s[TT[:sork]] }.each { |t| puts(fol(t)) }
44
+ novxt.sort_by { |s| -s[TT[:sork]] }.each { |t| puts(fol(t)) }
44
45
  end
45
46
 
46
47
  # mostra configuration text for adjusting days
47
48
  def mconfiguracao_ajuste_dias
48
- return unless novneost.any?
49
+ return unless novxt.any?
49
50
 
50
- puts("\nstring ajuste dias\n-h=#{novneost.sort_by { |s| -s[TT[:sork]] }.map { |t| "#{t[TT[:adjk]]}:0" }.join(' ')}")
51
+ puts("\nstring ajuste dias\n-h=#{novxt.sort_by { |s| -s[TT[:sork]] }.map { |t| "#{t[TT[:adjk]]}:0" }.join(' ')}")
51
52
  end
52
53
 
53
54
  # Format wallet summary text
@@ -153,36 +154,36 @@ module Cns
153
154
 
154
155
  # Lazy Greymass API Initialization
155
156
  # @return [Apibc] API instance
156
- def api
157
- @api ||= Apibc.new
157
+ memoize def api
158
+ Apibc.new
158
159
  end
159
160
 
160
161
  # Fetch all Greymass data
161
162
  # @return [Hash] Hash of Greymass data indexed by address
162
- def gmd
163
- @gmd ||= bqd[:wb].map { |o| bsgm(o) }.each_with_object({}) { |h, a| a[h[:ax]] = h }
163
+ memoize def bcd
164
+ bqd[:wb].map { |o| bsgm(o) }.to_h { |h| [h[:ax], h] }
164
165
  end
165
166
 
166
167
  # Fetch combined BigQuery and Greymass data
167
168
  # @return [Array<Hash>] Combined data list
168
- def dados
169
- @dados ||= bqd[:wb].map { |b| bqgm(b, gmd[b[:ax]]) }
169
+ memoize def dados
170
+ bqd[:wb].map { |b| bqgm(b, bcd[b[:ax]]) }
170
171
  end
171
172
 
172
173
  # @return [Array<Integer>] indices transacoes bigquery
173
- def bqidt
174
- @bqidt ||= show_all? ? [] : bqd[:nt].map { |i| i[:itx] }
174
+ memoize def bqidt
175
+ show_all? ? [] : bqd[:nt].map { |i| i[:itx] }
175
176
  end
176
177
 
177
178
  # @return [Array<Integer>] indices transacoes novas (greymass - bigquery)
178
- def idt
179
- @idt ||= gmd.values.map { |o| o[:tx].map { |i| i[:itx] } }.flatten - bqidt
179
+ memoize def bcidt
180
+ bcd.values.map { |o| o[:tx].map { |i| i[:itx] } }.flatten - bqidt
180
181
  end
181
182
 
182
183
  # Get new transactions
183
184
  # @return [Array<Hash>] List of new transactions
184
- def novneost
185
- @novneost ||= gmd.values.map { |t| t[:tx].select { |o| idt.include?(o[:itx]) } }.flatten.uniq { |i| i[:itx] }
185
+ memoize def novxt
186
+ bcd.values.map { |t| t[:tx].select { |o| bcidt.include?(o[:itx]) } }.flatten.uniq { |i| i[:itx] }
186
187
  end
187
188
  end
188
189
  end
data/lib/cns/kraken.rb CHANGED
@@ -1,15 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require('bigdecimal/util')
4
+ require('memoist')
4
5
 
5
6
  # @author Hernani Rodrigues Vaz
6
7
  module Cns
7
8
  # classe para processar transacoes trades/ledger do kraken
8
9
  class Kraken
9
- # @return [Apius] API kraken
10
+ extend Memoist
10
11
  # @return [Array<Hash>] todos os dados bigquery
11
12
  # @return [Thor::CoreExt::HashWithIndifferentAccess] opcoes trabalho
12
- attr_reader :api, :bqd, :ops
13
+ attr_reader :bqd, :ops
13
14
 
14
15
  # @param [Hash] dad todos os dados bigquery
15
16
  # @param [Thor::CoreExt::HashWithIndifferentAccess] pop opcoes trabalho
@@ -24,29 +25,27 @@ module Cns
24
25
  # mosta resumo saldos & transacoes & ajuste dias
25
26
  def mresumo
26
27
  puts("\nKRAKEN\ntipo kraken bigquery")
27
- usd[:sl].sort.each { |key, val| puts(fos(key, val)) }
28
+ ced[:sl].sort.each { |key, val| puts(fos(key, val)) }
28
29
  mtotais
29
30
 
30
31
  mtrades
31
32
  mledger
32
- return if novcust.empty?
33
+ return if novxt.empty?
33
34
 
34
- puts("\nstring ajuste dias dos trades\n-h=#{novcust.sort_by { |i| -i[:srx] }.map { |o| "#{o[:txid]}:0" }.join(' ')}")
35
+ puts("\nstring ajuste dias dos trades\n-h=#{novxt.sort_by { |i| -i[:srx] }.map { |o| "#{o[:txid]}:0" }.join(' ')}")
35
36
  end
36
37
 
37
38
  # @return [Hash] ledgers exchange kraken
38
39
  def uskl
39
- usd[:kl]
40
+ ced[:kl]
40
41
  end
41
42
 
42
43
  private
43
44
 
44
45
  # mosta contadores transacoes
45
46
  def mtotais
46
- vkt = usd[:kt].count
47
- vnt = bqd[:nt].count
48
- vkl = usd[:kl].count
49
- vnl = bqd[:nl].count
47
+ vkt, vnt = ced[:kt].count, bqd[:nt].count
48
+ vkl, vnl = ced[:kl].count, bqd[:nl].count
50
49
 
51
50
  puts("TRADES #{format('%<a>20i %<b>21i %<o>3.3s', a: vkt, b: vnt, o: vkt == vnt ? 'OK' : 'NOK')}")
52
51
  puts("LEDGER #{format('%<c>20i %<d>21i %<o>3.3s', c: vkl, d: vnl, o: vkl == vnl ? 'OK' : 'NOK')}")
@@ -54,18 +53,18 @@ module Cns
54
53
 
55
54
  # mosta transacoes trades
56
55
  def mtrades
57
- return unless ops[:v] && novcust.any?
56
+ return unless ops[:v] && novxt.any?
58
57
 
59
58
  puts("\ntrade data hora tipo par preco volume custo")
60
- novcust.sort_by { |i| -i[:srx] }.each { |o| puts(fot(o)) }
59
+ novxt.sort_by { |i| -i[:srx] }.each { |o| puts(fot(o)) }
61
60
  end
62
61
 
63
62
  # mosta transacoes ledger
64
63
  def mledger
65
- return unless ops[:v] && novcusl.any?
64
+ return unless ops[:v] && novxl.any?
66
65
 
67
66
  puts("\nledger data hora tipo moeda quantidade custo")
68
- novcusl.sort_by { |i| -i[:srx] }.each { |o| puts(fol(o)) }
67
+ novxl.sort_by { |i| -i[:srx] }.each { |o| puts(fol(o)) }
69
68
  end
70
69
 
71
70
  # @param [String] moe codigo kraken da moeda
@@ -136,53 +135,50 @@ module Cns
136
135
 
137
136
  # Lazy kraken API Initialization decorated with rate limiting logic
138
137
  # @return [Kraken] API - obter saldos & transacoes trades e ledger
139
- def api
140
- @api ||=
141
- begin
142
- t = Apice.new
143
- # Rate limiting to this specific instance (0.5s in Kraken)
144
- t.define_singleton_method(:run_curl) do |curl, url, **options|
145
- sleep(@lapi - Time.now + 0.5) if @lapi && Time.now - @lapi < 0.5
146
- super(curl, url, **options)
147
- @lapi = Time.now
148
- end
149
- t
138
+ memoize def api
139
+ Apice.new.tap do |t|
140
+ # Rate limiting to this specific instance (0.5s in Kraken)
141
+ t.define_singleton_method(:rcrl) do |c, u, **o|
142
+ sleep(@lapi - Time.now + 0.5) if @lapi && Time.now - @lapi < 0.5
143
+ super(c, u, **o)
144
+ @lapi = Time.now
150
145
  end
146
+ end
151
147
  end
152
148
 
153
149
  # @return [Hash] dados exchange kraken - saldos & transacoes trades e ledger
154
- def usd
155
- @usd ||= {sl: pusa(api.account_us), kt: pust(api.trades_us), kl: pusl(api.ledger_us)}
150
+ memoize def ced
151
+ {sl: pusa(api.account_us), kt: pust(api.trades_us), kl: pusl(api.ledger_us)}
156
152
  end
157
153
 
158
154
  # @return [Array<String>] indices trades bigquery
159
- def bqkyt
160
- @bqkyt ||= show_all? ? [] : bqd[:nt].map { |t| t[:txid] }
155
+ memoize def bqkyt
156
+ show_all? ? [] : bqd[:nt].map { |t| t[:txid] }
161
157
  end
162
158
 
163
- # @return [Array<String>] indices ledger bigquery
164
- def bqkyl
165
- @bqkyl ||= show_all? ? [] : bqd[:nl].map { |l| l[:txid] }
159
+ # @return [Array<Integer>] indices ledger bigquery
160
+ memoize def bqkyl
161
+ show_all? ? [] : bqd[:nl].map { |l| l[:txid] }
166
162
  end
167
163
 
168
164
  # @return [Array<String>] lista txid trades novos
169
- def kyt
170
- @kyt ||= usd[:kt].map { |t| t[:txid] } - bqkyt
165
+ memoize def cekyt
166
+ ced[:kt].map { |t| t[:txid] } - bqkyt
171
167
  end
172
168
 
173
169
  # @return [Array<String>] lista txid ledger novos
174
- def kyl
175
- @kyl ||= usd[:kl].map { |t| t[:txid] } - bqkyl
170
+ memoize def cekyl
171
+ ced[:kl].map { |t| t[:txid] } - bqkyl
176
172
  end
177
173
 
178
174
  # @return [Array<Hash>] trades novos kraken
179
- def novcust
180
- @novcust ||= usd[:kt].select { |o| kyt.include?(o[:txid]) }
175
+ memoize def novxt
176
+ ced[:kt].select { |o| cekyt.include?(o[:txid]) }
181
177
  end
182
178
 
183
179
  # @return [Array<Hash>] ledgers novos kraken
184
- def novcusl
185
- @novcusl ||= usd[:kl].select { |o| kyl.include?(o[:txid]) }
180
+ memoize def novxl
181
+ ced[:kl].select { |o| cekyl.include?(o[:txid]) }
186
182
  end
187
183
  end
188
184
  end
data/lib/cns/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cns
4
- VERSION = '2.0.2'
4
+ VERSION = '2.0.3'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cns
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hernâni Rodrigues Vaz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-03-18 00:00:00.000000000 Z
11
+ date: 2025-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: memoist
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
167
181
  - !ruby/object:Gem::Dependency
168
182
  name: thor
169
183
  requirement: !ruby/object:Gem::Requirement