lighstorm 0.0.9 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 551ffb5be38f96d6c0bb4f7b8fbde5763c623f0d100f0a1b34acb90a6074fb23
4
- data.tar.gz: 59451d54f2ad6d45c95c7649ab0a048a4adeb7a15f1af08f133d8eaae107d9bc
3
+ metadata.gz: 6072337300f3fd850fbca3ba5c7c804842c275d5f35fa288dfb83747fa0b1a56
4
+ data.tar.gz: 8a16d83cb96f0ed911ebd55e12707b20f0aac00a0acac8d176e544a68abad647
5
5
  SHA512:
6
- metadata.gz: 54e1e6929a1f5dc67f319461d6fc3799dd5cd5c349224c19198a6bffd203bd3e6431fb6bf571976c2a1c0d3d1d07ceb9cb272206f06794c52595c4ec8d5d57d3
7
- data.tar.gz: a903325535c6c2e98b95c4e54cb51f7bbd7123b40dfb2b9143fc9d7a392290230f1bb026c7bd30a669c8f981286ef56acfe0a2bf3751ea9cce5a4d663e160d61
6
+ metadata.gz: 3ccb6cef3322fcd1c0efb1439ddaf756e631113fbc7544218d10d6f71d08ca2ad80cf08b029ae4145e6916dcefc9ee3683124567bb952b02bf70793cc794616b
7
+ data.tar.gz: 2755ec9d8c2bf041459be7292983103c880f032e5e1e315ce2da2cc97ff945bbfb9f4083259a0c88ec22df8cd0301282c8ea376d63371a438ad58677b7f3d9e6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lighstorm (0.0.9)
4
+ lighstorm (0.0.11)
5
5
  dotenv (~> 2.8, >= 2.8.1)
6
6
  lnd-client (~> 0.0.5)
7
7
  zache (~> 0.12.0)
@@ -47,7 +47,7 @@ GEM
47
47
  rspec-expectations (3.12.2)
48
48
  diff-lcs (>= 1.2.0, < 2.0)
49
49
  rspec-support (~> 3.12.0)
50
- rspec-mocks (3.12.3)
50
+ rspec-mocks (3.12.4)
51
51
  diff-lcs (>= 1.2.0, < 2.0)
52
52
  rspec-support (~> 3.12.0)
53
53
  rspec-support (3.12.0)
data/README.md CHANGED
@@ -34,7 +34,7 @@ Although it tries to stay close to [Lightning's terminologies](https://docs.ligh
34
34
  Add to your `Gemfile`:
35
35
 
36
36
  ```ruby
37
- gem 'lighstorm', '~> 0.0.9'
37
+ gem 'lighstorm', '~> 0.0.11'
38
38
  ```
39
39
 
40
40
  ```ruby
@@ -46,15 +46,22 @@ Lighstorm.config!(
46
46
  macaroon_path: '/lnd/data/chain/bitcoin/mainnet/admin.macaroon',
47
47
  )
48
48
 
49
- puts Lighstorm.version # => 0.0.9
49
+ puts Lighstorm.version # => 0.0.11
50
50
 
51
51
  Lighstorm::Node.myself.alias # => icebaker/old-stone
52
52
 
53
53
  Lighstorm::Invoice.create(
54
- description: 'Coffee', millisatoshis: 1_000,
54
+ description: 'Coffee',
55
+ amount: { millisatoshis: 1_000 },
55
56
  payable: 'once'
56
57
  )
57
58
 
59
+ Lighstorm::Invoice.decode('lnbc20m1pv...qqdhhwkj').pay
60
+
61
+ Lighstorm::Invoice.decode('lnbc20m1pv...qqdhhwkj').pay(
62
+ fee: { maximum: { millisatoshis: 1000 } }
63
+ )
64
+
58
65
  Lighstorm::Satoshis.new(
59
66
  millisatoshis: 75_621_650
60
67
  ).satoshis # => 75_621
data/adapters/invoice.rb CHANGED
@@ -18,7 +18,7 @@ module Lighstorm
18
18
  }
19
19
  end
20
20
 
21
- def self.decode_pay_req(grpc, request_code = nil)
21
+ def self.decode_pay_req(grpc, code = nil)
22
22
  adapted = {
23
23
  _source: :decode_pay_req,
24
24
  _key: Digest::SHA256.hexdigest(
@@ -43,7 +43,7 @@ module Lighstorm
43
43
  }
44
44
  }
45
45
 
46
- adapted[:code] = request_code unless request_code.nil?
46
+ adapted[:code] = code unless code.nil?
47
47
 
48
48
  if grpc[:features].key?(30) && grpc[:features][30][:is_required]
49
49
  raise "unexpected feature[30] name #{grpc[:features][30][:name]}" if grpc[:features][30][:name] != 'amp'
@@ -16,7 +16,7 @@ module Lighstorm
16
16
  ).to_h
17
17
  end
18
18
 
19
- def self.prepare(payable:, expires_in:, description: nil, millisatoshis: nil)
19
+ def self.prepare(payable:, expires_in:, description: nil, amount: nil)
20
20
  request = {
21
21
  service: :lightning,
22
22
  method: :add_invoice,
@@ -28,7 +28,7 @@ module Lighstorm
28
28
  }
29
29
  }
30
30
 
31
- request[:params][:value_msat] = millisatoshis unless millisatoshis.nil?
31
+ request[:params][:value_msat] = amount[:millisatoshis] unless amount.nil?
32
32
 
33
33
  if payable.to_sym == :indefinitely
34
34
  request[:params][:is_amp] = true
@@ -55,10 +55,10 @@ module Lighstorm
55
55
  FindBySecretHash.model(data)
56
56
  end
57
57
 
58
- def self.perform(payable:, expires_in:, description: nil, millisatoshis: nil, preview: false, &vcr)
58
+ def self.perform(payable:, expires_in:, description: nil, amount: nil, preview: false, &vcr)
59
59
  grpc_request = prepare(
60
60
  description: description,
61
- millisatoshis: millisatoshis,
61
+ amount: amount,
62
62
  expires_in: expires_in,
63
63
  payable: payable
64
64
  )
@@ -18,8 +18,8 @@ module Lighstorm
18
18
  Payment::Pay.dispatch(grpc_request, &vcr)
19
19
  end
20
20
 
21
- def self.fetch(request_code, &vcr)
22
- Payment::Pay.fetch(request_code, &vcr)
21
+ def self.fetch(code, &vcr)
22
+ Payment::Pay.fetch(code, &vcr)
23
23
  end
24
24
 
25
25
  def self.adapt(data, node_get_info)
@@ -30,19 +30,23 @@ module Lighstorm
30
30
  Payment::Pay.model(data)
31
31
  end
32
32
 
33
- def self.prepare(request_code:, times_out_in:, millisatoshis: nil, message: nil)
33
+ def self.prepare(code:, times_out_in:, amount: nil, fee: nil, message: nil)
34
34
  request = {
35
35
  service: :router,
36
36
  method: :send_payment_v2,
37
37
  params: {
38
- payment_request: request_code,
38
+ payment_request: code,
39
39
  timeout_seconds: Helpers::TimeExpression.seconds(times_out_in),
40
40
  allow_self_payment: true,
41
41
  dest_custom_records: {}
42
42
  }
43
43
  }
44
44
 
45
- request[:params][:amt_msat] = millisatoshis unless millisatoshis.nil?
45
+ request[:params][:amt_msat] = amount[:millisatoshis] unless amount.nil?
46
+
47
+ unless fee.nil? || fee[:maximum].nil? || fee[:maximum][:millisatoshis].nil?
48
+ request[:params][:fee_limit_msat] = fee[:maximum][:millisatoshis]
49
+ end
46
50
 
47
51
  if !message.nil? && !message.empty?
48
52
  # https://github.com/satoshisstream/satoshis.stream/blob/main/TLV_registry.md
@@ -55,11 +59,15 @@ module Lighstorm
55
59
  end
56
60
 
57
61
  def self.perform(
58
- times_out_in:, request_code:, millisatoshis: nil, message: nil, preview: false, &vcr
62
+ times_out_in:, code:,
63
+ amount: nil, fee: nil,
64
+ message: nil,
65
+ preview: false, &vcr
59
66
  )
60
67
  grpc_request = prepare(
61
- request_code: request_code,
62
- millisatoshis: millisatoshis,
68
+ code: code,
69
+ amount: amount,
70
+ fee: fee,
63
71
  message: message,
64
72
  times_out_in: times_out_in
65
73
  )
@@ -70,7 +78,7 @@ module Lighstorm
70
78
 
71
79
  Payment::Pay.raise_error_if_exists!(response)
72
80
 
73
- data = fetch(request_code, &vcr)
81
+ data = fetch(code, &vcr)
74
82
 
75
83
  adapted = adapt(response, data)
76
84
 
@@ -8,17 +8,17 @@ module Lighstorm
8
8
  module Controllers
9
9
  module Invoice
10
10
  module Decode
11
- def self.fetch(request_code)
11
+ def self.fetch(code)
12
12
  {
13
- _request_code: request_code,
14
- decode_pay_req: Ports::GRPC.lightning.decode_pay_req(pay_req: request_code).to_h
13
+ _code: code,
14
+ decode_pay_req: Ports::GRPC.lightning.decode_pay_req(pay_req: code).to_h
15
15
  }
16
16
  end
17
17
 
18
18
  def self.adapt(raw)
19
19
  {
20
20
  decode_pay_req: Lighstorm::Adapter::Invoice.decode_pay_req(
21
- raw[:decode_pay_req], raw[:_request_code]
21
+ raw[:decode_pay_req], raw[:_code]
22
22
  )
23
23
  }
24
24
  end
@@ -27,8 +27,8 @@ module Lighstorm
27
27
  adapted[:decode_pay_req]
28
28
  end
29
29
 
30
- def self.data(request_code, &vcr)
31
- raw = vcr.nil? ? fetch(request_code) : vcr.call(-> { fetch(request_code) })
30
+ def self.data(code, &vcr)
31
+ raw = vcr.nil? ? fetch(code) : vcr.call(-> { fetch(code) })
32
32
 
33
33
  adapted = adapt(raw)
34
34
 
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../ports/grpc'
4
+ require_relative '../../adapters/invoice'
5
+ require_relative '../../models/invoice'
6
+
7
+ module Lighstorm
8
+ module Controllers
9
+ module Invoice
10
+ module FindByCode
11
+ def self.fetch(code)
12
+ at = Time.now
13
+
14
+ decoded = Ports::GRPC.lightning.decode_pay_req(pay_req: code).to_h
15
+
16
+ { response: {
17
+ at: at,
18
+ decode_pay_req: decoded,
19
+ lookup_invoice: Ports::GRPC.lightning.lookup_invoice(r_hash_str: decoded[:payment_hash]).to_h
20
+ }, exception: nil }
21
+ rescue StandardError => e
22
+ { exception: e }
23
+ end
24
+
25
+ def self.adapt(raw)
26
+ raise 'missing at' if raw[:at].nil?
27
+
28
+ {
29
+ lookup_invoice: Lighstorm::Adapter::Invoice.lookup_invoice(
30
+ raw[:lookup_invoice],
31
+ raw[:at]
32
+ )
33
+ }
34
+ end
35
+
36
+ def self.transform(adapted)
37
+ adapted[:lookup_invoice][:known] = true
38
+ adapted[:lookup_invoice]
39
+ end
40
+
41
+ def self.data(code, &vcr)
42
+ raw = vcr.nil? ? fetch(code) : vcr.call(-> { fetch(code) })
43
+
44
+ raise_error_if_exists!(raw)
45
+
46
+ adapted = adapt(raw[:response])
47
+
48
+ transform(adapted)
49
+ end
50
+
51
+ def self.model(data)
52
+ Lighstorm::Models::Invoice.new(data)
53
+ end
54
+
55
+ def self.raise_error_if_exists!(response)
56
+ return if response[:exception].nil?
57
+
58
+ if response[:exception].is_a?(GRPC::NotFound)
59
+ raise NoInvoiceFoundError.new(
60
+ "Invoice not found. Try using Invoice.decode if you don't own the invoice.",
61
+ grpc: response[:exception]
62
+ )
63
+ end
64
+
65
+ raise LighstormError.new(grpc: response[:exception])
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -9,10 +9,12 @@ module Lighstorm
9
9
  module Invoice
10
10
  module FindBySecretHash
11
11
  def self.fetch(secret_hash)
12
- {
12
+ { response: {
13
13
  at: Time.now,
14
14
  lookup_invoice: Ports::GRPC.lightning.lookup_invoice(r_hash_str: secret_hash).to_h
15
- }
15
+ }, exception: nil }
16
+ rescue StandardError => e
17
+ { exception: e }
16
18
  end
17
19
 
18
20
  def self.adapt(raw)
@@ -34,7 +36,7 @@ module Lighstorm
34
36
  def self.data(secret_hash, &vcr)
35
37
  raw = vcr.nil? ? fetch(secret_hash) : vcr.call(-> { fetch(secret_hash) })
36
38
 
37
- adapted = adapt(raw)
39
+ adapted = adapt(raw[:response])
38
40
 
39
41
  transform(adapted)
40
42
  end
@@ -3,6 +3,7 @@
3
3
  require_relative './invoice/all'
4
4
  require_relative './invoice/decode'
5
5
  require_relative './invoice/find_by_secret_hash'
6
+ require_relative './invoice/find_by_code'
6
7
  require_relative './invoice/actions/create'
7
8
 
8
9
  module Lighstorm
@@ -20,17 +21,21 @@ module Lighstorm
20
21
  All.model(All.data).last
21
22
  end
22
23
 
23
- def self.find_by_secret_hash(secret_hash)
24
- FindBySecretHash.model(FindBySecretHash.data(secret_hash))
24
+ def self.find_by_secret_hash(secret_hash, &vcr)
25
+ FindBySecretHash.model(FindBySecretHash.data(secret_hash, &vcr))
25
26
  end
26
27
 
27
- def self.decode(request_code, &vcr)
28
- Decode.model(Decode.data(request_code, &vcr))
28
+ def self.find_by_code(code, &vcr)
29
+ FindByCode.model(FindByCode.data(code, &vcr))
30
+ end
31
+
32
+ def self.decode(code, &vcr)
33
+ Decode.model(Decode.data(code, &vcr))
29
34
  end
30
35
 
31
36
  def self.create(
32
37
  payable:,
33
- description: nil, millisatoshis: nil,
38
+ description: nil, amount: nil,
34
39
  # Lightning Invoice Expiration: UX Considerations
35
40
  # https://d.elor.me/2022/01/lightning-invoice-expiration-ux-considerations/
36
41
  expires_in: { hours: 24 },
@@ -39,7 +44,7 @@ module Lighstorm
39
44
  Create.perform(
40
45
  payable: payable,
41
46
  description: description,
42
- millisatoshis: millisatoshis,
47
+ amount: amount,
43
48
  expires_in: expires_in,
44
49
  preview: preview,
45
50
  &vcr
@@ -34,7 +34,7 @@ module Lighstorm
34
34
  Payment::Pay.model(data)
35
35
  end
36
36
 
37
- def self.prepare(public_key:, millisatoshis:, times_out_in:, secret:, through:, message: nil)
37
+ def self.prepare(public_key:, amount:, times_out_in:, secret:, through:, fee: nil, message: nil)
38
38
  # Appreciation note for people that suffered in the past and shared
39
39
  # their knowledge, so we don't have to struggle the same:
40
40
  # - https://github.com/lightningnetwork/lnd/discussions/6357
@@ -46,7 +46,7 @@ module Lighstorm
46
46
  method: :send_payment_v2,
47
47
  params: {
48
48
  dest: [public_key].pack('H*'),
49
- amt_msat: millisatoshis,
49
+ amt_msat: amount[:millisatoshis],
50
50
  timeout_seconds: Helpers::TimeExpression.seconds(times_out_in),
51
51
  allow_self_payment: true,
52
52
  dest_custom_records: {}
@@ -58,6 +58,10 @@ module Lighstorm
58
58
  request[:params][:dest_custom_records][34_349_334] = message
59
59
  end
60
60
 
61
+ unless fee.nil? || fee[:maximum].nil? || fee[:maximum][:millisatoshis].nil?
62
+ request[:params][:fee_limit_msat] = fee[:maximum][:millisatoshis]
63
+ end
64
+
61
65
  if through.to_sym == :keysend
62
66
  request[:params][:payment_hash] = [secret[:hash]].pack('H*')
63
67
  request[:params][:dest_custom_records][5_482_373_484] = [secret[:preimage]].pack('H*')
@@ -71,8 +75,8 @@ module Lighstorm
71
75
  end
72
76
 
73
77
  def self.perform(
74
- public_key:, millisatoshis:, through:,
75
- times_out_in:,
78
+ public_key:, amount:, through:,
79
+ times_out_in:, fee: nil,
76
80
  message: nil, secret: nil,
77
81
  preview: false, &vcr
78
82
  )
@@ -80,7 +84,8 @@ module Lighstorm
80
84
 
81
85
  grpc_request = prepare(
82
86
  public_key: public_key,
83
- millisatoshis: millisatoshis,
87
+ amount: amount,
88
+ fee: fee,
84
89
  through: through,
85
90
  times_out_in: times_out_in,
86
91
  secret: secret,
@@ -30,15 +30,15 @@ module Lighstorm
30
30
  vcr.nil? ? call(grpc_request) : vcr.call(-> { call(grpc_request) }, :dispatch)
31
31
  end
32
32
 
33
- def self.fetch_all(request_code)
33
+ def self.fetch_all(code)
34
34
  {
35
- invoice_decode: request_code.nil? ? nil : Invoice::Decode.data(request_code),
35
+ invoice_decode: code.nil? ? nil : Invoice::Decode.data(code),
36
36
  node_myself: Node::Myself.data
37
37
  }
38
38
  end
39
39
 
40
- def self.fetch(request_code = nil, &vcr)
41
- raw = vcr.nil? ? fetch_all(request_code) : vcr.call(-> { fetch_all(request_code) })
40
+ def self.fetch(code = nil, &vcr)
41
+ raw = vcr.nil? ? fetch_all(code) : vcr.call(-> { fetch_all(code) })
42
42
  end
43
43
 
44
44
  def self.adapt(grpc_data, fetch_data)
@@ -12,7 +12,7 @@ module Lighstorm
12
12
  module Controllers
13
13
  module Payment
14
14
  module All
15
- def self.fetch(purpose: nil, limit: nil, fetch: {})
15
+ def self.fetch(purpose: nil, invoice_code: nil, secret_hash: nil, limit: nil, fetch: {})
16
16
  at = Time.now
17
17
 
18
18
  grpc = Ports::GRPC.session
@@ -31,6 +31,10 @@ module Lighstorm
31
31
  response.payments.each do |payment|
32
32
  payment = payment.to_h
33
33
 
34
+ next unless invoice_code.nil? || payment[:payment_request] == invoice_code
35
+
36
+ next unless secret_hash.nil? || payment[:payment_hash] == secret_hash
37
+
34
38
  payment_purpose = Adapter::Purpose.list_payments(payment, get_info)
35
39
 
36
40
  case purpose
@@ -108,9 +112,13 @@ module Lighstorm
108
112
 
109
113
  next if fetch[:get_node_info] == false || data[:get_node_info][hop[:pub_key]]
110
114
 
111
- data[:get_node_info][hop[:pub_key]] = grpc.lightning.get_node_info(
112
- pub_key: hop[:pub_key]
113
- ).to_h
115
+ begin
116
+ data[:get_node_info][hop[:pub_key]] = grpc.lightning.get_node_info(
117
+ pub_key: hop[:pub_key]
118
+ ).to_h
119
+ rescue StandardError => e
120
+ data[:get_node_info][hop[:pub_key]] = { _error: e }
121
+ end
114
122
  end
115
123
  end
116
124
  end
@@ -151,24 +159,36 @@ module Lighstorm
151
159
  end
152
160
 
153
161
  unless fetch[:get_node_info] == false || data[:get_node_info][channel[:node1_pub]]
154
- data[:get_node_info][channel[:node1_pub]] = grpc.lightning.get_node_info(
155
- pub_key: channel[:node1_pub]
156
- ).to_h
162
+ begin
163
+ data[:get_node_info][channel[:node1_pub]] = grpc.lightning.get_node_info(
164
+ pub_key: channel[:node1_pub]
165
+ ).to_h
166
+ rescue StandardError => e
167
+ data[:get_node_info][channel[:node1_pub]] = { _error: e }
168
+ end
157
169
  end
158
170
 
159
171
  next if fetch[:get_node_info] == false || data[:get_node_info][channel[:node2_pub]]
160
172
 
161
- data[:get_node_info][channel[:node2_pub]] = grpc.lightning.get_node_info(
162
- pub_key: channel[:node2_pub]
163
- ).to_h
173
+ begin
174
+ data[:get_node_info][channel[:node2_pub]] = grpc.lightning.get_node_info(
175
+ pub_key: channel[:node2_pub]
176
+ ).to_h
177
+ rescue StandardError => e
178
+ data[:get_node_info][channel[:node2_pub]] = { _error: e }
179
+ end
164
180
  end
165
181
 
166
182
  data[:list_channels].each_value do |channel|
167
183
  next if fetch[:get_node_info] == false || data[:get_node_info][channel[:remote_pubkey]]
168
184
 
169
- data[:get_node_info][channel[:remote_pubkey]] = grpc.lightning.get_node_info(
170
- pub_key: channel[:remote_pubkey]
171
- ).to_h
185
+ begin
186
+ data[:get_node_info][channel[:remote_pubkey]] = grpc.lightning.get_node_info(
187
+ pub_key: channel[:remote_pubkey]
188
+ ).to_h
189
+ rescue StandardError => e
190
+ data[:get_node_info][channel[:remote_pubkey]] = { _error: e }
191
+ end
172
192
  end
173
193
 
174
194
  data[:@meta] = { calls: grpc.calls }
@@ -223,6 +243,8 @@ module Lighstorm
223
243
  end
224
244
 
225
245
  raw[:get_node_info].each_key do |key|
246
+ next if raw[:get_node_info][key][:_error]
247
+
226
248
  adapted[:get_node_info][key] = Lighstorm::Adapter::Node.get_node_info(
227
249
  raw[:get_node_info][key]
228
250
  )
@@ -373,11 +395,22 @@ module Lighstorm
373
395
  list_payments
374
396
  end
375
397
 
376
- def self.data(purpose: nil, limit: nil, fetch: {}, &vcr)
398
+ def self.data(
399
+ purpose: nil, invoice_code: nil, secret_hash: nil, limit: nil,
400
+ fetch: {}, &vcr
401
+ )
377
402
  raw = if vcr.nil?
378
- self.fetch(purpose: purpose, limit: limit, fetch: fetch)
403
+ self.fetch(
404
+ purpose: purpose, invoice_code: invoice_code, secret_hash: secret_hash,
405
+ limit: limit, fetch: fetch
406
+ )
379
407
  else
380
- vcr.call(-> { self.fetch(purpose: purpose, limit: limit, fetch: fetch) })
408
+ vcr.call(lambda {
409
+ self.fetch(
410
+ purpose: purpose, invoice_code: invoice_code, secret_hash: secret_hash,
411
+ limit: limit, fetch: fetch
412
+ )
413
+ })
381
414
  end
382
415
 
383
416
  adapted = adapt(raw)
@@ -16,6 +16,14 @@ module Lighstorm
16
16
  def self.last(purpose: nil, fetch: {})
17
17
  All.model(All.data(purpose: purpose, fetch: fetch)).last
18
18
  end
19
+
20
+ def self.find_by_secret_hash(secret_hash, &vcr)
21
+ All.model(All.data(secret_hash: secret_hash, &vcr)).first
22
+ end
23
+
24
+ def self.find_by_invoice_code(invoice_code, &vcr)
25
+ All.model(All.data(invoice_code: invoice_code, &vcr)).first
26
+ end
19
27
  end
20
28
  end
21
29
  end
data/docs/README.md CHANGED
@@ -27,7 +27,7 @@ Lighstorm::Channel.mine.first.myself.node.alias
27
27
  Add to your `Gemfile`:
28
28
 
29
29
  ```ruby
30
- gem 'lighstorm', '~> 0.0.9'
30
+ gem 'lighstorm', '~> 0.0.11'
31
31
  ```
32
32
 
33
33
  Run `bundle install`.
@@ -60,23 +60,25 @@ Lighstorm.config!(
60
60
  ```ruby
61
61
  require 'lighstorm'
62
62
 
63
- puts Lighstorm.version # => 0.0.9
63
+ puts Lighstorm.version # => 0.0.11
64
64
 
65
65
  Lighstorm::Invoice.create(
66
- description: 'Coffee', millisatoshis: 1000, payable: 'once'
66
+ description: 'Coffee', amount: { millisatoshis: 1000 }, payable: 'once'
67
67
  )
68
68
 
69
- Lighstorm::Invoice.decode(
70
- 'lnbc20m1pv...qqdhhwkj'
71
- ).pay
69
+ Lighstorm::Invoice.decode('lnbc20m1pv...qqdhhwkj').pay
70
+
71
+ Lighstorm::Invoice.decode('lnbc20m1pv...qqdhhwkj').pay(
72
+ fee: { maximum: { millisatoshis: 1000 } }
73
+ )
72
74
 
73
75
  Lighstorm::Node.find_by_public_key(
74
76
  '02d3c80335a8ccb2ed364c06875f32240f36f7edb37d80f8dbe321b4c364b6e997'
75
- ).pay(millisatoshis: 1000)
77
+ ).pay(amount: { millisatoshis: 1000 })
76
78
 
77
79
  Lighstorm::Node.find_by_public_key(
78
80
  '02d3c80335a8ccb2ed364c06875f32240f36f7edb37d80f8dbe321b4c364b6e997'
79
- ).send_message('Hello from Lighstorm!', millisatoshis: 1000)
81
+ ).send_message('Hello from Lighstorm!', amount: { millisatoshis: 1000 })
80
82
 
81
83
  Lighstorm::Node.myself.alias # => icebaker/old-stone
82
84
  Lighstorm::Node.myself.public_key # => 02d3...e997
@@ -264,23 +266,25 @@ destination = Lighstorm::Node.find_by_public_key(
264
266
 
265
267
  destination.alias # => 'icebaker/old-stone'
266
268
 
267
- destination.pay(millisatoshis: 1000)
269
+ destination.pay(amount: { millisatoshis: 1000 })
268
270
 
269
271
  destination.pay(
270
- millisatoshis: 1500,
272
+ amount: { millisatoshis: 1500 },
273
+ fee: { maximum: { millisatoshis: 1000 } },
271
274
  message: 'Hello from Lighstorm!',
272
275
  through: 'amp',
273
276
  times_out_in: { seconds: 5 }
274
277
  )
275
278
 
276
279
  destination.pay(
277
- millisatoshis: 1200,
280
+ amount: { millisatoshis: 1200 },
281
+ fee: { maximum: { millisatoshis: 1000 } },
278
282
  message: 'Hello from Lighstorm!',
279
283
  through: 'keysend',
280
284
  times_out_in: { seconds: 5 }
281
285
  )
282
286
 
283
- action = destination.pay(millisatoshis: 1000)
287
+ action = destination.pay(amount: { millisatoshis: 1000 })
284
288
  action.result.fee.millisatoshis
285
289
  ```
286
290
 
@@ -295,23 +299,31 @@ destination = Lighstorm::Node.find_by_public_key(
295
299
 
296
300
  destination.alias # => 'icebaker/old-stone'
297
301
 
298
- destination.send_message('Hello from Lighstorm!', millisatoshis: 1000)
302
+ destination.send_message(
303
+ 'Hello from Lighstorm!',
304
+ amount: { millisatoshis: 1000 }
305
+ )
299
306
 
300
307
  destination.send_message(
301
308
  'Hello from Lighstorm!',
302
- millisatoshis: 1000,
309
+ amount: { millisatoshis: 1000 },
310
+ fee: { maximum: { millisatoshis: 1000 } },
303
311
  through: 'amp',
304
312
  times_out_in: { seconds: 5 }
305
313
  )
306
314
 
307
315
  destination.send_message(
308
316
  'Hello from Lighstorm!',
309
- millisatoshis: 1000,
317
+ amount: { millisatoshis: 1000 },
318
+ fee: { maximum: { millisatoshis: 1000 } },
310
319
  through: 'keysend',
311
320
  times_out_in: { seconds: 5 }
312
321
  )
313
322
 
314
- action = destination.send_message('Hello from Lighstorm!', millisatoshis: 1000)
323
+ action = destination.send_message(
324
+ 'Hello from Lighstorm!',
325
+ amount: { millisatoshis: 1000 }
326
+ )
315
327
  action.result.fee.millisatoshis
316
328
  ```
317
329
 
@@ -450,6 +462,12 @@ Lighstorm::Invoice.find_by_secret_hash(
450
462
  '1d438b8100518c9fba0a607e3317d6b36f74ceef3a6591836eb2f679c6853501'
451
463
  )
452
464
 
465
+ invoice = Lighstorm::Invoice.find_by_code('lnbc20n1pj...0eqps7h0k9')
466
+
467
+ invoice.secret.valid_proof?(
468
+ 'c504f73f83e3772b802844b54021e44e071c03011eeda476b198f7a093bcb09e'
469
+ ) # => true
470
+
453
471
  # _key is helpful for reactive javascript frameworks.
454
472
  # Please don't consider it as a unique identifier
455
473
  # for the item. Instead, use it as a volatile key for
@@ -485,12 +503,12 @@ invoice.secret.hash
485
503
  # 'preview' let you check the expected operation
486
504
  # before actually performing it for debug purposes
487
505
  preview = Lighstorm::Invoice.create(
488
- description: 'Coffee', millisatoshis: 1000,
506
+ description: 'Coffee', amount: { millisatoshis: 1000 },
489
507
  payable: 'once', preview: true
490
508
  )
491
509
 
492
510
  action = Lighstorm::Invoice.create(
493
- description: 'Coffee', millisatoshis: 1000,
511
+ description: 'Coffee', amount: { millisatoshis: 1000 },
494
512
  payable: 'once', expires_in: { minutes: 5 }
495
513
  )
496
514
 
@@ -504,7 +522,7 @@ action = Lighstorm::Invoice.create(
504
522
  )
505
523
 
506
524
  action = Lighstorm::Invoice.create(
507
- description: 'Concert Ticket', millisatoshis: 500000000,
525
+ description: 'Concert Ticket', amount: { millisatoshis: 500000000 },
508
526
  payable: 'indefinitely', expires_in: { days: 5 }
509
527
  )
510
528
 
@@ -514,6 +532,19 @@ action.response
514
532
  invoice = action.result
515
533
  ```
516
534
 
535
+ ### Proof of Payment
536
+
537
+ [Making Payments](https://docs.lightning.engineering/the-lightning-network/multihop-payments)
538
+
539
+
540
+ ```ruby
541
+ invoice = Lighstorm::Invoice.find_by_code('lnbc20n1pj...0eqps7h0k9')
542
+
543
+ invoice.secret.valid_proof?(
544
+ 'c504f73f83e3772b802844b54021e44e071c03011eeda476b198f7a093bcb09e'
545
+ ) # => true
546
+ ```
547
+
517
548
  ### Pay
518
549
 
519
550
  [Understanding Lightning Invoices](https://docs.lightning.engineering/the-lightning-network/payment-lifecycle/understanding-lightning-invoices)
@@ -535,6 +566,8 @@ payment = action.result
535
566
  payment.at
536
567
  payment.state
537
568
 
569
+ payment.secret.proof
570
+
538
571
  payment.amount.millisatoshis
539
572
  payment.fee.millisatoshis
540
573
  payment.fee.parts_per_million(
@@ -547,7 +580,8 @@ payment.hops.size
547
580
 
548
581
  ```ruby
549
582
  invoice.pay(
550
- millisatoshis: 1500,
583
+ amount: { millisatoshis: 1500 },
584
+ fee: { maximum: { millisatoshis: 1000 } },
551
585
  message: 'here we go',
552
586
  times_out_in: { seconds: 5 }
553
587
  )
@@ -568,7 +602,7 @@ end
568
602
 
569
603
  ```ruby
570
604
  begin
571
- invoice.pay(millisatoshis: 1000)
605
+ invoice.pay(amount: { millisatoshis: 1000 })
572
606
  rescue AmountForNonZeroError => error
573
607
  error.message # 'Millisatoshis must not be specified...'
574
608
  error.grpc.class # GRPC::Unknown
@@ -609,6 +643,7 @@ rescue PaymentError => error
609
643
  error.result
610
644
  end
611
645
  ```
646
+
612
647
  ## Payment
613
648
 
614
649
  [![This is an image representing Payment as a graph.](https://raw.githubusercontent.com/icebaker/assets/main/lighstorm/graph-payment.png)](https://raw.githubusercontent.com/icebaker/assets/main/lighstorm/graph-payment.png)
@@ -629,6 +664,12 @@ Lighstorm::Payment.all(limit: 10, purpose: 'rebalance')
629
664
  # 'self-payment', 'peer-to-peer',
630
665
  # 'rebalance', 'payment'
631
666
 
667
+ Lighstorm::Payment.find_by_invoice_code('lnbc20n1pj...0eqps7h0k9')
668
+
669
+ Lighstorm::Payment.find_by_secret_hash(
670
+ '1d438b8100518c9fba0a607e3317d6b36f74ceef3a6591836eb2f679c6853501'
671
+ )
672
+
632
673
  # _key is helpful for reactive javascript frameworks.
633
674
  # Please don't consider it as a unique identifier
634
675
  # for the item. Instead, use it as a volatile key for
@@ -658,6 +699,7 @@ payment.purpose
658
699
  # https://docs.lightning.engineering/the-lightning-network/multihop-payments
659
700
  payment.secret.preimage
660
701
  payment.secret.hash
702
+ payment.secret.proof
661
703
 
662
704
  payment.invoice.created_at
663
705
  payment.invoice.expires_at
@@ -734,6 +776,18 @@ payment.hops[0].channel.entry.public_key
734
776
  payment.hops[0].channel.entry.alias
735
777
  payment.hops[0].channel.entry.color
736
778
  ```
779
+
780
+ ### Proof of Payment
781
+
782
+ [Making Payments](https://docs.lightning.engineering/the-lightning-network/multihop-payments)
783
+
784
+ ```ruby
785
+ payment = Lighstorm::Invoice.decode('lnbc20m1pv...qqdhhwkj').pay.result
786
+
787
+ payment.secret.proof
788
+ # => 'c504f73f83e3772b802844b54021e44e071c03011eeda476b198f7a093bcb09e'
789
+ ```
790
+
737
791
  ### Performance
738
792
  Avoid fetching data that you don't need:
739
793
  ```ruby
@@ -990,7 +1044,7 @@ gem 'lighstorm', path: '/home/user/lighstorm'
990
1044
  # demo.rb
991
1045
  require 'lighstorm'
992
1046
 
993
- puts Lighstorm.version # => 0.0.9
1047
+ puts Lighstorm.version # => 0.0.11
994
1048
  ```
995
1049
 
996
1050
  ```sh
@@ -1050,13 +1104,15 @@ The downside is that we can't [lazy-load](https://en.wikipedia.org/wiki/Lazy_loa
1050
1104
  To perform an _action_, like creating an Invoice, you:
1051
1105
  ```ruby
1052
1106
  Lighstorm::Invoice.create(
1053
- description: 'Coffee', millisatoshis: 1000
1107
+ description: 'Coffee', amount: { millisatoshis: 1000 }
1054
1108
  )
1055
1109
  ```
1056
1110
 
1057
1111
  Internally, what's happening:
1058
1112
  ```ruby
1059
- action = Lighstorm::Invoice.create(description: 'Coffee', millisatoshis: 1000)
1113
+ action = Lighstorm::Invoice.create(
1114
+ description: 'Coffee', amount: { millisatoshis: 1000 }
1115
+ )
1060
1116
 
1061
1117
  request = Controllers::Invoice::Create.prepare(params) # pure
1062
1118
  response = Controllers::Invoice::Create.dispatch(request) # side effect
@@ -1225,13 +1281,13 @@ gem build lighstorm.gemspec
1225
1281
 
1226
1282
  gem signin
1227
1283
 
1228
- gem push lighstorm-0.0.9.gem
1284
+ gem push lighstorm-0.0.11.gem
1229
1285
  ```
1230
1286
 
1231
1287
  _________________
1232
1288
 
1233
1289
  <center>
1234
- lighstorm 0.0.9
1290
+ lighstorm 0.0.11
1235
1291
  |
1236
1292
  <a href="https://github.com/icebaker/lighstorm" rel="noopener noreferrer" target="_blank">GitHub</a>
1237
1293
  |
data/docs/_coverpage.md CHANGED
@@ -8,7 +8,7 @@
8
8
  - Built for maximum **reliability**.
9
9
  - Optimized for programmer **happiness**.
10
10
 
11
- 0.0.9
11
+ 0.0.11
12
12
 
13
13
  ⚠️ _Warning: Early-stage, breaking changes are expected._
14
14
 
data/docs/index.html CHANGED
@@ -18,7 +18,7 @@
18
18
  <script>
19
19
  window.$docsify = {
20
20
  coverpage: true,
21
- name: 'Lighstorm 0.0.9',
21
+ name: 'Lighstorm 0.0.11',
22
22
  repo: 'https://github.com/icebaker/lighstorm'
23
23
  }
24
24
  </script>
data/models/errors.rb CHANGED
@@ -2,7 +2,21 @@
2
2
 
3
3
  module Lighstorm
4
4
  module Errors
5
- class LighstormError < StandardError; end
5
+ class LighstormError < StandardError
6
+ attr_reader :grpc
7
+
8
+ def initialize(message = nil, grpc: nil)
9
+ super(message)
10
+ @grpc = grpc
11
+ end
12
+
13
+ def to_h
14
+ output = { class: self.class, message: message }
15
+ output[:grpc] = grpc.message unless grpc.nil?
16
+
17
+ output
18
+ end
19
+ end
6
20
 
7
21
  class ToDoError < LighstormError; end
8
22
 
@@ -19,6 +33,7 @@ module Lighstorm
19
33
  class OperationNotAllowedError < LighstormError; end
20
34
  class UnexpectedNumberOfHTLCsError < LighstormError; end
21
35
  class UnknownChannelError < LighstormError; end
36
+ class NoInvoiceFoundError < LighstormError; end
22
37
 
23
38
  class InvoiceMayHaveMultiplePaymentsError < LighstormError; end
24
39
 
data/models/invoice.rb CHANGED
@@ -84,7 +84,8 @@ module Lighstorm
84
84
  end
85
85
 
86
86
  def pay(
87
- millisatoshis: nil, message: nil, route: nil,
87
+ amount: nil, message: nil, route: nil,
88
+ fee: nil,
88
89
  times_out_in: { seconds: 5 },
89
90
  preview: false
90
91
  )
@@ -92,8 +93,9 @@ module Lighstorm
92
93
  Controllers::Invoice::PayThroughRoute.perform(self, route: route, preview: preview)
93
94
  else
94
95
  Controllers::Invoice::Pay.perform(
95
- request_code: code,
96
- millisatoshis: millisatoshis,
96
+ code: code,
97
+ amount: amount,
98
+ fee: fee,
97
99
  message: message,
98
100
  times_out_in: times_out_in,
99
101
  preview: preview
data/models/nodes/node.rb CHANGED
@@ -100,13 +100,14 @@ module Lighstorm
100
100
  end
101
101
 
102
102
  def send_message(
103
- message, millisatoshis:, secret: nil,
103
+ message, amount:, fee: nil, secret: nil,
104
104
  times_out_in: { seconds: 5 }, through: 'amp',
105
105
  preview: false
106
106
  )
107
107
  pay(
108
108
  message: message,
109
- millisatoshis: millisatoshis,
109
+ amount: amount,
110
+ fee: fee,
110
111
  secret: secret,
111
112
  times_out_in: times_out_in,
112
113
  through: through,
@@ -115,13 +116,15 @@ module Lighstorm
115
116
  end
116
117
 
117
118
  def pay(
118
- millisatoshis:, message: nil, secret: nil,
119
+ amount:, message: nil, secret: nil,
120
+ fee: nil,
119
121
  times_out_in: { seconds: 5 }, through: 'amp',
120
122
  preview: false
121
123
  )
122
124
  Controllers::Node::Pay.perform(
123
125
  public_key: public_key,
124
- millisatoshis: millisatoshis,
126
+ amount: amount,
127
+ fee: fee,
125
128
  through: through,
126
129
  secret: secret,
127
130
  message: message,
data/models/secret.rb CHANGED
@@ -7,9 +7,15 @@ module Lighstorm
7
7
  class Secret
8
8
  attr_reader :preimage, :hash
9
9
 
10
- def self.create
10
+ def self.generate
11
11
  data = { preimage: SecureRandom.hex(32) }
12
12
  data[:hash] = Digest::SHA256.hexdigest([data[:preimage]].pack('H*'))
13
+ data
14
+ end
15
+
16
+ def self.create(&vcr)
17
+ data = vcr.nil? ? generate : vcr.call(-> { generate })
18
+
13
19
  Secret.new(data)
14
20
  end
15
21
 
@@ -20,6 +26,14 @@ module Lighstorm
20
26
  @hash = data[:hash]
21
27
  end
22
28
 
29
+ def proof
30
+ @preimage
31
+ end
32
+
33
+ def valid_proof?(candidate_preimage)
34
+ candidate_preimage == preimage
35
+ end
36
+
23
37
  def to_h
24
38
  {
25
39
  preimage: preimage,
data/static/spec.rb CHANGED
@@ -4,7 +4,7 @@ module Lighstorm
4
4
  module Static
5
5
  SPEC = {
6
6
  name: 'lighstorm',
7
- version: '0.0.9',
7
+ version: '0.0.11',
8
8
  author: 'icebaker',
9
9
  summary: 'API for interacting with a Lightning Node.',
10
10
  description: 'Lighstorm is an opinionated abstraction layer on top of the lnd-client for interacting with a Lightning Node.',
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lighstorm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - icebaker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-11 00:00:00.000000000 Z
11
+ date: 2023-03-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dotenv
@@ -103,6 +103,7 @@ files:
103
103
  - controllers/invoice/actions/pay_through_route.rb
104
104
  - controllers/invoice/all.rb
105
105
  - controllers/invoice/decode.rb
106
+ - controllers/invoice/find_by_code.rb
106
107
  - controllers/invoice/find_by_secret_hash.rb
107
108
  - controllers/node.rb
108
109
  - controllers/node/actions/apply_gossip.rb