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 +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +10 -3
- data/adapters/invoice.rb +2 -2
- data/controllers/invoice/actions/create.rb +4 -4
- data/controllers/invoice/actions/pay.rb +17 -9
- data/controllers/invoice/decode.rb +6 -6
- data/controllers/invoice/find_by_code.rb +70 -0
- data/controllers/invoice/find_by_secret_hash.rb +5 -3
- data/controllers/invoice.rb +11 -6
- data/controllers/node/actions/pay.rb +10 -5
- data/controllers/payment/actions/pay.rb +4 -4
- data/controllers/payment/all.rb +49 -16
- data/controllers/payment.rb +8 -0
- data/docs/README.md +82 -26
- data/docs/_coverpage.md +1 -1
- data/docs/index.html +1 -1
- data/models/errors.rb +16 -1
- data/models/invoice.rb +5 -3
- data/models/nodes/node.rb +7 -4
- data/models/secret.rb +15 -1
- data/static/spec.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6072337300f3fd850fbca3ba5c7c804842c275d5f35fa288dfb83747fa0b1a56
|
4
|
+
data.tar.gz: 8a16d83cb96f0ed911ebd55e12707b20f0aac00a0acac8d176e544a68abad647
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
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.
|
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.
|
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',
|
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,
|
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] =
|
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,
|
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
|
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,
|
58
|
+
def self.perform(payable:, expires_in:, description: nil, amount: nil, preview: false, &vcr)
|
59
59
|
grpc_request = prepare(
|
60
60
|
description: description,
|
61
|
-
|
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(
|
22
|
-
Payment::Pay.fetch(
|
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(
|
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:
|
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
|
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:,
|
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
|
-
|
62
|
-
|
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(
|
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(
|
11
|
+
def self.fetch(code)
|
12
12
|
{
|
13
|
-
|
14
|
-
decode_pay_req: Ports::GRPC.lightning.decode_pay_req(pay_req:
|
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[:
|
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(
|
31
|
-
raw = vcr.nil? ? fetch(
|
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
|
data/controllers/invoice.rb
CHANGED
@@ -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.
|
28
|
-
|
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,
|
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
|
-
|
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:,
|
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:,
|
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
|
-
|
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(
|
33
|
+
def self.fetch_all(code)
|
34
34
|
{
|
35
|
-
invoice_decode:
|
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(
|
41
|
-
raw = vcr.nil? ? fetch_all(
|
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)
|
data/controllers/payment/all.rb
CHANGED
@@ -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
|
-
|
112
|
-
|
113
|
-
|
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
|
-
|
155
|
-
|
156
|
-
|
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
|
-
|
162
|
-
|
163
|
-
|
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
|
-
|
170
|
-
|
171
|
-
|
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(
|
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(
|
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(
|
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)
|
data/controllers/payment.rb
CHANGED
@@ -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.
|
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.
|
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
|
-
|
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(
|
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(
|
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.
|
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(
|
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.
|
1284
|
+
gem push lighstorm-0.0.11.gem
|
1229
1285
|
```
|
1230
1286
|
|
1231
1287
|
_________________
|
1232
1288
|
|
1233
1289
|
<center>
|
1234
|
-
lighstorm 0.0.
|
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
data/docs/index.html
CHANGED
data/models/errors.rb
CHANGED
@@ -2,7 +2,21 @@
|
|
2
2
|
|
3
3
|
module Lighstorm
|
4
4
|
module Errors
|
5
|
-
class LighstormError < StandardError
|
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
|
-
|
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
|
-
|
96
|
-
|
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,
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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.
|
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.
|
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
|
+
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
|