lighstorm 0.0.7 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.env.example +1 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +1 -0
- data/Gemfile +5 -3
- data/Gemfile.lock +15 -10
- data/README.md +4 -3
- data/Rakefile +11 -0
- data/adapters/edges/payment/purpose.rb +22 -11
- data/adapters/edges/payment.rb +51 -12
- data/adapters/invoice.rb +139 -17
- data/components/cache.rb +7 -2
- data/controllers/forward/group_by_channel.rb +1 -1
- data/controllers/invoice/actions/create.rb +22 -6
- data/controllers/invoice/actions/pay.rb +71 -13
- data/controllers/invoice/all.rb +16 -6
- data/controllers/invoice/decode.rb +44 -0
- data/controllers/invoice/find_by_secret_hash.rb +7 -1
- data/controllers/invoice.rb +17 -3
- data/controllers/node/actions/pay.rb +109 -0
- data/controllers/payment/actions/pay.rb +104 -0
- data/controllers/payment/all.rb +49 -16
- data/controllers/transaction/all.rb +54 -0
- data/controllers/transaction.rb +13 -0
- data/deleted.sh +1 -0
- data/docs/README.md +292 -49
- data/docs/_coverpage.md +1 -1
- data/docs/index.html +1 -1
- data/helpers/time_expression.rb +33 -0
- data/models/connections/payment_channel.rb +13 -8
- data/models/edges/channel.rb +1 -1
- data/models/edges/payment.rb +51 -20
- data/models/errors.rb +29 -1
- data/models/invoice.rb +67 -11
- data/models/nodes/node.rb +32 -0
- data/models/satoshis.rb +11 -3
- data/models/secret.rb +31 -0
- data/models/transaction.rb +42 -0
- data/ports/dsl/lighstorm.rb +2 -0
- data/static/cache.rb +14 -13
- data/static/spec.rb +1 -1
- metadata +12 -4
- data/adapters/payment_request.rb +0 -87
- data/models/payment_request.rb +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 551ffb5be38f96d6c0bb4f7b8fbde5763c623f0d100f0a1b34acb90a6074fb23
|
4
|
+
data.tar.gz: 59451d54f2ad6d45c95c7649ab0a048a4adeb7a15f1af08f133d8eaae107d9bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 54e1e6929a1f5dc67f319461d6fc3799dd5cd5c349224c19198a6bffd203bd3e6431fb6bf571976c2a1c0d3d1d07ceb9cb272206f06794c52595c4ec8d5d57d3
|
7
|
+
data.tar.gz: a903325535c6c2e98b95c4e54cb51f7bbd7123b40dfb2b9143fc9d7a392290230f1bb026c7bd30a669c8f981286ef56acfe0a2bf3751ea9cce5a4d663e160d61
|
data/.env.example
CHANGED
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
@@ -6,9 +6,11 @@ gemspec
|
|
6
6
|
|
7
7
|
group :test, :development do
|
8
8
|
gem 'babosa', '~> 2.0'
|
9
|
-
gem 'dotenv', '~> 2.8', '>= 2.8.1'
|
10
9
|
gem 'pry-byebug', '~> 3.10', '>= 3.10.1'
|
10
|
+
gem 'rainbow', '~> 3.1', '>= 3.1.1'
|
11
|
+
gem 'rake', '~> 13.0', '>= 13.0.6'
|
11
12
|
gem 'rspec', '~> 3.12'
|
12
|
-
gem 'rubocop', '~> 1.
|
13
|
-
gem 'rubocop-
|
13
|
+
gem 'rubocop', '~> 1.48'
|
14
|
+
gem 'rubocop-rake', '~> 0.6.0'
|
15
|
+
gem 'rubocop-rspec', '~> 2.19'
|
14
16
|
end
|
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.9)
|
5
5
|
dotenv (~> 2.8, >= 2.8.1)
|
6
6
|
lnd-client (~> 0.0.5)
|
7
7
|
zache (~> 0.12.0)
|
@@ -15,7 +15,7 @@ GEM
|
|
15
15
|
coderay (1.1.3)
|
16
16
|
diff-lcs (1.5.0)
|
17
17
|
dotenv (2.8.1)
|
18
|
-
google-protobuf (3.22.
|
18
|
+
google-protobuf (3.22.2-x86_64-linux)
|
19
19
|
googleapis-common-protos-types (1.5.0)
|
20
20
|
google-protobuf (~> 3.14)
|
21
21
|
grpc (1.52.0-x86_64-linux)
|
@@ -26,7 +26,7 @@ GEM
|
|
26
26
|
grpc (~> 1.52)
|
27
27
|
method_source (1.0.0)
|
28
28
|
parallel (1.22.1)
|
29
|
-
parser (3.2.1.
|
29
|
+
parser (3.2.1.1)
|
30
30
|
ast (~> 2.4.1)
|
31
31
|
pry (0.14.2)
|
32
32
|
coderay (~> 1.1)
|
@@ -35,6 +35,7 @@ GEM
|
|
35
35
|
byebug (~> 11.0)
|
36
36
|
pry (>= 0.13, < 0.15)
|
37
37
|
rainbow (3.1.1)
|
38
|
+
rake (13.0.6)
|
38
39
|
regexp_parser (2.7.0)
|
39
40
|
rexml (3.2.5)
|
40
41
|
rspec (3.12.0)
|
@@ -50,7 +51,7 @@ GEM
|
|
50
51
|
diff-lcs (>= 1.2.0, < 2.0)
|
51
52
|
rspec-support (~> 3.12.0)
|
52
53
|
rspec-support (3.12.0)
|
53
|
-
rubocop (1.
|
54
|
+
rubocop (1.48.0)
|
54
55
|
json (~> 2.3)
|
55
56
|
parallel (~> 1.10)
|
56
57
|
parser (>= 3.2.0.0)
|
@@ -60,14 +61,16 @@ GEM
|
|
60
61
|
rubocop-ast (>= 1.26.0, < 2.0)
|
61
62
|
ruby-progressbar (~> 1.7)
|
62
63
|
unicode-display_width (>= 2.4.0, < 3.0)
|
63
|
-
rubocop-ast (1.
|
64
|
+
rubocop-ast (1.27.0)
|
64
65
|
parser (>= 3.2.1.0)
|
65
66
|
rubocop-capybara (2.17.1)
|
66
67
|
rubocop (~> 1.41)
|
67
|
-
rubocop-
|
68
|
+
rubocop-rake (0.6.0)
|
69
|
+
rubocop (~> 1.0)
|
70
|
+
rubocop-rspec (2.19.0)
|
68
71
|
rubocop (~> 1.33)
|
69
72
|
rubocop-capybara (~> 2.17)
|
70
|
-
ruby-progressbar (1.
|
73
|
+
ruby-progressbar (1.13.0)
|
71
74
|
unicode-display_width (2.4.2)
|
72
75
|
zache (0.12.0)
|
73
76
|
|
@@ -76,12 +79,14 @@ PLATFORMS
|
|
76
79
|
|
77
80
|
DEPENDENCIES
|
78
81
|
babosa (~> 2.0)
|
79
|
-
dotenv (~> 2.8, >= 2.8.1)
|
80
82
|
lighstorm!
|
81
83
|
pry-byebug (~> 3.10, >= 3.10.1)
|
84
|
+
rainbow (~> 3.1, >= 3.1.1)
|
85
|
+
rake (~> 13.0, >= 13.0.6)
|
82
86
|
rspec (~> 3.12)
|
83
|
-
rubocop (~> 1.
|
84
|
-
rubocop-
|
87
|
+
rubocop (~> 1.48)
|
88
|
+
rubocop-rake (~> 0.6.0)
|
89
|
+
rubocop-rspec (~> 2.19)
|
85
90
|
|
86
91
|
BUNDLED WITH
|
87
92
|
2.4.4
|
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.9'
|
38
38
|
```
|
39
39
|
|
40
40
|
```ruby
|
@@ -46,12 +46,13 @@ 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.9
|
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', millisatoshis: 1_000,
|
55
|
+
payable: 'once'
|
55
56
|
)
|
56
57
|
|
57
58
|
Lighstorm::Satoshis.new(
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './spec/helpers/tasks/contracts'
|
4
|
+
|
5
|
+
# rspec --format json | bundle exec rake contracts:fix
|
6
|
+
namespace :contracts do
|
7
|
+
desc 'Fix Contract Tests Hash'
|
8
|
+
task :fix do
|
9
|
+
Tasks::Contracts.fix($stdin.gets)
|
10
|
+
end
|
11
|
+
end
|
@@ -3,27 +3,38 @@
|
|
3
3
|
module Lighstorm
|
4
4
|
module Adapter
|
5
5
|
class Purpose
|
6
|
+
def self.send_payment_v2(grpc, node_get_info)
|
7
|
+
return 'unknown' if grpc[:payment_route][:hops].empty?
|
8
|
+
|
9
|
+
return 'self-payment' if self_payment?(grpc[:payment_route][:hops])
|
10
|
+
return 'peer-to-peer' if peer_to_peer?(grpc[:payment_route][:hops])
|
11
|
+
return 'rebalance' if rebalance?(grpc[:payment_route][:hops], node_get_info)
|
12
|
+
|
13
|
+
'payment'
|
14
|
+
end
|
15
|
+
|
6
16
|
def self.list_payments(grpc, node_get_info)
|
7
|
-
return '
|
8
|
-
|
9
|
-
return '
|
17
|
+
return 'unknown' if grpc[:htlcs].empty?
|
18
|
+
|
19
|
+
return 'self-payment' if self_payment?(grpc[:htlcs].first[:route][:hops])
|
20
|
+
return 'peer-to-peer' if peer_to_peer?(grpc[:htlcs].first[:route][:hops])
|
21
|
+
return 'rebalance' if rebalance?(grpc[:htlcs].first[:route][:hops], node_get_info)
|
10
22
|
|
11
23
|
'payment'
|
12
24
|
end
|
13
25
|
|
14
|
-
def self.self_payment?(
|
15
|
-
|
16
|
-
grpc[:htlcs].first[:route][:hops][0][:chan_id] == grpc[:htlcs].first[:route][:hops][1][:chan_id]
|
26
|
+
def self.self_payment?(hops)
|
27
|
+
hops.size == 2 && hops[0][:chan_id] == hops[1][:chan_id]
|
17
28
|
end
|
18
29
|
|
19
|
-
def self.peer_to_peer?(
|
20
|
-
|
30
|
+
def self.peer_to_peer?(hops)
|
31
|
+
hops.size == 1
|
21
32
|
end
|
22
33
|
|
23
|
-
def self.rebalance?(
|
24
|
-
return false if
|
34
|
+
def self.rebalance?(hops, node_get_info)
|
35
|
+
return false if hops.size <= 2
|
25
36
|
|
26
|
-
destination_public_key =
|
37
|
+
destination_public_key = hops.last[:pub_key]
|
27
38
|
|
28
39
|
node_get_info[:identity_pubkey] == destination_public_key
|
29
40
|
end
|
data/adapters/edges/payment.rb
CHANGED
@@ -5,7 +5,7 @@ require 'digest'
|
|
5
5
|
require_relative '../connections/payment_channel'
|
6
6
|
require_relative 'payment/purpose'
|
7
7
|
|
8
|
-
require_relative '../
|
8
|
+
require_relative '../invoice'
|
9
9
|
|
10
10
|
require_relative '../../ports/dsl/lighstorm/errors'
|
11
11
|
|
@@ -23,25 +23,64 @@ module Lighstorm
|
|
23
23
|
)
|
24
24
|
end
|
25
25
|
|
26
|
-
def self.
|
26
|
+
def self.send_payment_v2(grpc, node_myself, invoice_decode)
|
27
|
+
adapted = list_payments(grpc, node_myself, invoice_decode)
|
28
|
+
adapted[:_source] = :send_payment_v2
|
29
|
+
adapted
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.list_payments(grpc, node_myself, invoice_decode = nil)
|
27
33
|
raise UnexpectedNumberOfHTLCsError, "htlcs: #{grpc[:htlcs].size}" if grpc[:htlcs].size > 1
|
28
34
|
|
29
35
|
data = {
|
30
36
|
_source: :list_payments,
|
31
37
|
_key: _key(grpc),
|
32
|
-
|
33
|
-
|
38
|
+
at: Time.at(grpc[:creation_time_ns] / 1e+9),
|
39
|
+
state: grpc[:status].to_s.downcase,
|
34
40
|
fee: { millisatoshis: grpc[:fee_msat] },
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
hop = PaymentChannel.list_payments(raw_hop, i)
|
39
|
-
hop[:channel][:target] = { public_key: raw_hop[:pub_key] }
|
40
|
-
hop
|
41
|
-
end
|
41
|
+
amount: { millisatoshis: grpc[:value_msat] },
|
42
|
+
purpose: Purpose.list_payments(grpc, node_myself),
|
43
|
+
invoice: Invoice.list_payments(grpc, invoice_decode)
|
42
44
|
}
|
43
45
|
|
44
|
-
data[:
|
46
|
+
data[:secret] = data[:invoice][:secret]
|
47
|
+
|
48
|
+
htlc = grpc[:htlcs].first
|
49
|
+
|
50
|
+
return data if htlc.nil?
|
51
|
+
|
52
|
+
data[:hops] = htlc[:route][:hops].map.with_index do |raw_hop, i|
|
53
|
+
hop = PaymentChannel.list_payments(raw_hop, i)
|
54
|
+
hop[:channel][:target] = { public_key: raw_hop[:pub_key] }
|
55
|
+
hop
|
56
|
+
end
|
57
|
+
|
58
|
+
data[:invoice][:settled_at] = Time.at(htlc[:resolve_time_ns] / 1e+9) if htlc[:resolve_time_ns]
|
59
|
+
|
60
|
+
last_hop = htlc[:route][:hops].last
|
61
|
+
|
62
|
+
return data if last_hop.nil?
|
63
|
+
|
64
|
+
# https://github.com/satoshisstream/satoshis.stream/blob/main/TLV_registry.md
|
65
|
+
if last_hop[:custom_records][34_349_334]
|
66
|
+
data[:message] = last_hop[:custom_records][34_349_334].dup
|
67
|
+
|
68
|
+
unless data[:message].force_encoding('UTF-8').valid_encoding?
|
69
|
+
data[:message] = data[:message].unpack1('H*')
|
70
|
+
|
71
|
+
data[:message] = data[:message].scrub('?') unless data[:message].force_encoding('UTF-8').valid_encoding?
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
if data[:invoice] && data[:invoice][:code] && !data[:invoice][:code].nil? && !data[:invoice][:code].empty?
|
76
|
+
data[:through] = if data[:invoice][:payable] == 'indefinitely'
|
77
|
+
'amp'
|
78
|
+
else
|
79
|
+
'non-amp'
|
80
|
+
end
|
81
|
+
else
|
82
|
+
data[:through] = last_hop[:mpp_record] ? 'amp' : 'keysend'
|
83
|
+
end
|
45
84
|
|
46
85
|
data
|
47
86
|
end
|
data/adapters/invoice.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'digest'
|
4
4
|
|
5
|
-
require_relative '
|
5
|
+
require_relative '../ports/dsl/lighstorm/errors'
|
6
6
|
|
7
7
|
module Lighstorm
|
8
8
|
module Adapter
|
@@ -10,43 +10,165 @@ module Lighstorm
|
|
10
10
|
def self.add_invoice(grpc)
|
11
11
|
{
|
12
12
|
_source: :add_invoice,
|
13
|
+
code: grpc[:payment_request],
|
14
|
+
address: grpc[:payment_addr].unpack1('H*'),
|
15
|
+
secret: {
|
16
|
+
hash: grpc[:r_hash].unpack1('H*')
|
17
|
+
}
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.decode_pay_req(grpc, request_code = nil)
|
22
|
+
adapted = {
|
23
|
+
_source: :decode_pay_req,
|
13
24
|
_key: Digest::SHA256.hexdigest(
|
14
25
|
[
|
15
|
-
grpc[:
|
16
|
-
grpc[:
|
17
|
-
grpc[:
|
26
|
+
grpc[:payment_hash],
|
27
|
+
grpc[:num_satoshis],
|
28
|
+
grpc[:timestamp],
|
18
29
|
grpc[:payment_addr]
|
19
30
|
].join('/')
|
20
31
|
),
|
21
|
-
|
32
|
+
payable: 'once',
|
33
|
+
created_at: Time.at(grpc[:timestamp]),
|
34
|
+
expires_at: Time.at(grpc[:timestamp] + grpc[:expiry]),
|
35
|
+
amount: (grpc[:num_msat]).zero? ? nil : { millisatoshis: grpc[:num_msat] },
|
36
|
+
description: {
|
37
|
+
memo: grpc[:description].empty? ? nil : grpc[:description],
|
38
|
+
hash: grpc[:description_hash] == '' ? nil : grpc[:description_hash]
|
39
|
+
},
|
40
|
+
address: grpc[:payment_addr].unpack1('H*'),
|
41
|
+
secret: {
|
42
|
+
hash: grpc[:payment_hash]
|
43
|
+
}
|
22
44
|
}
|
23
|
-
end
|
24
45
|
|
25
|
-
|
26
|
-
adapted = list_or_lookup(grpc)
|
46
|
+
adapted[:code] = request_code unless request_code.nil?
|
27
47
|
|
28
|
-
|
29
|
-
|
48
|
+
if grpc[:features].key?(30) && grpc[:features][30][:is_required]
|
49
|
+
raise "unexpected feature[30] name #{grpc[:features][30][:name]}" if grpc[:features][30][:name] != 'amp'
|
50
|
+
|
51
|
+
adapted[:payable] = 'indefinitely'
|
52
|
+
end
|
30
53
|
|
31
54
|
adapted
|
32
55
|
end
|
33
56
|
|
34
|
-
def self.
|
35
|
-
adapted =
|
57
|
+
def self.lookup_invoice(grpc, at)
|
58
|
+
adapted = list_or_lookup_invoice(grpc, at)
|
59
|
+
adapted[:_source] = :lookup_invoice
|
60
|
+
adapted
|
61
|
+
end
|
36
62
|
|
63
|
+
def self.list_invoices(grpc, at)
|
64
|
+
adapted = list_or_lookup_invoice(grpc, at)
|
37
65
|
adapted[:_source] = :list_invoices
|
38
|
-
adapted
|
66
|
+
adapted
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.list_or_lookup_invoice(grpc, at)
|
70
|
+
raise 'missing at' if at.nil?
|
71
|
+
|
72
|
+
adapted = {
|
73
|
+
_key: _key(grpc),
|
74
|
+
created_at: Time.at(grpc[:creation_date]),
|
75
|
+
expires_at: Time.at(grpc[:creation_date] + grpc[:expiry]),
|
76
|
+
settled_at: grpc[:settle_date].nil? || !grpc[:settle_date].positive? ? nil : Time.at(grpc[:settle_date]),
|
77
|
+
state: grpc[:state].to_s.downcase,
|
78
|
+
code: grpc[:payment_request].empty? ? nil : grpc[:payment_request],
|
79
|
+
payable: grpc[:is_amp] == true ? 'indefinitely' : 'once',
|
80
|
+
description: {
|
81
|
+
memo: grpc[:memo].empty? ? nil : grpc[:memo],
|
82
|
+
hash: grpc[:description_hash].empty? ? nil : grpc[:description_hash]
|
83
|
+
},
|
84
|
+
address: grpc[:payment_addr].unpack1('H*'),
|
85
|
+
secret: {
|
86
|
+
preimage: grpc[:r_preimage].empty? ? nil : grpc[:r_preimage].unpack1('H*'),
|
87
|
+
hash: grpc[:r_hash].empty? ? nil : grpc[:r_hash].unpack1('H*')
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
adapted[:amount] = { millisatoshis: grpc[:value_msat] } if grpc[:value_msat] != 0
|
92
|
+
|
93
|
+
adapted[:received] = { millisatoshis: grpc[:amt_paid_msat] } if grpc[:amt_paid_msat] != 0
|
94
|
+
|
95
|
+
if adapted[:state] == 'settled' &&
|
96
|
+
adapted[:payable] == 'indefinitely' &&
|
97
|
+
adapted[:expires_at] > at
|
98
|
+
adapted[:state] = 'open'
|
99
|
+
end
|
100
|
+
|
101
|
+
raise 'todo: received with canceled' if !adapted[:received].nil? && adapted[:state] == 'canceled'
|
102
|
+
|
103
|
+
adapted[:payments] = []
|
104
|
+
|
105
|
+
grpc[:htlcs].each do |htlc|
|
106
|
+
next unless htlc[:state] == :SETTLED
|
107
|
+
|
108
|
+
payment = {
|
109
|
+
amount: { millisatoshis: htlc[:amt_msat] },
|
110
|
+
hops: [{ channel: { id: htlc[:chan_id] } }],
|
111
|
+
at: Time.at(htlc[:resolve_time])
|
112
|
+
}
|
113
|
+
|
114
|
+
if grpc[:is_amp]
|
115
|
+
payment[:secret] = {
|
116
|
+
preimage: htlc[:amp][:preimage].unpack1('H*'),
|
117
|
+
hash: htlc[:amp][:hash].unpack1('H*')
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
# https://github.com/satoshisstream/satoshis.stream/blob/main/TLV_registry.md
|
122
|
+
if htlc[:custom_records][34_349_334]
|
123
|
+
payment[:message] = htlc[:custom_records][34_349_334].dup
|
124
|
+
|
125
|
+
unless payment[:message].force_encoding('UTF-8').valid_encoding?
|
126
|
+
payment[:message] = payment[:message].unpack1('H*')
|
127
|
+
|
128
|
+
unless payment[:message].force_encoding('UTF-8').valid_encoding?
|
129
|
+
payment[:message] = payment[:message].scrub('?')
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
adapted[:payments] << payment
|
135
|
+
end
|
136
|
+
|
137
|
+
adapted[:payments] = adapted[:payments].sort_by { |payment| -payment[:at].to_i }
|
138
|
+
|
139
|
+
adapted.delete(:payments) if adapted[:payments].empty?
|
39
140
|
|
40
141
|
adapted
|
41
142
|
end
|
42
143
|
|
43
|
-
def self.
|
44
|
-
{
|
144
|
+
def self.list_payments(grpc, invoice_decode = nil)
|
145
|
+
raise UnexpectedNumberOfHTLCsError, "htlcs: #{grpc[:htlcs].size}" if grpc[:htlcs].size > 1
|
146
|
+
|
147
|
+
data = {
|
45
148
|
_key: _key(grpc),
|
149
|
+
_source: :list_payments,
|
46
150
|
created_at: Time.at(grpc[:creation_date]),
|
47
|
-
|
48
|
-
state:
|
151
|
+
settled_at: grpc[:settle_date].nil? || !grpc[:settle_date].positive? ? nil : Time.at(grpc[:settle_date]),
|
152
|
+
state: nil,
|
153
|
+
payable: grpc[:is_amp] == true ? 'indefinitely' : 'once',
|
154
|
+
code: grpc[:payment_request].empty? ? nil : grpc[:payment_request],
|
155
|
+
amount: { millisatoshis: grpc[:value_msat] },
|
156
|
+
description: {
|
157
|
+
memo: grpc[:memo],
|
158
|
+
hash: grpc[:description_hash] == '' ? nil : grpc[:description_hash]
|
159
|
+
},
|
160
|
+
secret: {
|
161
|
+
preimage: grpc[:payment_preimage],
|
162
|
+
hash: grpc[:payment_hash]
|
163
|
+
}
|
49
164
|
}
|
165
|
+
|
166
|
+
unless invoice_decode.nil?
|
167
|
+
data[:payable] = invoice_decode[:payable]
|
168
|
+
data[:expires_at] = invoice_decode[:expires_at]
|
169
|
+
end
|
170
|
+
|
171
|
+
data
|
50
172
|
end
|
51
173
|
|
52
174
|
def self._key(grpc)
|
data/components/cache.rb
CHANGED
@@ -21,10 +21,15 @@ module Lighstorm
|
|
21
21
|
@client = Zache.new
|
22
22
|
end
|
23
23
|
|
24
|
+
def safety_key(key)
|
25
|
+
key.gsub('.', '_').to_sym
|
26
|
+
end
|
27
|
+
|
24
28
|
def for(key, ttl: nil, params: {}, &block)
|
25
29
|
if ttl.nil?
|
26
|
-
|
27
|
-
|
30
|
+
safety_key = self.safety_key(key)
|
31
|
+
ttl = Lighstorm::Static::CACHE[safety_key]
|
32
|
+
raise MissingTTLError, "missing ttl for #{safety_key} static/cache.rb" if ttl.nil?
|
28
33
|
|
29
34
|
ttl = ttl == false ? false : ttl[:ttl]
|
30
35
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative '../../../ports/grpc'
|
4
4
|
require_relative '../../../models/errors'
|
5
|
+
require_relative '../../../helpers/time_expression'
|
5
6
|
require_relative '../../invoice'
|
6
7
|
require_relative '../../action'
|
7
8
|
|
@@ -15,15 +16,27 @@ module Lighstorm
|
|
15
16
|
).to_h
|
16
17
|
end
|
17
18
|
|
18
|
-
def self.prepare(description: nil, millisatoshis: nil)
|
19
|
-
{
|
19
|
+
def self.prepare(payable:, expires_in:, description: nil, millisatoshis: nil)
|
20
|
+
request = {
|
20
21
|
service: :lightning,
|
21
22
|
method: :add_invoice,
|
22
23
|
params: {
|
23
24
|
memo: description,
|
24
|
-
|
25
|
+
# Lightning Invoice Expiration: UX Considerations
|
26
|
+
# https://d.elor.me/2022/01/lightning-invoice-expiration-ux-considerations/
|
27
|
+
expiry: Helpers::TimeExpression.seconds(expires_in)
|
25
28
|
}
|
26
29
|
}
|
30
|
+
|
31
|
+
request[:params][:value_msat] = millisatoshis unless millisatoshis.nil?
|
32
|
+
|
33
|
+
if payable.to_sym == :indefinitely
|
34
|
+
request[:params][:is_amp] = true
|
35
|
+
elsif payable.to_sym != :once
|
36
|
+
raise Errors::ArgumentError, "payable: accepts 'indefinitely' or 'once', '#{payable}' is not valid."
|
37
|
+
end
|
38
|
+
|
39
|
+
request
|
27
40
|
end
|
28
41
|
|
29
42
|
def self.dispatch(grpc_request, &vcr)
|
@@ -35,16 +48,19 @@ module Lighstorm
|
|
35
48
|
end
|
36
49
|
|
37
50
|
def self.fetch(adapted, &vcr)
|
38
|
-
FindBySecretHash.data(adapted[:
|
51
|
+
FindBySecretHash.data(adapted[:secret][:hash], &vcr)
|
39
52
|
end
|
40
53
|
|
41
54
|
def self.model(data)
|
42
55
|
FindBySecretHash.model(data)
|
43
56
|
end
|
44
57
|
|
45
|
-
def self.perform(description: nil, millisatoshis: nil, preview: false, &vcr)
|
58
|
+
def self.perform(payable:, expires_in:, description: nil, millisatoshis: nil, preview: false, &vcr)
|
46
59
|
grpc_request = prepare(
|
47
|
-
description: description,
|
60
|
+
description: description,
|
61
|
+
millisatoshis: millisatoshis,
|
62
|
+
expires_in: expires_in,
|
63
|
+
payable: payable
|
48
64
|
)
|
49
65
|
|
50
66
|
return grpc_request if preview
|
@@ -2,25 +2,83 @@
|
|
2
2
|
|
3
3
|
require_relative '../../../ports/grpc'
|
4
4
|
require_relative '../../../models/errors'
|
5
|
+
require_relative '../../../models/edges/payment'
|
6
|
+
require_relative '../../../adapters/edges/payment'
|
7
|
+
require_relative '../../invoice'
|
8
|
+
require_relative '../../action'
|
9
|
+
require_relative '../../node/myself'
|
10
|
+
|
11
|
+
require_relative '../../payment/actions/pay'
|
5
12
|
|
6
13
|
module Lighstorm
|
7
14
|
module Controllers
|
8
15
|
module Invoice
|
9
16
|
module Pay
|
10
|
-
def self.
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
def self.dispatch(grpc_request, &vcr)
|
18
|
+
Payment::Pay.dispatch(grpc_request, &vcr)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.fetch(request_code, &vcr)
|
22
|
+
Payment::Pay.fetch(request_code, &vcr)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.adapt(data, node_get_info)
|
26
|
+
Payment::Pay.adapt(data, node_get_info)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.model(data)
|
30
|
+
Payment::Pay.model(data)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.prepare(request_code:, times_out_in:, millisatoshis: nil, message: nil)
|
34
|
+
request = {
|
35
|
+
service: :router,
|
36
|
+
method: :send_payment_v2,
|
37
|
+
params: {
|
38
|
+
payment_request: request_code,
|
39
|
+
timeout_seconds: Helpers::TimeExpression.seconds(times_out_in),
|
40
|
+
allow_self_payment: true,
|
41
|
+
dest_custom_records: {}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
request[:params][:amt_msat] = millisatoshis unless millisatoshis.nil?
|
46
|
+
|
47
|
+
if !message.nil? && !message.empty?
|
48
|
+
# https://github.com/satoshisstream/satoshis.stream/blob/main/TLV_registry.md
|
49
|
+
request[:params][:dest_custom_records][34_349_334] = message
|
23
50
|
end
|
51
|
+
|
52
|
+
request[:params].delete(:dest_custom_records) if request[:params][:dest_custom_records].empty?
|
53
|
+
|
54
|
+
request
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.perform(
|
58
|
+
times_out_in:, request_code:, millisatoshis: nil, message: nil, preview: false, &vcr
|
59
|
+
)
|
60
|
+
grpc_request = prepare(
|
61
|
+
request_code: request_code,
|
62
|
+
millisatoshis: millisatoshis,
|
63
|
+
message: message,
|
64
|
+
times_out_in: times_out_in
|
65
|
+
)
|
66
|
+
|
67
|
+
return grpc_request if preview
|
68
|
+
|
69
|
+
response = dispatch(grpc_request, &vcr)
|
70
|
+
|
71
|
+
Payment::Pay.raise_error_if_exists!(response)
|
72
|
+
|
73
|
+
data = fetch(request_code, &vcr)
|
74
|
+
|
75
|
+
adapted = adapt(response, data)
|
76
|
+
|
77
|
+
model = self.model(adapted)
|
78
|
+
|
79
|
+
Payment::Pay.raise_failure_if_exists!(model, response)
|
80
|
+
|
81
|
+
Action::Output.new({ response: response[:response], result: model })
|
24
82
|
end
|
25
83
|
end
|
26
84
|
end
|