lighstorm 0.0.2 → 0.0.4

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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +5 -0
  3. data/.gitignore +1 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +10 -0
  6. data/Gemfile +5 -1
  7. data/Gemfile.lock +32 -8
  8. data/README.md +30 -341
  9. data/adapters/connections/channel_node/fee.rb +26 -0
  10. data/adapters/connections/channel_node.rb +52 -0
  11. data/adapters/connections/payment_channel.rb +28 -0
  12. data/adapters/edges/channel.rb +80 -0
  13. data/adapters/edges/forward.rb +41 -0
  14. data/adapters/edges/payment/purpose.rb +34 -0
  15. data/adapters/edges/payment.rb +53 -0
  16. data/adapters/invoice.rb +50 -0
  17. data/adapters/nodes/node.rb +77 -0
  18. data/adapters/payment_request.rb +77 -0
  19. data/components/cache.rb +3 -2
  20. data/components/lnd.rb +5 -1
  21. data/controllers/channel/actions/update_fee.rb +76 -0
  22. data/controllers/channel/all.rb +79 -0
  23. data/controllers/channel/find_by_id.rb +153 -0
  24. data/controllers/channel/mine.rb +114 -0
  25. data/controllers/channel.rb +23 -0
  26. data/controllers/forward/all.rb +244 -0
  27. data/controllers/forward/group_by_channel.rb +89 -0
  28. data/controllers/forward.rb +28 -0
  29. data/controllers/invoice/actions/create.rb +36 -0
  30. data/controllers/invoice/actions/pay.rb +28 -0
  31. data/controllers/invoice/actions/pay_through_route.rb +71 -0
  32. data/controllers/invoice/all.rb +70 -0
  33. data/controllers/invoice/find_by_secret_hash.rb +42 -0
  34. data/controllers/invoice.rb +36 -0
  35. data/controllers/node/all.rb +63 -0
  36. data/controllers/node/find_by_public_key.rb +49 -0
  37. data/controllers/node/myself.rb +34 -0
  38. data/controllers/node.rb +23 -0
  39. data/controllers/payment/all.rb +352 -0
  40. data/controllers/payment.rb +21 -0
  41. data/docs/.nojekyll +0 -0
  42. data/docs/README.md +655 -0
  43. data/docs/_coverpage.md +12 -0
  44. data/docs/index.html +26 -0
  45. data/docs/vendor/docsify/docsify@4.js +1 -0
  46. data/docs/vendor/docsify-themeable/theme-simple-dark.css +3 -0
  47. data/docs/vendor/docsify-themeable/theme-simple-dark.css.map +1 -0
  48. data/docs/vendor/prismjs/prism-bash.min.js +1 -0
  49. data/docs/vendor/prismjs/prism-ruby.min.js +1 -0
  50. data/docs/vendor/prismjs/prism-tomorrow.min.css +1 -0
  51. data/lighstorm.gemspec +4 -2
  52. data/models/connections/channel_node/accounting.rb +3 -12
  53. data/models/connections/channel_node/fee.rb +44 -56
  54. data/models/connections/channel_node/htlc.rb +52 -0
  55. data/models/connections/channel_node/policy.rb +11 -12
  56. data/models/connections/channel_node.rb +20 -19
  57. data/models/connections/forward_channel.rb +8 -43
  58. data/models/connections/payment_channel.rb +18 -39
  59. data/models/edges/channel/accounting.rb +42 -18
  60. data/models/edges/channel/hop.rb +65 -0
  61. data/models/edges/channel.rb +98 -120
  62. data/models/edges/forward.rb +9 -118
  63. data/models/edges/groups/{analysis.rb → channel_forwards/analysis.rb} +9 -9
  64. data/models/edges/groups/channel_forwards.rb +10 -40
  65. data/models/edges/payment.rb +29 -214
  66. data/models/errors.rb +29 -0
  67. data/models/invoice.rb +49 -0
  68. data/models/nodes/node/lightning.rb +5 -16
  69. data/models/nodes/node/platform.rb +7 -13
  70. data/models/nodes/node.rb +19 -56
  71. data/models/payment_request.rb +69 -0
  72. data/models/rate.rb +11 -1
  73. data/models/satoshis.rb +5 -6
  74. data/ports/dsl/lighstorm/errors.rb +5 -0
  75. data/ports/dsl/lighstorm.rb +12 -8
  76. data/ports/grpc.rb +62 -0
  77. data/static/cache.rb +12 -0
  78. data/static/spec.rb +3 -1
  79. metadata +58 -8
  80. data/models/connections/channel_node/constraints.rb +0 -24
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+ require 'digest'
5
+
6
+ require_relative '../connections/channel_node'
7
+
8
+ module Lighstorm
9
+ module Adapter
10
+ class Channel
11
+ def self._key(id, active)
12
+ Digest::SHA256.hexdigest(
13
+ [id, active].join('/')
14
+ )
15
+ end
16
+
17
+ def self.list_channels(grpc, at)
18
+ {
19
+ _source: :list_channels,
20
+ _key: _key(grpc[:chan_id], grpc[:active]),
21
+ # Standard JSON don't support BigInt, so, a String is safer.
22
+ id: grpc[:chan_id].to_s,
23
+ transaction: {
24
+ funding: {
25
+ id: grpc[:channel_point].split(':').first,
26
+ index: grpc[:channel_point].split(':').last.to_i
27
+ }
28
+ },
29
+ opened_at: DateTime.parse((at - grpc[:lifetime]).to_s),
30
+ up_at: DateTime.parse((at - grpc[:uptime]).to_s),
31
+ active: grpc[:active],
32
+ exposure: grpc[:private] ? 'private' : 'public',
33
+ accounting: {
34
+ capacity: { milisatoshis: grpc[:capacity] * 1000 },
35
+ sent: { milisatoshis: grpc[:total_satoshis_sent] * 1000 },
36
+ received: { milisatoshis: grpc[:total_satoshis_received] * 1000 },
37
+ unsettled: { milisatoshis: grpc[:unsettled_balance] * 1000 }
38
+ },
39
+ partners: [
40
+ ChannelNode.list_channels(grpc, :local),
41
+ ChannelNode.list_channels(grpc, :remote)
42
+ ]
43
+ }
44
+ end
45
+
46
+ def self.get_chan_info(grpc)
47
+ {
48
+ _source: :get_chan_info,
49
+ _key: _key(grpc[:channel_id], nil),
50
+ # Standard JSON don't support BigInt, so, a String is safer.
51
+ id: grpc[:channel_id].to_s,
52
+ accounting: {
53
+ capacity: { milisatoshis: grpc[:capacity] * 1000 }
54
+ },
55
+ partners: [
56
+ ChannelNode.get_chan_info(grpc, 1),
57
+ ChannelNode.get_chan_info(grpc, 2)
58
+ ]
59
+ }
60
+ end
61
+
62
+ def self.describe_graph(grpc)
63
+ {
64
+ _source: :describe_graph,
65
+ _key: _key(grpc[:channel_id], nil),
66
+ # Standard JSON don't support BigInt, so, a String is safer.
67
+ id: grpc[:channel_id].to_s,
68
+ exposure: 'public',
69
+ accounting: {
70
+ capacity: { milisatoshis: grpc[:capacity] * 1000 }
71
+ },
72
+ partners: [
73
+ ChannelNode.describe_graph(grpc, 1),
74
+ ChannelNode.describe_graph(grpc, 2)
75
+ ]
76
+ }
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+ require 'digest'
5
+
6
+ module Lighstorm
7
+ module Adapter
8
+ class Forward
9
+ def self.forwarding_history(grpc)
10
+ {
11
+ _source: :forwarding_history,
12
+ _key: _key(grpc),
13
+ at: DateTime.parse(Time.at(grpc[:timestamp_ns] / 1e+9).to_s),
14
+ fee: { milisatoshis: grpc[:fee_msat] },
15
+ in: {
16
+ amount: { milisatoshis: grpc[:amt_in_msat] },
17
+ channel: {
18
+ id: grpc[:chan_id_in].to_s
19
+ }
20
+ },
21
+ out: {
22
+ amount: { milisatoshis: grpc[:amt_out_msat] },
23
+ channel: {
24
+ id: grpc[:chan_id_out].to_s
25
+ }
26
+ }
27
+ }
28
+ end
29
+
30
+ def self._key(grpc)
31
+ Digest::SHA256.hexdigest(
32
+ [
33
+ grpc[:timestamp_ns],
34
+ grpc[:chan_id_in], grpc[:chan_id_out],
35
+ grpc[:amt_in_msat], grpc[:fee_msat]
36
+ ].join('/')
37
+ )
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module Lighstorm
6
+ module Adapter
7
+ class Purpose
8
+ def self.list_payments(grpc, node_get_info)
9
+ return 'self-payment' if self_payment?(grpc)
10
+ return 'peer-to-peer' if peer_to_peer?(grpc)
11
+ return 'rebalance' if rebalance?(grpc, node_get_info)
12
+
13
+ 'payment'
14
+ end
15
+
16
+ def self.self_payment?(grpc)
17
+ grpc[:htlcs].first[:route][:hops].size == 2 &&
18
+ grpc[:htlcs].first[:route][:hops][0][:chan_id] == grpc[:htlcs].first[:route][:hops][1][:chan_id]
19
+ end
20
+
21
+ def self.peer_to_peer?(grpc)
22
+ grpc[:htlcs].first[:route][:hops].size == 1
23
+ end
24
+
25
+ def self.rebalance?(grpc, node_get_info)
26
+ return false if grpc[:htlcs].first[:route][:hops].size <= 2
27
+
28
+ destination_public_key = grpc[:htlcs].first[:route][:hops].last[:pub_key]
29
+
30
+ node_get_info[:identity_pubkey] == destination_public_key
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+ require 'date'
5
+
6
+ require_relative '../connections/payment_channel'
7
+ require_relative 'payment/purpose'
8
+
9
+ require_relative '../payment_request'
10
+
11
+ require_relative '../../ports/dsl/lighstorm/errors'
12
+
13
+ module Lighstorm
14
+ module Adapter
15
+ class Payment
16
+ def self._key(grpc)
17
+ Digest::SHA256.hexdigest(
18
+ [
19
+ grpc[:payment_request],
20
+ grpc[:creation_time_ns],
21
+ grpc[:resolve_time_ns],
22
+ grpc[:status]
23
+ ].join('/')
24
+ )
25
+ end
26
+
27
+ def self.list_payments(grpc, node_get_info)
28
+ raise UnexpectedNumberOfHTLCsError, "htlcs: #{grpc[:htlcs].size}" if grpc[:htlcs].size > 1
29
+
30
+ data = {
31
+ _source: :list_payments,
32
+ _key: _key(grpc),
33
+ created_at: DateTime.parse(Time.at(grpc[:creation_time_ns] / 1e+9).to_s),
34
+ status: grpc[:status].to_s.downcase,
35
+ fee: { milisatoshis: grpc[:fee_msat] },
36
+ purpose: Purpose.list_payments(grpc, node_get_info),
37
+ request: PaymentRequest.list_payments(grpc),
38
+ hops: grpc[:htlcs].first[:route][:hops].map.with_index do |raw_hop, i|
39
+ hop = PaymentChannel.list_payments(raw_hop, i)
40
+ hop[:channel][:target] = { public_key: raw_hop[:pub_key] }
41
+ hop
42
+ end
43
+ }
44
+
45
+ if grpc[:htlcs].first[:resolve_time_ns]
46
+ data[:settled_at] = DateTime.parse(Time.at(grpc[:htlcs].first[:resolve_time_ns] / 1e+9).to_s)
47
+ end
48
+
49
+ data
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+ require 'digest'
5
+
6
+ require_relative 'payment_request'
7
+
8
+ module Lighstorm
9
+ module Adapter
10
+ class Invoice
11
+ def self.lookup_invoice(grpc)
12
+ adapted = list_or_lookup(grpc)
13
+
14
+ adapted[:_source] = :lookup_invoice
15
+ adapted[:request] = PaymentRequest.lookup_invoice(grpc)
16
+
17
+ adapted
18
+ end
19
+
20
+ def self.list_invoices(grpc)
21
+ adapted = list_or_lookup(grpc)
22
+
23
+ adapted[:_source] = :list_invoices
24
+ adapted[:request] = PaymentRequest.list_invoices(grpc)
25
+
26
+ adapted
27
+ end
28
+
29
+ def self.list_or_lookup(grpc)
30
+ {
31
+ _key: _key(grpc),
32
+ created_at: DateTime.parse(Time.at(grpc[:creation_date]).to_s),
33
+ settle_at: DateTime.parse(Time.at(grpc[:settle_date]).to_s),
34
+ state: grpc[:state].to_s.downcase
35
+ }
36
+ end
37
+
38
+ def self._key(grpc)
39
+ Digest::SHA256.hexdigest(
40
+ [
41
+ grpc[:creation_date],
42
+ grpc[:settle_date],
43
+ grpc[:payment_request],
44
+ grpc[:state]
45
+ ].join('/')
46
+ )
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module Lighstorm
6
+ module Adapter
7
+ class Node
8
+ def self._key(public_key)
9
+ Digest::SHA256.hexdigest(
10
+ [public_key].join('/')
11
+ )
12
+ end
13
+
14
+ def self.get_chan_info(grpc, index)
15
+ {
16
+ _source: :get_chan_info,
17
+ _key: _key(grpc[:"node#{index}_pub"]),
18
+ public_key: grpc[:"node#{index}_pub"]
19
+ }
20
+ end
21
+
22
+ def self.list_channels(grpc, key)
23
+ {
24
+ _source: :list_channels,
25
+ _key: _key(key == :remote ? grpc[:remote_pubkey] : nil),
26
+ public_key: key == :remote ? grpc[:remote_pubkey] : nil
27
+ }
28
+ end
29
+
30
+ def self.get_info(grpc)
31
+ {
32
+ _source: :get_info,
33
+ _key: _key(grpc[:identity_pubkey]),
34
+ public_key: grpc[:identity_pubkey],
35
+ alias: grpc[:alias],
36
+ color: grpc[:color],
37
+ platform: {
38
+ blockchain: grpc[:chains][0][:chain],
39
+ network: grpc[:chains][0][:network],
40
+ lightning: {
41
+ implementation: 'lnd',
42
+ version: grpc[:version]
43
+ }
44
+ }
45
+ }
46
+ end
47
+
48
+ def self.get_node_info(grpc)
49
+ {
50
+ _source: :get_node_info,
51
+ _key: _key(grpc[:node][:pub_key]),
52
+ public_key: grpc[:node][:pub_key],
53
+ alias: grpc[:node][:alias],
54
+ color: grpc[:node][:color]
55
+ }
56
+ end
57
+
58
+ def self.describe_graph(grpc)
59
+ {
60
+ _source: :describe_graph,
61
+ _key: _key(grpc[:pub_key]),
62
+ public_key: grpc[:pub_key],
63
+ alias: grpc[:alias],
64
+ color: grpc[:color]
65
+ }
66
+ end
67
+
68
+ def self.describe_graph_from_channel(grpc, index)
69
+ {
70
+ _source: :describe_graph,
71
+ _key: _key(grpc[:"node#{index}_pub"]),
72
+ public_key: grpc[:"node#{index}_pub"]
73
+ }
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+ require 'digest'
5
+
6
+ require_relative '../ports/dsl/lighstorm/errors'
7
+
8
+ module Lighstorm
9
+ module Adapter
10
+ class PaymentRequest
11
+ def self.decode_pay_req(grpc)
12
+ {
13
+ _source: :decode_pay_req,
14
+ amount: { milisatoshis: grpc[:num_msat] },
15
+ description: {
16
+ memo: grpc[:description],
17
+ hash: grpc[:description_hash] == '' ? nil : grpc[:description_hash]
18
+ },
19
+ address: grpc[:payment_addr].unpack1('H*'),
20
+ secret: {
21
+ hash: grpc[:payment_hash]
22
+ }
23
+ }
24
+ end
25
+
26
+ def self.lookup_invoice(grpc)
27
+ adapted = list_or_lookup_invoice(grpc)
28
+ adapted[:_source] = :lookup_invoice
29
+ adapted
30
+ end
31
+
32
+ def self.list_invoices(grpc)
33
+ adapted = list_or_lookup_invoice(grpc)
34
+ adapted[:_source] = :list_invoices
35
+ adapted
36
+ end
37
+
38
+ def self.list_or_lookup_invoice(grpc)
39
+ {
40
+ code: grpc[:payment_request],
41
+ amount: { milisatoshis: grpc[:value_msat] },
42
+ description: {
43
+ memo: grpc[:memo],
44
+ hash: grpc[:description_hash] == '' ? nil : grpc[:description_hash]
45
+ },
46
+ address: grpc[:payment_addr].unpack1('H*'),
47
+ secret: {
48
+ preimage: grpc[:r_preimage].unpack1('H*'),
49
+ hash: grpc[:r_hash].unpack1('H*')
50
+ }
51
+ }
52
+ end
53
+
54
+ def self.list_payments(grpc)
55
+ raise UnexpectedNumberOfHTLCsError, "htlcs: #{grpc[:htlcs].size}" if grpc[:htlcs].size > 1
56
+
57
+ data = {
58
+ _source: :list_payments,
59
+ code: grpc[:payment_request],
60
+ amount: { milisatoshis: grpc[:value_msat] },
61
+ secret: {
62
+ preimage: grpc[:payment_preimage],
63
+ hash: grpc[:payment_hash]
64
+ }
65
+ }
66
+
67
+ grpc[:htlcs].first[:route][:hops].map do |raw_hop|
68
+ if raw_hop[:mpp_record] && raw_hop[:mpp_record][:payment_addr]
69
+ data[:address] = raw_hop[:mpp_record][:payment_addr].unpack1('H*')
70
+ end
71
+ end
72
+
73
+ data
74
+ end
75
+ end
76
+ end
77
+ end
data/components/cache.rb CHANGED
@@ -5,6 +5,7 @@ require 'singleton'
5
5
  require 'zache'
6
6
 
7
7
  require_relative '../static/cache'
8
+ require_relative '../ports/dsl/lighstorm/errors'
8
9
 
9
10
  module Lighstorm
10
11
  class Cache
@@ -23,7 +24,7 @@ module Lighstorm
23
24
  def for(key, ttl: nil, params: {}, &block)
24
25
  if ttl.nil?
25
26
  ttl = Lighstorm::Static::CACHE[key.sub('lightning.', '').to_sym]
26
- raise "missing ttl for #{key}" if ttl.nil?
27
+ raise MissingTTLError, "missing ttl for #{key} static/cache.rb" if ttl.nil?
27
28
 
28
29
  ttl = ttl[:ttl]
29
30
  end
@@ -36,7 +37,7 @@ module Lighstorm
36
37
  end
37
38
 
38
39
  def build_key_for(key, params)
39
- return key unless params.size.positive?
40
+ return key unless !params.nil? && params.size.positive?
40
41
 
41
42
  key_params = []
42
43
  params.keys.sort.each do |param_key|
data/components/lnd.rb CHANGED
@@ -4,6 +4,8 @@ require 'singleton'
4
4
 
5
5
  require 'lnd-client'
6
6
 
7
+ require_relative '../ports/dsl/lighstorm/errors'
8
+
7
9
  module Lighstorm
8
10
  class LND
9
11
  include Singleton
@@ -23,7 +25,9 @@ module Lighstorm
23
25
  def client
24
26
  return @client if @client
25
27
 
26
- raise 'missing credentials' if @config.nil? && ENV.fetch('LIGHSTORM_CERTIFICATE_PATH', nil).nil?
28
+ raise MissingCredentialsError, 'missing credentials' if @config.nil? && ENV.fetch(
29
+ 'LIGHSTORM_CERTIFICATE_PATH', nil
30
+ ).nil?
27
31
 
28
32
  @client = if @config
29
33
  create_client_from_config
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../ports/grpc'
4
+ require_relative '../../../models/errors'
5
+ require_relative '../../../models/satoshis'
6
+ require_relative '../../../models/rate'
7
+
8
+ module Lighstorm
9
+ module Controllers
10
+ module Channel
11
+ module UpdateFee
12
+ def self.perform(policy, params, preview: false, fake: false)
13
+ grpc_request = {
14
+ service: :lightning,
15
+ method: :update_channel_policy,
16
+ params: {
17
+ chan_point: {
18
+ funding_txid_str: policy.transaction.funding.id,
19
+ output_index: policy.transaction.funding.index
20
+ },
21
+ base_fee_msat: policy.fee.base.milisatoshis,
22
+ fee_rate_ppm: policy.fee.rate.parts_per_million,
23
+ time_lock_delta: policy.htlc.blocks.delta.minimum,
24
+ max_htlc_msat: policy.htlc.maximum.milisatoshis,
25
+ min_htlc_msat: policy.htlc.minimum.milisatoshis
26
+ }
27
+ }
28
+
29
+ if params[:rate] && params[:rate][:parts_per_million]
30
+ if (params[:rate][:parts_per_million]).negative?
31
+ raise Errors::NegativeNotAllowedError, "fee rate can't be negative: #{params[:rate][:parts_per_million]}"
32
+ end
33
+
34
+ grpc_request[:params][:fee_rate_ppm] = params[:rate][:parts_per_million]
35
+ end
36
+
37
+ if params[:base] && params[:base][:milisatoshis]
38
+ if (params[:base][:milisatoshis]).negative?
39
+ raise Errors::NegativeNotAllowedError, "fee base can't be negative: #{params[:base][:milisatoshis]}"
40
+ end
41
+
42
+ grpc_request[:params][:base_fee_msat] = params[:base][:milisatoshis]
43
+ end
44
+
45
+ return grpc_request if preview
46
+
47
+ response = if fake
48
+ :fake
49
+ else
50
+ LND.instance.middleware("lightning.#{grpc_request[:method]}") do
51
+ LND.instance.client.lightning.send(grpc_request[:method], grpc_request[:params])
52
+ end
53
+ end
54
+
55
+ raise UpdateChannelPolicyError.new(nil, response) unless fake || response.failed_updates.empty?
56
+
57
+ token = SecureRandom.hex
58
+ policy.fee.prepare_token!(token)
59
+ policy.fee.base = {
60
+ value: Models::Satoshis.new(milisatoshis: grpc_request[:params][:base_fee_msat]),
61
+ token: token
62
+ }
63
+
64
+ token = SecureRandom.hex
65
+ policy.fee.prepare_token!(token)
66
+ policy.fee.rate = {
67
+ value: Models::Rate.new(parts_per_million: grpc_request[:params][:fee_rate_ppm]),
68
+ token: token
69
+ }
70
+
71
+ response
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'mine'
4
+
5
+ require_relative '../../ports/grpc'
6
+ require_relative '../../adapters/edges/channel'
7
+ require_relative '../../adapters/nodes/node'
8
+ require_relative '../../adapters/connections/channel_node/fee'
9
+
10
+ module Lighstorm
11
+ module Controllers
12
+ module Channel
13
+ module All
14
+ def self.fetch(limit: nil)
15
+ data = {
16
+ at: Time.now,
17
+ mine: Mine.fetch,
18
+ describe_graph: Ports::GRPC.lightning.describe_graph.edges
19
+ }
20
+
21
+ data[:describe_graph] = data[:describe_graph][0..limit - 1] unless limit.nil?
22
+
23
+ data
24
+ end
25
+
26
+ def self.adapt(raw)
27
+ mine_adapted = Mine.adapt(raw[:mine])
28
+
29
+ mine = mine_adapted[:list_channels].map do |data|
30
+ Mine.transform(data, mine_adapted)
31
+ end
32
+
33
+ adapted = {
34
+ mine: {},
35
+ describe_graph: raw[:describe_graph].map do |raw_channel|
36
+ Lighstorm::Adapter::Channel.describe_graph(raw_channel.to_h)
37
+ end
38
+ }
39
+
40
+ mine.each do |channel|
41
+ adapted[:mine][channel[:id]] = channel
42
+ end
43
+
44
+ adapted
45
+ end
46
+
47
+ def self.transform(data, adapted)
48
+ return adapted[:mine][data[:id]] if adapted[:mine][data[:id]]
49
+
50
+ data[:known] = true
51
+ data[:mine] = false
52
+
53
+ data[:partners].each do |partner|
54
+ partner[:node][:platform] = {
55
+ blockchain: adapted[:mine].first[1][:partners][0][:node][:platform][:blockchain],
56
+ network: adapted[:mine].first[1][:partners][0][:node][:platform][:network]
57
+ }
58
+ end
59
+
60
+ data
61
+ end
62
+
63
+ def self.data(limit: nil, &vcr)
64
+ raw = vcr.nil? ? fetch(limit: limit) : vcr.call(-> { fetch(limit: limit) })
65
+
66
+ adapted = adapt(raw)
67
+
68
+ adapted[:describe_graph].map { |data| transform(data, adapted) }
69
+ end
70
+
71
+ def self.model(data)
72
+ data.map do |node_data|
73
+ Lighstorm::Models::Channel.new(node_data)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end