lighstorm 0.0.15 → 0.0.16

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 (156) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +7 -7
  4. data/adapters/bitcoin/address.rb +19 -0
  5. data/adapters/bitcoin/transaction.rb +34 -0
  6. data/adapters/lightning/connections/channel_node/fee.rb +28 -0
  7. data/adapters/lightning/connections/channel_node/policy.rb +63 -0
  8. data/adapters/lightning/connections/channel_node.rb +77 -0
  9. data/adapters/lightning/connections/payment_channel.rb +30 -0
  10. data/adapters/lightning/edges/channel.rb +98 -0
  11. data/adapters/lightning/edges/forward.rb +42 -0
  12. data/adapters/lightning/edges/payment/purpose.rb +45 -0
  13. data/adapters/lightning/edges/payment.rb +89 -0
  14. data/adapters/lightning/invoice.rb +186 -0
  15. data/adapters/lightning/nodes/node.rb +113 -0
  16. data/controllers/action.rb +1 -1
  17. data/controllers/bitcoin/address/actions/create.rb +91 -0
  18. data/controllers/bitcoin/address/actions/pay.rb +119 -0
  19. data/controllers/bitcoin/address.rb +24 -0
  20. data/controllers/bitcoin/transaction/all.rb +65 -0
  21. data/controllers/bitcoin/transaction.rb +25 -0
  22. data/controllers/concerns/impersonatable.rb +5 -3
  23. data/controllers/connection.rb +1 -1
  24. data/controllers/lightning/channel/actions/apply_gossip.rb +201 -0
  25. data/controllers/lightning/channel/actions/update_fee.rb +94 -0
  26. data/controllers/lightning/channel/all.rb +85 -0
  27. data/controllers/lightning/channel/find_by_id.rb +155 -0
  28. data/controllers/lightning/channel/mine.rb +116 -0
  29. data/controllers/lightning/channel.rb +43 -0
  30. data/controllers/lightning/forward/all.rb +250 -0
  31. data/controllers/lightning/forward/group_by_channel.rb +91 -0
  32. data/controllers/lightning/forward.rb +36 -0
  33. data/controllers/lightning/invoice/actions/create.rb +90 -0
  34. data/controllers/lightning/invoice/actions/pay.rb +97 -0
  35. data/controllers/lightning/invoice/actions/pay_through_route.rb +73 -0
  36. data/controllers/lightning/invoice/all.rb +82 -0
  37. data/controllers/lightning/invoice/decode.rb +50 -0
  38. data/controllers/lightning/invoice/find_by_code.rb +76 -0
  39. data/controllers/lightning/invoice/find_by_secret_hash.rb +56 -0
  40. data/controllers/lightning/invoice.rb +64 -0
  41. data/controllers/lightning/node/actions/apply_gossip.rb +114 -0
  42. data/controllers/lightning/node/actions/pay.rb +117 -0
  43. data/controllers/lightning/node/all.rb +69 -0
  44. data/controllers/lightning/node/find_by_public_key.rb +55 -0
  45. data/controllers/lightning/node/myself.rb +36 -0
  46. data/controllers/lightning/node.rb +35 -0
  47. data/controllers/lightning/payment/actions/pay.rb +110 -0
  48. data/controllers/lightning/payment/all.rb +439 -0
  49. data/controllers/lightning/payment.rb +37 -0
  50. data/controllers/lightning/secret/valid_proof.rb +60 -0
  51. data/controllers/lightning/secret.rb +16 -0
  52. data/controllers/wallet/activity/all.rb +196 -0
  53. data/controllers/wallet/activity.rb +28 -0
  54. data/controllers/wallet/balance.rb +3 -3
  55. data/controllers/wallet.rb +1 -1
  56. data/docs/README.md +229 -148
  57. data/docs/_coverpage.md +1 -1
  58. data/docs/index.html +1 -1
  59. data/models/bitcoin/address.rb +49 -0
  60. data/models/bitcoin/transaction.rb +41 -0
  61. data/models/concerns/protectable.rb +1 -1
  62. data/models/errors.rb +7 -8
  63. data/models/lightning/connections/channel_node/accounting.rb +27 -0
  64. data/models/lightning/connections/channel_node/fee.rb +82 -0
  65. data/models/lightning/connections/channel_node/htlc/blocks/delta.rb +41 -0
  66. data/models/lightning/connections/channel_node/htlc.rb +88 -0
  67. data/models/lightning/connections/channel_node/policy.rb +41 -0
  68. data/models/lightning/connections/channel_node.rb +86 -0
  69. data/models/lightning/connections/forward_channel.rb +31 -0
  70. data/models/lightning/connections/payment_channel.rb +58 -0
  71. data/models/lightning/edges/channel/accounting.rb +87 -0
  72. data/models/lightning/edges/channel/hop.rb +67 -0
  73. data/models/lightning/edges/channel.rb +197 -0
  74. data/models/lightning/edges/forward.rb +51 -0
  75. data/models/lightning/edges/groups/channel_forwards/analysis.rb +71 -0
  76. data/models/lightning/edges/groups/channel_forwards.rb +39 -0
  77. data/models/lightning/edges/payment.rb +104 -0
  78. data/models/lightning/invoice.rb +115 -0
  79. data/models/lightning/nodes/node/lightning.rb +33 -0
  80. data/models/lightning/nodes/node/platform.rb +50 -0
  81. data/models/lightning/nodes/node.rb +145 -0
  82. data/models/lightning/rate.rb +37 -0
  83. data/models/lightning/secret.rb +57 -0
  84. data/models/satoshis.rb +1 -1
  85. data/models/wallet/activity.rb +54 -0
  86. data/models/wallet/balance.rb +42 -0
  87. data/ports/dsl/lighstorm.rb +29 -16
  88. data/static/cache.rb +2 -0
  89. data/static/spec.rb +1 -1
  90. metadata +74 -68
  91. data/adapters/connections/channel_node/fee.rb +0 -26
  92. data/adapters/connections/channel_node/policy.rb +0 -61
  93. data/adapters/connections/channel_node.rb +0 -75
  94. data/adapters/connections/payment_channel.rb +0 -28
  95. data/adapters/edges/channel.rb +0 -96
  96. data/adapters/edges/forward.rb +0 -40
  97. data/adapters/edges/payment/purpose.rb +0 -43
  98. data/adapters/edges/payment.rb +0 -87
  99. data/adapters/invoice.rb +0 -184
  100. data/adapters/nodes/node.rb +0 -111
  101. data/adapters/transaction.rb +0 -23
  102. data/controllers/activity/all.rb +0 -194
  103. data/controllers/activity.rb +0 -26
  104. data/controllers/channel/actions/apply_gossip.rb +0 -193
  105. data/controllers/channel/actions/update_fee.rb +0 -91
  106. data/controllers/channel/all.rb +0 -83
  107. data/controllers/channel/find_by_id.rb +0 -153
  108. data/controllers/channel/mine.rb +0 -114
  109. data/controllers/channel.rb +0 -41
  110. data/controllers/forward/all.rb +0 -248
  111. data/controllers/forward/group_by_channel.rb +0 -89
  112. data/controllers/forward.rb +0 -34
  113. data/controllers/invoice/actions/create.rb +0 -88
  114. data/controllers/invoice/actions/pay.rb +0 -95
  115. data/controllers/invoice/actions/pay_through_route.rb +0 -71
  116. data/controllers/invoice/all.rb +0 -80
  117. data/controllers/invoice/decode.rb +0 -44
  118. data/controllers/invoice/find_by_code.rb +0 -70
  119. data/controllers/invoice/find_by_secret_hash.rb +0 -54
  120. data/controllers/invoice.rb +0 -62
  121. data/controllers/node/actions/apply_gossip.rb +0 -112
  122. data/controllers/node/actions/pay.rb +0 -115
  123. data/controllers/node/all.rb +0 -67
  124. data/controllers/node/find_by_public_key.rb +0 -53
  125. data/controllers/node/myself.rb +0 -34
  126. data/controllers/node.rb +0 -33
  127. data/controllers/payment/actions/pay.rb +0 -108
  128. data/controllers/payment/all.rb +0 -437
  129. data/controllers/payment.rb +0 -35
  130. data/controllers/secret/valid_proof.rb +0 -58
  131. data/controllers/transaction/all.rb +0 -61
  132. data/controllers/transaction.rb +0 -25
  133. data/models/activity.rb +0 -52
  134. data/models/connections/channel_node/accounting.rb +0 -25
  135. data/models/connections/channel_node/fee.rb +0 -80
  136. data/models/connections/channel_node/htlc/blocks/delta.rb +0 -39
  137. data/models/connections/channel_node/htlc.rb +0 -86
  138. data/models/connections/channel_node/policy.rb +0 -39
  139. data/models/connections/channel_node.rb +0 -84
  140. data/models/connections/forward_channel.rb +0 -29
  141. data/models/connections/payment_channel.rb +0 -56
  142. data/models/edges/channel/accounting.rb +0 -85
  143. data/models/edges/channel/hop.rb +0 -65
  144. data/models/edges/channel.rb +0 -195
  145. data/models/edges/forward.rb +0 -49
  146. data/models/edges/groups/channel_forwards/analysis.rb +0 -69
  147. data/models/edges/groups/channel_forwards.rb +0 -37
  148. data/models/edges/payment.rb +0 -102
  149. data/models/invoice.rb +0 -113
  150. data/models/nodes/node/lightning.rb +0 -31
  151. data/models/nodes/node/platform.rb +0 -48
  152. data/models/nodes/node.rb +0 -143
  153. data/models/rate.rb +0 -35
  154. data/models/secret.rb +0 -55
  155. data/models/transaction.rb +0 -39
  156. data/models/wallet.rb +0 -40
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1722bbe98bbd5a925f29fb5e172f04dec56ed8acc73eb9e6ef88eeb7200b94bd
4
- data.tar.gz: f06cb3903370b567275814a9541db2ca0c7dea7febd75e9ec95eb76d758714ef
3
+ metadata.gz: '0004783b50e9d57b22b89d956b84e88176902be82e1a6b42f4e4c4d1a385405c'
4
+ data.tar.gz: a153b71845e699695777c5b062a51e398ebf5d444c634b63fb2b6fc4b1523e8b
5
5
  SHA512:
6
- metadata.gz: 9cf1908d5809f4c2d8e3201926e3480b9e63b5958eee22ddfff6e210dac056f2f222bd9836fb4e7b98f316eace4c82ef44a579111afe283719b2cf268dc762e4
7
- data.tar.gz: 37a3c2544ed50c25e839c41f441c684f282d4995f319ad81f428ae0fc1a6b30d7225208ecd886732264da723e33db17d2732019eb8f430907662a3f5eebaeda0
6
+ metadata.gz: abbeeace9a564c6cb06abc0a726dfa84e56907d4b92aaf4c6169945ff5f66fb82120046e5df233d5273034cf202e0230184554ba1f3a667522498907fae5095e
7
+ data.tar.gz: e7b887c4e3411621cdfc495f5b3026cf3b84f70b80bbca986c3b46f26f414eff0e7d02e99aab67659dd65dd5908e9ec6ca091ff7eae6c554d04e1b5eb1f04e85
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lighstorm (0.0.15)
4
+ lighstorm (0.0.16)
5
5
  dotenv (~> 2.8, >= 2.8.1)
6
6
  lnd-client (~> 0.0.9)
7
7
  zache (~> 0.12.0)
data/README.md CHANGED
@@ -7,7 +7,7 @@ API for interacting with a [Lightning Node](https://lightning.network).
7
7
  ![Lighstorm text written stylized with an illustration of a Graph connecting two Nodes.](https://raw.githubusercontent.com/icebaker/assets/main/lighstorm/lighstorm.png)
8
8
 
9
9
  ```ruby
10
- Lighstorm::Channel.mine.first.myself.node.alias
10
+ Lighstorm::Lightning::Channel.mine.first.myself.node.alias
11
11
  ```
12
12
 
13
13
  ## Index
@@ -35,7 +35,7 @@ Although it tries to stay close to [Lightning's terminologies](https://docs.ligh
35
35
  Add to your `Gemfile`:
36
36
 
37
37
  ```ruby
38
- gem 'lighstorm', '~> 0.0.15'
38
+ gem 'lighstorm', '~> 0.0.16'
39
39
  ```
40
40
 
41
41
  ```ruby
@@ -53,19 +53,19 @@ Lighstorm.connect!(
53
53
  macaroon_path: '/lnd/data/chain/bitcoin/mainnet/admin.macaroon'
54
54
  )
55
55
 
56
- puts Lighstorm.version # => 0.0.15
56
+ puts Lighstorm.version # => 0.0.16
57
57
 
58
- Lighstorm::Node.myself.alias # => icebaker/old-stone
58
+ Lighstorm::Lightning::Node.myself.alias # => icebaker/old-stone
59
59
 
60
- Lighstorm::Invoice.create(
60
+ Lighstorm::Lightning::Invoice.create(
61
61
  description: 'Coffee',
62
62
  amount: { millisatoshis: 1_000 },
63
63
  payable: 'once'
64
64
  )
65
65
 
66
- Lighstorm::Invoice.decode('lnbc20m1pv...qqdhhwkj').pay
66
+ Lighstorm::Lightning::Invoice.decode('lnbc20m1pv...qqdhhwkj').pay
67
67
 
68
- Lighstorm::Invoice.decode('lnbc20m1pv...qqdhhwkj').pay(
68
+ Lighstorm::Lightning::Invoice.decode('lnbc20m1pv...qqdhhwkj').pay(
69
69
  fee: { maximum: { millisatoshis: 1000 } }
70
70
  )
71
71
 
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module Lighstorm
6
+ module Adapter
7
+ module Bitcoin
8
+ class Address
9
+ def self.new_address(grpc)
10
+ {
11
+ _source: :new_address,
12
+ _key: Digest::SHA256.hexdigest([grpc[:address]].join('/')),
13
+ code: grpc[:address]
14
+ }
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module Lighstorm
6
+ module Adapter
7
+ module Bitcoin
8
+ class Transaction
9
+ def self.get_transactions(grpc)
10
+ {
11
+ _source: :get_transactions,
12
+ _key: Digest::SHA256.hexdigest(
13
+ [grpc[:time_stamp], grpc[:tx_hash], grpc[:amount], grpc[:total_fees]].join('/')
14
+ ),
15
+ at: Time.at(grpc[:time_stamp]),
16
+ amount: { millisatoshis: (grpc[:amount] * 1000) + ((grpc[:amount].positive? ? -1 : 1) * (grpc[:total_fees] * 1000)) },
17
+ fee: { millisatoshis: grpc[:total_fees] * 1000 },
18
+ hash: grpc[:tx_hash],
19
+ description: grpc[:label] == '' ? nil : grpc[:label],
20
+ to: { address: { code: grpc[:dest_addresses].first } }
21
+ }
22
+ end
23
+
24
+ def self.send_coins(grpc)
25
+ {
26
+ _source: :send_coins,
27
+ _key: Digest::SHA256.hexdigest([grpc[:txid]].join('/')),
28
+ hash: grpc[:txid]
29
+ }
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lighstorm
4
+ module Adapter
5
+ module Lightning
6
+ class Fee
7
+ def self.fee_report(grpc)
8
+ {
9
+ _source: :fee_report,
10
+ id: grpc[:chan_id].to_s,
11
+ partner: {
12
+ policy: {
13
+ fee: {
14
+ base: {
15
+ millisatoshis: grpc[:base_fee_msat]
16
+ },
17
+ rate: {
18
+ parts_per_million: grpc[:fee_per_mil]
19
+ }
20
+ }
21
+ }
22
+ }
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lighstorm
4
+ module Adapter
5
+ module Lightning
6
+ class Policy
7
+ def self.get_chan_info(grpc)
8
+ {
9
+ fee: {
10
+ base: { millisatoshis: grpc[:fee_base_msat] },
11
+ rate: { parts_per_million: grpc[:fee_rate_milli_msat] }
12
+ },
13
+ htlc: {
14
+ minimum: { millisatoshis: grpc[:min_htlc] },
15
+ maximum: { millisatoshis: grpc[:max_htlc_msat] },
16
+ # https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#cltv_expiry_delta-selection
17
+ blocks: {
18
+ delta: {
19
+ minimum: grpc[:time_lock_delta] # aka cltv_expiry_delta
20
+ }
21
+ }
22
+ }
23
+ }
24
+ end
25
+
26
+ def self.subscribe_channel_graph(json)
27
+ result = {
28
+ _source: :subscribe_channel_graph,
29
+ fee: {
30
+ base: { millisatoshis: json['routingPolicy']['feeBaseMsat'].to_i },
31
+ rate: { parts_per_million: json['routingPolicy']['feeRateMilliMsat'].to_i }
32
+ },
33
+ htlc: {
34
+ minimum: { millisatoshis: json['routingPolicy']['minHtlc'].to_i },
35
+ maximum: { millisatoshis: json['routingPolicy']['maxHtlcMsat'].to_i },
36
+ # https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#cltv_expiry_delta-selection
37
+ blocks: {
38
+ delta: {
39
+ minimum: json['routingPolicy']['timeLockDelta'].to_i # aka cltv_expiry_delta
40
+ }
41
+ }
42
+ }
43
+ }
44
+
45
+ policy = json['routingPolicy']
46
+
47
+ result[:fee].delete(:base) unless policy.key?('feeBaseMsat') && !policy['feeBaseMsat'].nil?
48
+ result[:fee].delete(:rate) unless policy.key?('feeRateMilliMsat') && !policy['feeRateMilliMsat'].nil?
49
+ result.delete(:fee) if result[:fee].empty?
50
+
51
+ result[:htlc].delete(:minimum) unless policy.key?('minHtlc') && !policy['minHtlc'].nil?
52
+ result[:htlc].delete(:maximum) unless policy.key?('maxHtlcMsat') && !policy['maxHtlcMsat'].nil?
53
+ result[:htlc].delete(:blocks) unless policy.key?('timeLockDelta') && !policy['timeLockDelta'].nil?
54
+ result.delete(:htlc) if result[:htlc].empty?
55
+
56
+ return nil unless result.key?(:fee) || result.key?(:htlc)
57
+
58
+ result
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../nodes/node'
4
+ require_relative 'channel_node/policy'
5
+
6
+ module Lighstorm
7
+ module Adapter
8
+ module Lightning
9
+ class ChannelNode
10
+ def self.list_channels(grpc, key)
11
+ data = {
12
+ _source: :list_channels,
13
+ state: grpc[:active] ? 'active' : 'inactive',
14
+ initiator: grpc[:initiator] && key == :local,
15
+ accounting: { balance: { millisatoshis: grpc[:"#{key}_balance"] * 1000 } },
16
+ node: Node.list_channels(grpc, key)
17
+ }
18
+
19
+ data.delete(:node) if data[:node].nil?
20
+
21
+ data
22
+ end
23
+
24
+ def self.get_chan_info(grpc, index)
25
+ data = {
26
+ _source: :get_chan_info,
27
+ node: Node.get_chan_info(grpc, index)
28
+ }
29
+
30
+ if grpc[:"node#{index}_policy"]
31
+ data[:state] = grpc[:"node#{index}_policy"][:disabled] ? 'inactive' : 'active'
32
+ data[:policy] = Policy.get_chan_info(grpc[:"node#{index}_policy"])
33
+ end
34
+
35
+ data.delete(:node) if data[:node].nil?
36
+
37
+ data
38
+ end
39
+
40
+ def self.describe_graph(grpc, index)
41
+ data = {
42
+ _source: :describe_graph,
43
+ node: Node.describe_graph_from_channel(grpc, index)
44
+ }
45
+
46
+ # TODO: No examples to validate the correctness of this scenario.
47
+ if grpc[:"node#{index}_policy"]
48
+ data[:state] = grpc[:"node#{index}_policy"][:disabled] ? 'inactive' : 'active'
49
+ data[:policy] = Policy.get_chan_info(grpc[:"node#{index}_policy"])
50
+ end
51
+
52
+ data.delete(:node) if data[:node].nil?
53
+
54
+ data
55
+ end
56
+
57
+ def self.subscribe_channel_graph(json)
58
+ data = {
59
+ _source: :subscribe_channel_graph,
60
+ node: {
61
+ public_key: json['advertisingNode']
62
+ },
63
+ policy: Policy.subscribe_channel_graph(json)
64
+ }
65
+
66
+ unless json['routingPolicy']['disabled'].nil?
67
+ data[:state] = json['routingPolicy']['disabled'] ? 'inactive' : 'active'
68
+ end
69
+
70
+ data.delete(:policy) if data[:policy].nil?
71
+
72
+ data
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module Lighstorm
6
+ module Adapter
7
+ module Lightning
8
+ class PaymentChannel
9
+ def self.list_payments(grpc, index)
10
+ {
11
+ _source: :list_payments,
12
+ hop: index + 1,
13
+ amount: { millisatoshis: grpc[:amt_to_forward_msat] },
14
+ fee: { millisatoshis: grpc[:fee_msat] },
15
+ channel: {
16
+ _key: Digest::SHA256.hexdigest(grpc[:chan_id].to_s),
17
+ id: grpc[:chan_id].to_s,
18
+ partners: [
19
+ node: {
20
+ _key: Digest::SHA256.hexdigest(grpc[:pub_key].to_s),
21
+ public_key: grpc[:pub_key]
22
+ }
23
+ ]
24
+ }
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ require_relative '../connections/channel_node'
6
+
7
+ module Lighstorm
8
+ module Adapter
9
+ module Lightning
10
+ class Channel
11
+ def self._key(id, state)
12
+ Digest::SHA256.hexdigest(
13
+ [id, state].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] ? 'active' : 'inactive'),
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: at - grpc[:lifetime],
30
+ up_at: at - grpc[:uptime],
31
+ state: grpc[:active] ? 'active' : 'inactive',
32
+ exposure: grpc[:private] ? 'private' : 'public',
33
+ accounting: {
34
+ capacity: { millisatoshis: grpc[:capacity] * 1000 },
35
+ sent: { millisatoshis: grpc[:total_satoshis_sent] * 1000 },
36
+ received: { millisatoshis: grpc[:total_satoshis_received] * 1000 },
37
+ unsettled: { millisatoshis: 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: { millisatoshis: 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: { millisatoshis: grpc[:capacity] * 1000 }
71
+ },
72
+ partners: [
73
+ ChannelNode.describe_graph(grpc, 1),
74
+ ChannelNode.describe_graph(grpc, 2)
75
+ ]
76
+ }
77
+ end
78
+
79
+ def self.subscribe_channel_graph(json)
80
+ {
81
+ _source: :subscribe_channel_graph,
82
+ _key: _key(json['chanId'], nil),
83
+ id: json['chanId'],
84
+ accounting: {
85
+ capacity: { millisatoshis: json['capacity'].to_i * 1000 }
86
+ },
87
+ partners: [
88
+ ChannelNode.subscribe_channel_graph(json),
89
+ { node: {
90
+ public_key: json['connectingNode']
91
+ } }
92
+ ]
93
+ }
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module Lighstorm
6
+ module Adapter
7
+ module Lightning
8
+ class Forward
9
+ def self.forwarding_history(grpc)
10
+ {
11
+ _source: :forwarding_history,
12
+ _key: _key(grpc),
13
+ at: Time.at(grpc[:timestamp_ns] / 1e+9),
14
+ fee: { millisatoshis: grpc[:fee_msat] },
15
+ in: {
16
+ amount: { millisatoshis: grpc[:amt_in_msat] },
17
+ channel: {
18
+ id: grpc[:chan_id_in].to_s
19
+ }
20
+ },
21
+ out: {
22
+ amount: { millisatoshis: 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
42
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lighstorm
4
+ module Adapter
5
+ module Lightning
6
+ class Purpose
7
+ def self.send_payment_v2(grpc, node_get_info)
8
+ return 'unknown' if grpc[:payment_route][:hops].empty?
9
+
10
+ return 'self-payment' if self_payment?(grpc[:payment_route][:hops])
11
+ return 'peer-to-peer' if peer_to_peer?(grpc[:payment_route][:hops])
12
+ return 'rebalance' if rebalance?(grpc[:payment_route][:hops], node_get_info)
13
+
14
+ 'payment'
15
+ end
16
+
17
+ def self.list_payments(grpc, node_get_info)
18
+ return 'unknown' if grpc[:htlcs].empty?
19
+
20
+ return 'self-payment' if self_payment?(grpc[:htlcs].last[:route][:hops])
21
+ return 'peer-to-peer' if peer_to_peer?(grpc[:htlcs].last[:route][:hops])
22
+ return 'rebalance' if rebalance?(grpc[:htlcs].last[:route][:hops], node_get_info)
23
+
24
+ 'payment'
25
+ end
26
+
27
+ def self.self_payment?(hops)
28
+ hops.size == 2 && hops[0][:chan_id] == hops[1][:chan_id]
29
+ end
30
+
31
+ def self.peer_to_peer?(hops)
32
+ hops.size == 1
33
+ end
34
+
35
+ def self.rebalance?(hops, node_get_info)
36
+ return false if hops.size <= 2
37
+
38
+ destination_public_key = hops.last[:pub_key]
39
+
40
+ node_get_info[:identity_pubkey] == destination_public_key
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ require_relative '../connections/payment_channel'
6
+ require_relative 'payment/purpose'
7
+
8
+ require_relative '../invoice'
9
+
10
+ require_relative '../../../ports/dsl/lighstorm/errors'
11
+
12
+ module Lighstorm
13
+ module Adapter
14
+ module Lightning
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.send_payment_v2(grpc, node_myself, invoice_decode)
28
+ adapted = list_payments(grpc, node_myself, invoice_decode)
29
+ adapted[:_source] = :send_payment_v2
30
+ adapted
31
+ end
32
+
33
+ def self.list_payments(grpc, node_myself, invoice_decode = nil)
34
+ data = {
35
+ _source: :list_payments,
36
+ _key: _key(grpc),
37
+ at: Time.at(grpc[:creation_time_ns] / 1e+9),
38
+ state: grpc[:status].to_s.downcase,
39
+ fee: { millisatoshis: grpc[:fee_msat] },
40
+ amount: { millisatoshis: grpc[:value_msat] },
41
+ purpose: Purpose.list_payments(grpc, node_myself),
42
+ invoice: Invoice.list_payments(grpc, invoice_decode)
43
+ }
44
+
45
+ data[:secret] = data[:invoice][:secret]
46
+
47
+ htlc = grpc[:htlcs].last
48
+
49
+ return data if htlc.nil?
50
+
51
+ data[:hops] = htlc[:route][:hops].map.with_index do |raw_hop, i|
52
+ hop = PaymentChannel.list_payments(raw_hop, i)
53
+ hop[:channel][:target] = { public_key: raw_hop[:pub_key] }
54
+ hop
55
+ end
56
+
57
+ data[:invoice][:settled_at] = Time.at(htlc[:resolve_time_ns] / 1e+9) if htlc[:resolve_time_ns]
58
+
59
+ last_hop = htlc[:route][:hops].last
60
+
61
+ return data if last_hop.nil?
62
+
63
+ # https://github.com/satoshisstream/satoshis.stream/blob/main/TLV_registry.md
64
+ if last_hop[:custom_records][34_349_334]
65
+ data[:message] = last_hop[:custom_records][34_349_334].dup
66
+
67
+ unless data[:message].force_encoding('UTF-8').valid_encoding?
68
+ data[:message] = data[:message].unpack1('H*')
69
+
70
+ data[:message] = data[:message].scrub('?') unless data[:message].force_encoding('UTF-8').valid_encoding?
71
+ end
72
+ end
73
+
74
+ if data[:invoice] && data[:invoice][:code] && !data[:invoice][:code].nil? && !data[:invoice][:code].empty?
75
+ data[:through] = if data[:invoice][:payable] == 'indefinitely'
76
+ 'amp'
77
+ else
78
+ 'non-amp'
79
+ end
80
+ else
81
+ data[:through] = last_hop[:mpp_record] ? 'amp' : 'keysend'
82
+ end
83
+
84
+ data
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end