lighstorm 0.0.3 → 0.0.5

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +5 -0
  3. data/.github/workflows/ruby-rspec-tests.yml +39 -0
  4. data/.gitignore +1 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +10 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile.lock +26 -2
  9. data/README.md +30 -371
  10. data/adapters/connections/channel_node/fee.rb +26 -0
  11. data/adapters/connections/channel_node/policy.rb +61 -0
  12. data/adapters/connections/channel_node.rb +74 -0
  13. data/adapters/connections/payment_channel.rb +28 -0
  14. data/adapters/edges/channel.rb +96 -0
  15. data/adapters/edges/forward.rb +40 -0
  16. data/adapters/edges/payment/purpose.rb +32 -0
  17. data/adapters/edges/payment.rb +50 -0
  18. data/adapters/invoice.rb +49 -0
  19. data/adapters/nodes/node.rb +111 -0
  20. data/adapters/payment_request.rb +76 -0
  21. data/components/cache.rb +3 -2
  22. data/components/lnd.rb +5 -1
  23. data/controllers/channel/actions/apply_gossip.rb +194 -0
  24. data/controllers/channel/actions/update_fee.rb +76 -0
  25. data/controllers/channel/all.rb +79 -0
  26. data/controllers/channel/find_by_id.rb +153 -0
  27. data/controllers/channel/mine.rb +114 -0
  28. data/controllers/channel.rb +27 -0
  29. data/controllers/forward/all.rb +244 -0
  30. data/controllers/forward/group_by_channel.rb +89 -0
  31. data/controllers/forward.rb +28 -0
  32. data/controllers/invoice/actions/create.rb +36 -0
  33. data/controllers/invoice/actions/pay.rb +28 -0
  34. data/controllers/invoice/actions/pay_through_route.rb +71 -0
  35. data/controllers/invoice/all.rb +70 -0
  36. data/controllers/invoice/find_by_secret_hash.rb +42 -0
  37. data/controllers/invoice.rb +36 -0
  38. data/controllers/node/actions/apply_gossip.rb +112 -0
  39. data/controllers/node/all.rb +63 -0
  40. data/controllers/node/find_by_public_key.rb +49 -0
  41. data/controllers/node/myself.rb +34 -0
  42. data/controllers/node.rb +27 -0
  43. data/controllers/payment/all.rb +368 -0
  44. data/controllers/payment.rb +21 -0
  45. data/docs/.nojekyll +0 -0
  46. data/docs/README.md +731 -0
  47. data/docs/_coverpage.md +12 -0
  48. data/docs/index.html +26 -0
  49. data/docs/vendor/docsify/docsify@4.js +1 -0
  50. data/docs/vendor/docsify-themeable/theme-simple-dark.css +3 -0
  51. data/docs/vendor/docsify-themeable/theme-simple-dark.css.map +1 -0
  52. data/docs/vendor/prismjs/prism-bash.min.js +1 -0
  53. data/docs/vendor/prismjs/prism-ruby.min.js +1 -0
  54. data/docs/vendor/prismjs/prism-tomorrow.min.css +1 -0
  55. data/lighstorm.gemspec +3 -1
  56. data/models/concerns/protectable.rb +23 -0
  57. data/models/connections/channel_node/accounting.rb +7 -14
  58. data/models/connections/channel_node/fee.rb +55 -84
  59. data/models/connections/channel_node/htlc/blocks/delta.rb +39 -0
  60. data/models/connections/channel_node/htlc.rb +65 -11
  61. data/models/connections/channel_node/policy.rb +15 -18
  62. data/models/connections/channel_node.rb +48 -22
  63. data/models/connections/forward_channel.rb +8 -43
  64. data/models/connections/payment_channel.rb +18 -39
  65. data/models/edges/channel/accounting.rb +45 -20
  66. data/models/edges/channel/hop.rb +65 -0
  67. data/models/edges/channel.rb +111 -169
  68. data/models/edges/forward.rb +9 -119
  69. data/models/edges/groups/{analysis.rb → channel_forwards/analysis.rb} +9 -9
  70. data/models/edges/groups/channel_forwards.rb +10 -40
  71. data/models/edges/payment.rb +29 -215
  72. data/models/errors.rb +32 -0
  73. data/models/invoice.rb +49 -0
  74. data/models/nodes/node/lightning.rb +11 -16
  75. data/models/nodes/node/platform.rb +13 -13
  76. data/models/nodes/node.rb +59 -103
  77. data/models/payment_request.rb +72 -0
  78. data/models/rate.rb +11 -1
  79. data/models/satoshis.rb +5 -6
  80. data/ports/dsl/lighstorm/errors.rb +5 -0
  81. data/ports/dsl/lighstorm.rb +11 -9
  82. data/ports/grpc/session.rb +26 -0
  83. data/ports/grpc.rb +80 -0
  84. data/static/cache.rb +12 -0
  85. data/static/spec.rb +3 -1
  86. metadata +62 -6
  87. data/models/connections/channel_node/constraints.rb +0 -24
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'time'
4
- require 'date'
4
+
5
+ require_relative '../../ports/grpc'
6
+ require_relative '../../adapters/edges/channel'
5
7
 
6
8
  require_relative '../../components/lnd'
7
9
  require_relative '../../components/cache'
@@ -9,246 +11,186 @@ require_relative '../../components/cache'
9
11
  require_relative '../nodes/node'
10
12
  require_relative 'channel/accounting'
11
13
 
14
+ require_relative '../../controllers/channel/actions/apply_gossip'
12
15
  require_relative '../connections/channel_node'
13
16
  require_relative '../satoshis'
14
17
 
18
+ require_relative '../errors'
19
+
15
20
  module Lighstorm
16
21
  module Models
17
22
  class Channel
18
- KIND = :edge
23
+ attr_reader :data, :_key, :id
19
24
 
20
- attr_reader :data
21
-
22
- def self.all
23
- response = LND.instance.middleware('lightning.describe_graph') do
24
- LND.instance.client.lightning.describe_graph
25
- end
25
+ def initialize(data)
26
+ @data = data
26
27
 
27
- response.edges.map do |raw_channel|
28
- Channel.new({ describe_graph: raw_channel })
29
- end
28
+ @_key = data[:_key]
29
+ @id = data[:id]
30
30
  end
31
31
 
32
- def self.mine
33
- response = Cache.for('lightning.list_channels') do
34
- LND.instance.middleware('lightning.list_channels') do
35
- LND.instance.client.lightning.list_channels
36
- end
37
- end
38
-
39
- response.channels.map do |channel|
40
- Channel.find_by_id(channel.chan_id.to_s)
41
- end
32
+ def known?
33
+ @data[:known] == true
42
34
  end
43
35
 
44
- def self.find_by_id(id)
45
- Channel.new({ id: id })
46
- end
36
+ def mine?
37
+ ensure_known!
47
38
 
48
- def id
49
- # Standard JSON don't support BigInt, so, a String is safer.
50
- @id.to_s
39
+ @data[:mine]
51
40
  end
52
41
 
53
- def initialize(params)
54
- if params[:id]
55
- begin
56
- response = Cache.for('lightning.get_chan_info', params: { chan_id: params[:id].to_i }) do
57
- LND.instance.middleware('lightning.get_chan_info') do
58
- LND.instance.client.lightning.get_chan_info(chan_id: params[:id].to_i)
59
- end
60
- end
42
+ def exposure
43
+ ensure_known!
61
44
 
62
- @data = { get_chan_info: response }
63
- @id = @data[:get_chan_info].channel_id
64
- rescue StandardError => e
65
- @data = { get_chan_info: nil, error: e }
66
- @id = params[:id]
67
- end
68
- elsif params[:describe_graph]
69
- @data = { describe_graph: params[:describe_graph] }
70
- @id = @data[:describe_graph].channel_id
71
- end
45
+ @data[:exposure]
46
+ end
72
47
 
73
- fetch_from_fee_report!
48
+ def opened_at
49
+ ensure_mine!
74
50
 
75
- fetch_from_list_channels!
76
- calculate_times_after_list_channels!
51
+ @data[:opened_at]
77
52
  end
78
53
 
79
- def error?
80
- !@data[:error].nil?
81
- end
54
+ def up_at
55
+ ensure_mine!
82
56
 
83
- def error
84
- @data[:error]
57
+ @data[:up_at]
85
58
  end
86
59
 
87
- def active
88
- @data[:list_channels] ? @data[:list_channels][:channels].first.active : nil
89
- end
60
+ def active?
61
+ ensure_mine!
90
62
 
91
- def exposure
92
- return 'public' if @data[:describe_graph]
63
+ @data[:state] == 'active'
64
+ end
93
65
 
94
- return unless @data[:list_channels]
66
+ def state
67
+ ensure_mine!
95
68
 
96
- @data[:list_channels][:channels].first.private ? 'private' : 'public'
69
+ @data[:state]
97
70
  end
98
71
 
99
- def opened_at
100
- @opened_at ||= if @data[:list_channels]
101
- DateTime.parse(
102
- (Time.now - @data[:list_channels][:channels].first.lifetime).to_s
103
- )
104
- end
105
- end
72
+ def accounting
73
+ ensure_known!
106
74
 
107
- def up_at
108
- @up_at ||= if @data[:list_channels]
109
- DateTime.parse(
110
- (Time.now - @data[:list_channels][:channels].first.uptime).to_s
111
- )
112
- end
75
+ @accounting ||= @data[:accounting] ? ChannelAccounting.new(@data[:accounting], mine?) : nil
113
76
  end
114
77
 
115
- def accounting
116
- @accounting ||= ChannelAccounting.new(self)
117
- end
118
-
119
- def partners(fetch: false)
120
- @partners ||= if mine?
121
- [myself, partner]
122
- elsif @data[:describe_graph]
123
- [
124
- ChannelNode.new(
125
- self,
126
- Node.new({ public_key: @data[:describe_graph].node1_pub }, fetch: fetch)
127
- ),
128
- ChannelNode.new(
129
- self,
130
- Node.new({ public_key: @data[:describe_graph].node2_pub }, fetch: fetch)
131
- )
132
- ]
133
- elsif @data[:get_chan_info]
134
- [
135
- ChannelNode.new(
136
- self,
137
- Node.new({ public_key: @data[:get_chan_info].node1_pub }, fetch: fetch)
138
- ),
139
- ChannelNode.new(
140
- self,
141
- Node.new({ public_key: @data[:get_chan_info].node2_pub }, fetch: fetch)
142
- )
143
- ]
78
+ def partners
79
+ @partners ||= if @data[:partners]
80
+ @data[:partners].map do |data|
81
+ ChannelNode.new(data, known? ? mine? : nil, transaction)
82
+ end
144
83
  else
145
- raise 'missing data'
84
+ []
146
85
  end
147
86
  end
148
87
 
149
- def mine?
150
- my_node = Node.myself.public_key
151
-
152
- if @data[:get_chan_info]
153
- (
154
- @data[:get_chan_info].node1_pub == my_node || @data[:get_chan_info].node2_pub == my_node
155
- )
156
- elsif @data[:describe_graph]
157
- (
158
- @data[:describe_graph].node1_pub == my_node || @data[:describe_graph].node2_pub == my_node
159
- )
160
- else
161
- false
162
- end
163
- end
164
-
165
88
  def myself
166
- raise 'not your channel' unless mine?
89
+ ensure_mine!
167
90
 
168
- @myself ||= ChannelNode.new(self, Node.myself)
91
+ @myself ||= partners.find { |partner| partner.node.myself? }
169
92
  end
170
93
 
171
94
  def partner
172
- raise 'not your channel' unless mine?
95
+ ensure_mine!
173
96
 
174
- key = @data[:get_chan_info] ? :get_chan_info : :describe_graph
97
+ @partner ||= partners.find { |partner| !partner.node.myself? }
98
+ end
175
99
 
176
- public_key = if @data[key].node1_pub == myself.node.public_key
177
- @data[key].node2_pub
178
- else
179
- @data[key].node1_pub
180
- end
100
+ def transaction
101
+ Struct.new(:data) do
102
+ def funding
103
+ Struct.new(:data) do
104
+ def id
105
+ data[:id]
106
+ end
181
107
 
182
- @partner ||= ChannelNode.new(self, Node.find_by_public_key(public_key))
183
- end
108
+ def index
109
+ data[:index]
110
+ end
184
111
 
185
- def raw
186
- {
187
- get_chan_info: @data[:get_chan_info].to_h,
188
- describe_graph: @data[:describe_graph].to_h,
189
- list_channels: {
190
- channels: @data[:list_channels] ? @data[:list_channels][:channels].map(&:to_h) : nil
191
- }
192
- }
112
+ def to_h
113
+ { id: id, index: index }
114
+ end
115
+ end.new(data[:funding])
116
+ end
117
+
118
+ def to_h
119
+ { funding: funding.to_h }
120
+ end
121
+ end.new(@data[:transaction])
193
122
  end
194
123
 
195
124
  def to_h
196
- if @data[:get_chan_info]
125
+ if !known? && partners.size.positive?
126
+ { _key: _key, id: id, partners: partners.map(&:to_h) }
127
+ elsif !known?
128
+ { _key: _key, id: id }
129
+ elsif mine?
197
130
  {
131
+ _key: _key,
198
132
  id: id,
199
133
  opened_at: opened_at,
200
134
  up_at: up_at,
201
- active: active,
135
+ state: state,
202
136
  exposure: exposure,
203
137
  accounting: accounting.to_h,
204
138
  partner: partner.to_h,
205
139
  myself: myself.to_h
206
140
  }
207
- else
141
+ elsif @data[:accounting]
208
142
  {
143
+ _key: _key,
209
144
  id: id,
210
145
  accounting: accounting.to_h,
211
146
  partners: partners.map(&:to_h)
212
147
  }
148
+ else
149
+ {
150
+ _key: _key,
151
+ id: id,
152
+ partners: partners.map(&:to_h)
153
+ }
213
154
  end
214
155
  end
215
156
 
216
- private
157
+ def dump
158
+ result = Marshal.load(Marshal.dump(@data)).merge(
159
+ { partners: partners.map(&:dump) }
160
+ )
217
161
 
218
- # Ensure that we are getting fresh up-date data about our own fees.
219
- def fetch_from_fee_report!
220
- response = Cache.for('lightning.fee_report') do
221
- LND.instance.middleware('lightning.fee_report') do
222
- LND.instance.client.lightning.fee_report
223
- end
224
- end
162
+ result[:accounting] = accounting.dump if known?
225
163
 
226
- response.channel_fees.map do |channel|
227
- if channel.chan_id == @id
228
- @data[:fee_report] = { channel_fees: [channel] }
229
- break
230
- end
231
- end
164
+ result
232
165
  end
233
166
 
234
- def fetch_from_list_channels!
235
- response = Cache.for('lightning.list_channels') do
236
- LND.instance.middleware('lightning.list_channels') do
237
- LND.instance.client.lightning.list_channels
238
- end
239
- end
167
+ def self.adapt(gossip: nil, dump: nil)
168
+ raise TooManyArgumentsError, 'you need to pass gossip: or dump:, not both' if !gossip.nil? && !dump.nil?
240
169
 
241
- response.channels.map do |channel|
242
- if channel.chan_id == @id
243
- @data[:list_channels] = { channels: [channel] }
244
- break
245
- end
170
+ raise ArgumentError, 'missing gossip: or dump:' if gossip.nil? && dump.nil?
171
+
172
+ if !gossip.nil?
173
+ new(Adapter::Channel.subscribe_channel_graph(gossip))
174
+ elsif !dump.nil?
175
+ new(dump)
246
176
  end
247
177
  end
248
178
 
249
- def calculate_times_after_list_channels!
250
- opened_at
251
- up_at
179
+ def apply!(gossip:)
180
+ Controllers::Channel::ApplyGossip.perform(
181
+ self, gossip
182
+ )
183
+ end
184
+
185
+ private
186
+
187
+ def ensure_known!
188
+ raise Errors::UnknownChannelError unless known?
189
+ end
190
+
191
+ def ensure_mine!
192
+ ensure_known!
193
+ raise Errors::NotYourChannelError if @data[:mine] == false
252
194
  end
253
195
  end
254
196
  end
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'digest'
4
3
  require 'time'
5
- require 'date'
6
4
 
7
5
  require_relative '../satoshis'
8
6
 
@@ -12,130 +10,30 @@ require_relative 'groups/channel_forwards'
12
10
  module Lighstorm
13
11
  module Models
14
12
  class Forward
15
- KIND = :edge
13
+ attr_reader :_key, :at
16
14
 
17
- attr_reader :data
15
+ def initialize(data)
16
+ @data = data
18
17
 
19
- def self.all(limit: nil, raw: false, info: true)
20
- last_offset = 0
21
-
22
- forwards = []
23
-
24
- loop do
25
- response = Cache.for(
26
- 'lightning.forwarding_history',
27
- params: { peer_alias_lookup: true, index_offset: last_offset }
28
- ) do
29
- LND.instance.middleware('lightning.forwarding_history') do
30
- LND.instance.client.lightning.forwarding_history(
31
- peer_alias_lookup: true, index_offset: last_offset
32
- )
33
- end
34
- end
35
-
36
- response.forwarding_events.each { |raw_forward| forwards << raw_forward }
37
-
38
- # Unfortunately, forwards aren't sorted in descending order. :(
39
- # break if !limit.nil? && forwards.size >= limit
40
-
41
- break if last_offset == response.last_offset_index || last_offset > response.last_offset_index
42
-
43
- last_offset = response.last_offset_index
44
- end
45
-
46
- forwards = forwards.sort_by { |raw_forward| -raw_forward.timestamp_ns }
47
-
48
- forwards = forwards[0..limit - 1] unless limit.nil?
49
-
50
- return forwards if raw
51
-
52
- forwards.map { |raw_forward| Forward.new(raw_forward, respond_info: info) }
53
- end
54
-
55
- def self.first
56
- all(limit: 1).first
57
- end
58
-
59
- def self.last
60
- all.last
61
- end
62
-
63
- def self.group_by_channel(direction: :out, hours_ago: nil, limit: nil, info: true)
64
- raw_forwards = all(raw: true)
65
-
66
- direction = direction.to_sym
67
-
68
- groups = {}
69
-
70
- raw_forwards.each do |raw_forward|
71
- channel_id = direction == :in ? raw_forward.chan_id_in : raw_forward.chan_id_out
72
-
73
- if hours_ago
74
- forward_hours_ago = (
75
- Time.now - Time.at(raw_forward.timestamp_ns / 1e+9)
76
- ).to_f / 3600
77
-
78
- next if forward_hours_ago > hours_ago
79
- end
80
-
81
- unless groups[channel_id]
82
- groups[channel_id] = {
83
- last_at: nil,
84
- analysis: { count: 0, sums: { amount: 0, fee: 0 } },
85
- direction => { id: channel_id }
86
- }
87
- end
88
-
89
- groups[channel_id][:analysis][:count] += 1
90
- groups[channel_id][:analysis][:sums][:amount] += raw_forward.amt_in_msat
91
- groups[channel_id][:analysis][:sums][:fee] += raw_forward.fee_msat
92
-
93
- if groups[channel_id][:last_at].nil? || raw_forward.timestamp_ns > groups[channel_id][:last_at]
94
- groups[channel_id][:last_at] = raw_forward.timestamp_ns
95
- groups[channel_id][:sample] = raw_forward
96
- end
97
- end
98
-
99
- groups = groups.values.sort_by { |group| - group[:last_at] }
100
- .sort_by { |group| - group[:analysis][:count] }
101
-
102
- groups = groups[0..limit - 1] unless limit.nil?
103
-
104
- groups.map { |raw_group| ChannelForwardsGroup.new(direction, raw_group) }
105
- end
106
-
107
- def initialize(raw, respond_info: true)
108
- @respond_info = respond_info
109
- @data = { forwarding_history: { forwarding_events: [raw] } }
110
- end
111
-
112
- def id
113
- @id ||= Digest::SHA256.hexdigest(
114
- @data[:forwarding_history][:forwarding_events].first.timestamp_ns.to_s
115
- )
116
- end
117
-
118
- def at
119
- DateTime.parse(Time.at(
120
- @data[:forwarding_history][:forwarding_events].first.timestamp_ns / 1e+9
121
- ).to_s)
18
+ @_key = data[:_key]
19
+ @at = data[:at]
122
20
  end
123
21
 
124
22
  def fee
125
- Satoshis.new(milisatoshis: @data[:forwarding_history][:forwarding_events].first.fee_msat)
23
+ @fee ||= Satoshis.new(milisatoshis: @data[:fee][:milisatoshis])
126
24
  end
127
25
 
128
26
  def in
129
- @in ||= ForwardChannel.new(:in, self, respond_info: @respond_info)
27
+ @in ||= ForwardChannel.new(@data[:in])
130
28
  end
131
29
 
132
30
  def out
133
- @out ||= ForwardChannel.new(:out, self, respond_info: @respond_info)
31
+ @out ||= ForwardChannel.new(@data[:out])
134
32
  end
135
33
 
136
34
  def to_h
137
35
  {
138
- id: id,
36
+ _key: _key,
139
37
  at: at,
140
38
  fee: {
141
39
  milisatoshis: fee.milisatoshis,
@@ -145,14 +43,6 @@ module Lighstorm
145
43
  out: out.to_h
146
44
  }
147
45
  end
148
-
149
- def raw
150
- {
151
- forwarding_history: {
152
- forwarding_events: [@data[:forwarding_history][:forwarding_events].first.to_h]
153
- }
154
- }
155
- end
156
46
  end
157
47
  end
158
48
  end
@@ -3,19 +3,19 @@
3
3
  module Lighstorm
4
4
  module Models
5
5
  class ChannelForwardsGroup
6
- Analysis = Struct.new(:analysis) do
6
+ Analysis = Struct.new(:data) do
7
7
  def count
8
- analysis[:count]
8
+ data[:count]
9
9
  end
10
10
 
11
11
  def sums
12
12
  Struct.new(:sums) do
13
13
  def amount
14
- Satoshis.new(milisatoshis: sums[:amount])
14
+ Satoshis.new(milisatoshis: sums[:amount][:milisatoshis])
15
15
  end
16
16
 
17
17
  def fee
18
- Satoshis.new(milisatoshis: sums[:fee])
18
+ Satoshis.new(milisatoshis: sums[:fee][:milisatoshis])
19
19
  end
20
20
 
21
21
  def to_h
@@ -27,20 +27,20 @@ module Lighstorm
27
27
  }
28
28
  }
29
29
  end
30
- end.new(analysis[:sums])
30
+ end.new(data[:sums])
31
31
  end
32
32
 
33
33
  def averages
34
- Struct.new(:analysis) do
34
+ Struct.new(:data) do
35
35
  def amount
36
36
  Satoshis.new(
37
- milisatoshis: analysis[:sums][:amount].to_f / analysis[:count]
37
+ milisatoshis: data[:sums][:amount][:milisatoshis].to_f / data[:count]
38
38
  )
39
39
  end
40
40
 
41
41
  def fee
42
42
  Satoshis.new(
43
- milisatoshis: analysis[:sums][:fee].to_f / analysis[:count]
43
+ milisatoshis: data[:sums][:fee][:milisatoshis].to_f / data[:count]
44
44
  )
45
45
  end
46
46
 
@@ -53,7 +53,7 @@ module Lighstorm
53
53
  }
54
54
  }
55
55
  end
56
- end.new(analysis)
56
+ end.new(data)
57
57
  end
58
58
 
59
59
  def to_h
@@ -1,66 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../../satoshis'
4
- require_relative 'analysis'
4
+ require_relative 'channel_forwards/analysis'
5
5
 
6
6
  module Lighstorm
7
7
  module Models
8
8
  class ChannelForwardsGroup
9
- def initialize(direction, data)
10
- @direction = direction
9
+ attr_reader :_key, :last_at
10
+
11
+ def initialize(data)
11
12
  @data = data
12
- end
13
13
 
14
- def last_at
15
- @last_at ||= DateTime.parse(Time.at(@data[:last_at].to_f / 1e+9).to_s)
14
+ @_key = data[:_key]
15
+ @last_at = data[:last_at]
16
16
  end
17
17
 
18
18
  def analysis
19
19
  Analysis.new(@data[:analysis])
20
20
  end
21
21
 
22
- def in
23
- return @in if @in
24
-
25
- raise raise ArgumentError, "Method `in` doesn't exist." unless @direction == :in
26
-
27
- @in = Channel.new({ id: @data[:in][:id] })
28
- end
29
-
30
- def out
31
- return @out if @out
32
-
33
- raise raise ArgumentError, "Method `out` doesn't exist." unless @direction == :out
34
-
35
- @out = Channel.new({ id: @data[:out][:id] })
22
+ def channel
23
+ @channel ||= Channel.new(@data[:channel])
36
24
  end
37
25
 
38
- # def capacity
39
- # @capacity ||= Satoshis.new(milisatoshis: @channel.data[:get_chan_info].capacity * 1000)
40
- # end
41
-
42
26
  def to_h
43
27
  {
28
+ _key: _key,
44
29
  last_at: last_at,
45
30
  analysis: analysis.to_h,
46
- @direction => {
47
- id: channel.id,
48
- partner: {
49
- node: {
50
- alias: channel&.partner&.node&.alias,
51
- public_key: channel&.partner&.node&.public_key,
52
- color: channel&.partner&.node&.color
53
- }
54
- }
55
- }
31
+ channel: channel.to_h
56
32
  }
57
33
  end
58
-
59
- private
60
-
61
- def channel
62
- @channel ||= @direction == :in ? self.in : out
63
- end
64
34
  end
65
35
  end
66
36
  end