lighstorm 0.0.8 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
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