lighstorm 0.0.8 → 0.0.10

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +1 -0
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +1 -0
  5. data/Gemfile +5 -3
  6. data/Gemfile.lock +13 -8
  7. data/README.md +11 -3
  8. data/Rakefile +11 -0
  9. data/adapters/edges/payment/purpose.rb +22 -11
  10. data/adapters/edges/payment.rb +51 -12
  11. data/adapters/invoice.rb +133 -31
  12. data/components/cache.rb +7 -2
  13. data/controllers/forward/group_by_channel.rb +1 -1
  14. data/controllers/invoice/actions/create.rb +22 -6
  15. data/controllers/invoice/actions/pay.rb +79 -13
  16. data/controllers/invoice/all.rb +16 -6
  17. data/controllers/invoice/decode.rb +6 -6
  18. data/controllers/invoice/find_by_secret_hash.rb +7 -1
  19. data/controllers/invoice.rb +15 -6
  20. data/controllers/node/actions/pay.rb +114 -0
  21. data/controllers/payment/actions/pay.rb +104 -0
  22. data/controllers/payment/all.rb +79 -28
  23. data/controllers/transaction/all.rb +54 -0
  24. data/controllers/transaction.rb +13 -0
  25. data/deleted.sh +1 -0
  26. data/docs/README.md +307 -51
  27. data/docs/_coverpage.md +1 -1
  28. data/docs/index.html +1 -1
  29. data/helpers/time_expression.rb +33 -0
  30. data/models/connections/payment_channel.rb +13 -8
  31. data/models/edges/channel.rb +1 -1
  32. data/models/edges/payment.rb +51 -20
  33. data/models/errors.rb +29 -1
  34. data/models/invoice.rb +69 -11
  35. data/models/nodes/node.rb +35 -0
  36. data/models/satoshis.rb +11 -3
  37. data/models/secret.rb +37 -0
  38. data/models/transaction.rb +42 -0
  39. data/ports/dsl/lighstorm.rb +2 -0
  40. data/static/cache.rb +14 -13
  41. data/static/spec.rb +1 -1
  42. metadata +11 -4
  43. data/adapters/payment_request.rb +0 -87
  44. data/models/payment_request.rb +0 -72
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../invoice/all'
4
+ require_relative '../../models/transaction'
5
+
6
+ module Lighstorm
7
+ module Controllers
8
+ module Transaction
9
+ module All
10
+ def self.fetch(limit: nil)
11
+ transactions = []
12
+
13
+ Invoice::All.data(spontaneous: true).filter do |invoice|
14
+ !invoice[:payments].nil? && invoice[:payments].size.positive?
15
+ end.each do |invoice|
16
+ invoice[:payments].each do |payment|
17
+ transactions << {
18
+ direction: 'in',
19
+ at: payment[:at],
20
+ amount: payment[:amount],
21
+ message: payment[:message],
22
+ kind: 'invoice',
23
+ data: invoice
24
+ }
25
+ end
26
+ end
27
+
28
+ transactions = transactions.sort_by { |transaction| -transaction[:at].to_i }
29
+
30
+ transactions = transactions[0..limit - 1] unless limit.nil?
31
+
32
+ { transactions: transactions }
33
+ end
34
+
35
+ def self.transform(raw)
36
+ raw[:transactions].map do |transaction|
37
+ transaction[:_key] = SecureRandom.hex
38
+ transaction
39
+ end
40
+ end
41
+
42
+ def self.data(limit: nil, &vcr)
43
+ raw = vcr.nil? ? fetch(limit: limit) : vcr.call(-> { fetch(limit: limit) })
44
+
45
+ transform(raw)
46
+ end
47
+
48
+ def self.model(data)
49
+ data.map { |data| Models::Transaction.new(data) }
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './transaction/all'
4
+
5
+ module Lighstorm
6
+ module Controllers
7
+ module Transaction
8
+ def self.all(limit: nil)
9
+ All.model(All.data(limit: limit))
10
+ end
11
+ end
12
+ end
13
+ end
data/deleted.sh ADDED
@@ -0,0 +1 @@
1
+ deleted.sh
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.8'
30
+ gem 'lighstorm', '~> 0.0.10'
31
31
  ```
32
32
 
33
33
  Run `bundle install`.
@@ -60,12 +60,26 @@ Lighstorm.config!(
60
60
  ```ruby
61
61
  require 'lighstorm'
62
62
 
63
- puts Lighstorm.version # => 0.0.8
63
+ puts Lighstorm.version # => 0.0.10
64
64
 
65
65
  Lighstorm::Invoice.create(
66
- description: 'Coffee', millisatoshis: 1000
66
+ description: 'Coffee', amount: { millisatoshis: 1000 }, payable: 'once'
67
67
  )
68
68
 
69
+ Lighstorm::Invoice.decode('lnbc20m1pv...qqdhhwkj').pay
70
+
71
+ Lighstorm::Invoice.decode('lnbc20m1pv...qqdhhwkj').pay(
72
+ fee: { maximum: { millisatoshis: 1000 } }
73
+ )
74
+
75
+ Lighstorm::Node.find_by_public_key(
76
+ '02d3c80335a8ccb2ed364c06875f32240f36f7edb37d80f8dbe321b4c364b6e997'
77
+ ).pay(amount: { millisatoshis: 1000 })
78
+
79
+ Lighstorm::Node.find_by_public_key(
80
+ '02d3c80335a8ccb2ed364c06875f32240f36f7edb37d80f8dbe321b4c364b6e997'
81
+ ).send_message('Hello from Lighstorm!', amount: { millisatoshis: 1000 })
82
+
69
83
  Lighstorm::Node.myself.alias # => icebaker/old-stone
70
84
  Lighstorm::Node.myself.public_key # => 02d3...e997
71
85
 
@@ -95,7 +109,7 @@ payment.hops.first.channel.partner.node.alias
95
109
 
96
110
  Lighstorm::Satoshis.new(
97
111
  millisatoshis: 75621650
98
- ).satoshis # => 75621
112
+ ).satoshis # => 75621.65
99
113
  ```
100
114
 
101
115
  # Data Modeling
@@ -146,7 +160,9 @@ forward = Lighstorm::Forward.last
146
160
  forward.at
147
161
 
148
162
  forward.fee.millisatoshis
149
- forward.fee.parts_per_million
163
+ forward.fee.parts_per_million(
164
+ forward.in.amount.millisatoshis
165
+ )
150
166
 
151
167
  forward.in.amount.millisatoshis
152
168
  forward.out.amount.millisatoshis
@@ -168,15 +184,15 @@ forward.out.channel.partner.node.alias
168
184
  ### Payment
169
185
 
170
186
  ```ruby
171
- payment = Payment.last
187
+ payment = Lighstorm::Payment.last
172
188
 
173
- payment.status
174
- payment.created_at
189
+ payment.at
190
+ payment.state
175
191
 
176
192
  # https://github.com/lightning/bolts/blob/master/11-payment-encoding.md
177
- payment.request.code # "lnbc20m1pv...qqdhhwkj"
193
+ payment.invoice.code # "lnbc20m1pv...qqdhhwkj"
178
194
 
179
- payment.request.amount.millisatoshis
195
+ payment.invoice.amount.millisatoshis
180
196
 
181
197
  payment.from.hop
182
198
  payment.from.amount.millisatoshis
@@ -239,6 +255,86 @@ node.platform.lightning.implementation
239
255
  node.platform.lightning.version
240
256
  ```
241
257
 
258
+ ### Pay
259
+
260
+ Read more about [_Spontaneous Payments_](https://docs.lightning.engineering/lightning-network-tools/lnd/send-messages-with-keysend#send-a-spontaneous-payment).
261
+
262
+ ```ruby
263
+ destination = Lighstorm::Node.find_by_public_key(
264
+ '02d3c80335a8ccb2ed364c06875f32240f36f7edb37d80f8dbe321b4c364b6e997'
265
+ )
266
+
267
+ destination.alias # => 'icebaker/old-stone'
268
+
269
+ destination.pay(amount: { millisatoshis: 1000 })
270
+
271
+ destination.pay(
272
+ amount: { millisatoshis: 1500 },
273
+ fee: { maximum: { millisatoshis: 1000 } },
274
+ message: 'Hello from Lighstorm!',
275
+ through: 'amp',
276
+ times_out_in: { seconds: 5 }
277
+ )
278
+
279
+ destination.pay(
280
+ amount: { millisatoshis: 1200 },
281
+ fee: { maximum: { millisatoshis: 1000 } },
282
+ message: 'Hello from Lighstorm!',
283
+ through: 'keysend',
284
+ times_out_in: { seconds: 5 }
285
+ )
286
+
287
+ action = destination.pay(amount: { millisatoshis: 1000 })
288
+ action.result.fee.millisatoshis
289
+ ```
290
+
291
+ ### Send Messages
292
+
293
+ **Warning:** Sending messages through Lightning Network requires you to spend satoshis and potentially pay fees.
294
+
295
+ ```ruby
296
+ destination = Lighstorm::Node.find_by_public_key(
297
+ '02d3c80335a8ccb2ed364c06875f32240f36f7edb37d80f8dbe321b4c364b6e997'
298
+ )
299
+
300
+ destination.alias # => 'icebaker/old-stone'
301
+
302
+ destination.send_message(
303
+ 'Hello from Lighstorm!',
304
+ amount: { millisatoshis: 1000 }
305
+ )
306
+
307
+ destination.send_message(
308
+ 'Hello from Lighstorm!',
309
+ amount: { millisatoshis: 1000 },
310
+ fee: { maximum: { millisatoshis: 1000 } },
311
+ through: 'amp',
312
+ times_out_in: { seconds: 5 }
313
+ )
314
+
315
+ destination.send_message(
316
+ 'Hello from Lighstorm!',
317
+ amount: { millisatoshis: 1000 },
318
+ fee: { maximum: { millisatoshis: 1000 } },
319
+ through: 'keysend',
320
+ times_out_in: { seconds: 5 }
321
+ )
322
+
323
+ action = destination.send_message(
324
+ 'Hello from Lighstorm!',
325
+ amount: { millisatoshis: 1000 }
326
+ )
327
+ action.result.fee.millisatoshis
328
+ ```
329
+
330
+ Read more about sending messages:
331
+ - [_Send a message to other nodes_](https://docs.lightning.engineering/lightning-network-tools/lnd/send-messages-with-keysend#send-a-message-to-other-nodes)
332
+ - [_Does Private messaging over Bitcoin’s Lightning Network have potential?_](https://cryptopurview.com/private-messaging-over-bitcoins-lightning-network/)
333
+ - [_How Bitcoin's Lightning Can Be Used for Private Messaging_](https://www.coindesk.com/markets/2019/11/09/how-bitcoins-lightning-can-be-used-for-private-messaging/)
334
+
335
+ ### Error Handling
336
+ Same error handling used for [Invoices Payment Errors](?id=error-handling-1)
337
+
242
338
  ## Channel
243
339
 
244
340
  [![This is an image representing Channel as a graph.](https://raw.githubusercontent.com/icebaker/assets/main/lighstorm/graph-channel.png)](https://raw.githubusercontent.com/icebaker/assets/main/lighstorm/graph-channel.png)
@@ -373,23 +469,24 @@ Lighstorm::Invoice.find_by_secret_hash(
373
469
  invoice._key
374
470
 
375
471
  invoice.created_at
376
- invoice.settle_at
472
+ invoice.expires_at
473
+ invoice.settled_at
377
474
 
378
475
  invoice.state
379
476
 
380
477
  # https://github.com/lightning/bolts/blob/master/11-payment-encoding.md
381
- invoice.request.code # "lnbc20m1pv...qqdhhwkj"
478
+ invoice.code # "lnbc20m1pv...qqdhhwkj"
382
479
 
383
- invoice.request.amount.millisatoshis
480
+ invoice.amount.millisatoshis
384
481
 
385
- invoice.request.description.memo
386
- invoice.request.description.hash
482
+ invoice.payable # 'once' or 'indefinitely'
387
483
 
388
- # https://docs.lightning.engineering/the-lightning-network/multihop-payments
389
- invoice.request.secret.preimage
390
- invoice.request.secret.hash
484
+ invoice.description.memo
485
+ invoice.description.hash
391
486
 
392
- invoice.request.address
487
+ # https://docs.lightning.engineering/the-lightning-network/multihop-payments
488
+ invoice.secret.preimage
489
+ invoice.secret.hash
393
490
  ```
394
491
 
395
492
  ### Create
@@ -400,11 +497,27 @@ invoice.request.address
400
497
  # 'preview' let you check the expected operation
401
498
  # before actually performing it for debug purposes
402
499
  preview = Lighstorm::Invoice.create(
403
- description: 'Coffee', millisatoshis: 1000, preview: true
500
+ description: 'Coffee', amount: { millisatoshis: 1000 },
501
+ payable: 'once', preview: true
502
+ )
503
+
504
+ action = Lighstorm::Invoice.create(
505
+ description: 'Coffee', amount: { millisatoshis: 1000 },
506
+ payable: 'once', expires_in: { minutes: 5 }
507
+ )
508
+
509
+ action = Lighstorm::Invoice.create(
510
+ description: 'Beer', payable: 'once'
511
+ )
512
+
513
+ action = Lighstorm::Invoice.create(
514
+ description: 'Donations', payable: 'indefinitely',
515
+ expires_in: { hours: 24 }
404
516
  )
405
517
 
406
518
  action = Lighstorm::Invoice.create(
407
- description: 'Piña Colada', millisatoshis: 1000
519
+ description: 'Concert Ticket', amount: { millisatoshis: 500000000 },
520
+ payable: 'indefinitely', expires_in: { days: 5 }
408
521
  )
409
522
 
410
523
  action.to_h
@@ -413,6 +526,102 @@ action.response
413
526
  invoice = action.result
414
527
  ```
415
528
 
529
+ ### Pay
530
+
531
+ [Understanding Lightning Invoices](https://docs.lightning.engineering/the-lightning-network/payment-lifecycle/understanding-lightning-invoices)
532
+
533
+ ```ruby
534
+ invoice = Lighstorm::Invoice.decode('lnbc20m1pv...qqdhhwkj')
535
+
536
+ # 'preview' let you check the expected operation
537
+ # before actually performing it for debug purposes
538
+ invoice.pay(preview: true)
539
+
540
+ action = invoice.pay
541
+
542
+ action.to_h
543
+
544
+ action.response
545
+ payment = action.result
546
+
547
+ payment.at
548
+ payment.state
549
+
550
+ payment.amount.millisatoshis
551
+ payment.fee.millisatoshis
552
+ payment.fee.parts_per_million(
553
+ payment.amount.millisatoshis
554
+ )
555
+
556
+ payment.purpose
557
+ payment.hops.size
558
+ ```
559
+
560
+ ```ruby
561
+ invoice.pay(
562
+ amount: { millisatoshis: 1500 },
563
+ fee: { maximum: { millisatoshis: 1000 } },
564
+ message: 'here we go',
565
+ times_out_in: { seconds: 5 }
566
+ )
567
+ ```
568
+
569
+ #### Error Handling
570
+ Check [Error Handling](?id=error-handling-2)
571
+
572
+ ```ruby
573
+ begin
574
+ invoice.pay
575
+ rescue AlreadyPaidError => error
576
+ error.message # 'The invoice is already paid.'
577
+ error.grpc.class # GRPC::AlreadyExists
578
+ error.grpc.message # '6:invoice is already paid. debug_error_string:{UNKNOWN...'
579
+ end
580
+ ```
581
+
582
+ ```ruby
583
+ begin
584
+ invoice.pay(amount: { millisatoshis: 1000 })
585
+ rescue AmountForNonZeroError => error
586
+ error.message # 'Millisatoshis must not be specified...'
587
+ error.grpc.class # GRPC::Unknown
588
+ error.grpc.message # '2:amount must not be specified when paying...'
589
+ end
590
+ ```
591
+
592
+ ```ruby
593
+ begin
594
+ invoice.pay
595
+ rescue MissingMillisatoshisError => error
596
+ error.message # 'Millisatoshis must be specified...'
597
+ error.grpc.class # GRPC::Unknown
598
+ error.grpc.message # '2:amount must be specified when paying a zero...'
599
+ end
600
+ ```
601
+
602
+ ```ruby
603
+ begin
604
+ invoice.pay
605
+ rescue NoRouteFoundError => error
606
+ error.message # 'FAILURE_REASON_NO_ROUTE'
607
+ e.response
608
+ e.response.last[:failure_reason] # => :FAILURE_REASON_NO_ROUTE
609
+ end
610
+ ```
611
+
612
+
613
+ ```ruby
614
+ begin
615
+ invoice.pay
616
+ rescue PaymentError => error
617
+ error.class
618
+ error.message
619
+
620
+ error.grpc
621
+ error.response
622
+ error.result
623
+ end
624
+ ```
416
625
  ## Payment
417
626
 
418
627
  [![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)
@@ -430,7 +639,8 @@ Lighstorm::Payment.last
430
639
  Lighstorm::Payment.all(limit: 10, purpose: 'rebalance')
431
640
 
432
641
  # Possible Purposes:
433
- ['self-payment', 'peer-to-peer', 'rebalance', 'payment']
642
+ # 'self-payment', 'peer-to-peer',
643
+ # 'rebalance', 'payment'
434
644
 
435
645
  # _key is helpful for reactive javascript frameworks.
436
646
  # Please don't consider it as a unique identifier
@@ -440,34 +650,53 @@ payment._key
440
650
 
441
651
  payment.to_h
442
652
 
443
- payment.status
444
- payment.created_at
445
- payment.settled_at
446
- payment.purpose
653
+ payment.at
654
+
655
+ payment.amount.millisatoshis
447
656
 
448
657
  payment.fee.millisatoshis
449
658
  payment.fee.parts_per_million(
450
- payment.request.amount.millisatoshis
659
+ payment.amount.millisatoshis
451
660
  )
452
661
 
453
- # https://github.com/lightning/bolts/blob/master/11-payment-encoding.md
454
- payment.request.code # "lnbc20m1pv...qqdhhwkj"
662
+ payment.state
663
+ payment.message
455
664
 
456
- payment.request.amount.millisatoshis
665
+ payment.how # 'spontaneously', 'with-invoice'
666
+ payment.through # 'keysend', 'amp', 'non-amp'
667
+ payment.purpose
668
+ # 'self-payment', 'peer-to-peer',
669
+ # 'rebalance', 'payment'
457
670
 
458
671
  # https://docs.lightning.engineering/the-lightning-network/multihop-payments
459
- payment.request.secret.preimage
460
- payment.request.secret.hash
672
+ payment.secret.preimage
673
+ payment.secret.hash
674
+
675
+ payment.invoice.created_at
676
+ payment.invoice.expires_at
677
+ payment.invoice.settled_at
678
+
679
+ payment.invoice.state
680
+
681
+ # https://github.com/lightning/bolts/blob/master/11-payment-encoding.md
682
+ payment.invoice.code # "lnbc20m1pv...qqdhhwkj"
683
+ payment.invoice.amount.millisatoshis
461
684
 
462
- payment.request.address
685
+ payment.invoice.payable # 'once', 'indefinitely'
463
686
 
464
- payment.request.description.memo
465
- payment.request.description.hash
687
+ payment.invoice.description.memo
688
+ payment.invoice.description.hash
689
+
690
+ # https://docs.lightning.engineering/the-lightning-network/multihop-payments
691
+ payment.invoice.secret.preimage
692
+ payment.invoice.secret.hash
466
693
 
467
694
  payment.from.hop
468
695
  payment.from.amount.millisatoshis
469
696
  payment.from.fee.millisatoshis
470
- payment.from.fee.parts_per_million(payment.from.amount.millisatoshis)
697
+ payment.from.fee.parts_per_million(
698
+ payment.from.amount.millisatoshis
699
+ )
471
700
 
472
701
  payment.from.channel.id
473
702
 
@@ -482,7 +711,9 @@ payment.from.channel.exit.color
482
711
  payment.to.hop
483
712
  payment.to.amount.millisatoshis
484
713
  payment.to.fee.millisatoshis
485
- payment.to.fee.parts_per_million(payment.to.amount.millisatoshis)
714
+ payment.to.fee.parts_per_million(
715
+ payment.to.amount.millisatoshis
716
+ )
486
717
 
487
718
  payment.to.channel.id
488
719
 
@@ -502,7 +733,9 @@ payment.hops[0].last?
502
733
  payment.hops[0].hop
503
734
  payment.hops[0].amount.millisatoshis
504
735
  payment.hops[0].fee.millisatoshis
505
- payment.hops[0].fee.parts_per_million(payment.hops[0].amount.millisatoshis)
736
+ payment.hops[0].fee.parts_per_million(
737
+ payment.hops[0].amount.millisatoshis
738
+ )
506
739
 
507
740
  payment.hops[0].channel.id
508
741
 
@@ -666,6 +899,7 @@ Lighstorm::Channel.adapt(dump: channel.dump)
666
899
 
667
900
  ```ruby
668
901
  Lighstorm::Satoshis
902
+ Lighstorm::Satoshis.new(bitcoins: 0.005)
669
903
  Lighstorm::Satoshis.new(millisatoshis: 75621650)
670
904
 
671
905
  satoshis.to_h
@@ -736,24 +970,26 @@ end
736
970
  ```ruby
737
971
  LighstormError
738
972
 
973
+ ArgumentError
739
974
  IncoherentGossipError
740
-
741
- TooManyArgumentsError
742
975
  MissingCredentialsError
743
976
  MissingGossipHandlerError
744
- MissingMillisatoshisError
745
977
  MissingPartsPerMillionError
746
- MissingTTLError
747
-
748
978
  NegativeNotAllowedError
749
-
750
979
  NotYourChannelError
751
980
  NotYourNodeError
752
- UnknownChannelError
753
-
754
981
  OperationNotAllowedError
982
+ TooManyArgumentsError
755
983
  UnexpectedNumberOfHTLCsError
984
+ UnknownChannelError
756
985
  UpdateChannelPolicyError
986
+
987
+ PaymentError
988
+
989
+ AlreadyPaidError
990
+ AmountForNonZeroError
991
+ MissingMillisatoshisError
992
+ NoRouteFoundError
757
993
  ```
758
994
 
759
995
  # Development
@@ -767,7 +1003,7 @@ gem 'lighstorm', path: '/home/user/lighstorm'
767
1003
  # demo.rb
768
1004
  require 'lighstorm'
769
1005
 
770
- puts Lighstorm.version # => 0.0.8
1006
+ puts Lighstorm.version # => 0.0.10
771
1007
  ```
772
1008
 
773
1009
  ```sh
@@ -827,13 +1063,15 @@ The downside is that we can't [lazy-load](https://en.wikipedia.org/wiki/Lazy_loa
827
1063
  To perform an _action_, like creating an Invoice, you:
828
1064
  ```ruby
829
1065
  Lighstorm::Invoice.create(
830
- description: 'Coffee', millisatoshis: 1000
1066
+ description: 'Coffee', amount: { millisatoshis: 1000 }
831
1067
  )
832
1068
  ```
833
1069
 
834
1070
  Internally, what's happening:
835
1071
  ```ruby
836
- action = Lighstorm::Invoice.create(description: 'Coffee', millisatoshis: 1000)
1072
+ action = Lighstorm::Invoice.create(
1073
+ description: 'Coffee', amount: { millisatoshis: 1000 }
1074
+ )
837
1075
 
838
1076
  request = Controllers::Invoice::Create.prepare(params) # pure
839
1077
  response = Controllers::Invoice::Create.dispatch(request) # side effect
@@ -969,6 +1207,24 @@ expected: nil
969
1207
 
970
1208
  Remember to undo it afterward, replacing `expect!` with `expect`.
971
1209
 
1210
+ ### Extra Tips for Testing
1211
+
1212
+ To auto-fix contracts:
1213
+
1214
+ ```sh
1215
+ rspec --format json | bundle exec rake contracts:fix
1216
+ ```
1217
+
1218
+ To delete unused test data files, update the `.env` file:
1219
+ ```sh
1220
+ LIGHSTORM_DELETE_UNUSED_TEST_DATA=true
1221
+ ```
1222
+
1223
+ Deletion will only occur if you run all tests and no failures are found:
1224
+ ```ruby
1225
+ bundle exec rspec
1226
+ ```
1227
+
972
1228
  ## Generating Documentation
973
1229
 
974
1230
  ```sh
@@ -984,13 +1240,13 @@ gem build lighstorm.gemspec
984
1240
 
985
1241
  gem signin
986
1242
 
987
- gem push lighstorm-0.0.8.gem
1243
+ gem push lighstorm-0.0.10.gem
988
1244
  ```
989
1245
 
990
1246
  _________________
991
1247
 
992
1248
  <center>
993
- lighstorm 0.0.8
1249
+ lighstorm 0.0.10
994
1250
  |
995
1251
  <a href="https://github.com/icebaker/lighstorm" rel="noopener noreferrer" target="_blank">GitHub</a>
996
1252
  |
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.8
11
+ 0.0.10
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.8',
21
+ name: 'Lighstorm 0.0.10',
22
22
  repo: 'https://github.com/icebaker/lighstorm'
23
23
  }
24
24
  </script>
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../models/errors'
4
+
5
+ module Lighstorm
6
+ module Helpers
7
+ module TimeExpression
8
+ def self.seconds(expression)
9
+ raise Errors::ArgumentError, 'missing keywords for time expression' unless expression.is_a?(Hash)
10
+
11
+ duration = 0.0
12
+ expression.each_key do |key|
13
+ case key
14
+ when :seconds
15
+ duration += expression[key].to_f
16
+ when :minutes
17
+ duration += (expression[key].to_f * 60.0)
18
+ when :hours
19
+ duration += (expression[key].to_f * 60.0 * 60.0)
20
+ when :days
21
+ duration += (expression[key].to_f * 24.0 * 60.0 * 60.0)
22
+ else
23
+ raise Errors::ArgumentError, "unexpected keyword :#{key} for time expression #{expression}"
24
+ end
25
+ end
26
+
27
+ raise Errors::ArgumentError, 'missing keywords for time expression' if expression.keys.empty?
28
+
29
+ duration.to_i
30
+ end
31
+ end
32
+ end
33
+ end
@@ -24,11 +24,11 @@ module Lighstorm
24
24
  end
25
25
 
26
26
  def amount
27
- @amount ||= Satoshis.new(millisatoshis: @data[:amount][:millisatoshis])
27
+ @amount ||= @data[:amount] ? Satoshis.new(millisatoshis: @data[:amount][:millisatoshis]) : nil
28
28
  end
29
29
 
30
30
  def fee
31
- @fee ||= Satoshis.new(millisatoshis: @data[:fee][:millisatoshis])
31
+ @fee ||= @data[:fee] ? Satoshis.new(millisatoshis: @data[:fee][:millisatoshis]) : nil
32
32
  end
33
33
 
34
34
  def channel
@@ -36,15 +36,20 @@ module Lighstorm
36
36
  end
37
37
 
38
38
  def to_h
39
- {
39
+ result = {
40
40
  hop: hop,
41
- amount: amount.to_h,
42
- fee: {
43
- millisatoshis: fee.millisatoshis,
44
- parts_per_million: fee.parts_per_million(amount.millisatoshis)
45
- },
46
41
  channel: channel.to_h
47
42
  }
43
+
44
+ result[:amount] = amount.to_h if amount
45
+ if fee
46
+ result[:fee] = {
47
+ millisatoshis: fee.millisatoshis,
48
+ parts_per_million: fee.parts_per_million(amount.millisatoshis)
49
+ }
50
+ end
51
+
52
+ result
48
53
  end
49
54
  end
50
55
  end