@psf/bch-js 5.4.1 → 6.2.1

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.
@@ -45,216 +45,6 @@ describe('#SLP Utils', () => {
45
45
  sandbox.restore()
46
46
  })
47
47
 
48
- describe('#list', () => {
49
- it('should list single SLP token by id', async () => {
50
- sandbox
51
- .stub(uut.Utils.axios, 'get')
52
- .resolves({ data: mockData.mockToken })
53
-
54
- const tokenId =
55
- '4276533bb702e7f8c9afd8aa61ebf016e95011dc3d54e55faa847ac1dd461e84'
56
-
57
- const list = await uut.Utils.list(tokenId)
58
- // console.log(`list: ${JSON.stringify(list, null, 2)}`)
59
-
60
- assert.equal(list.id, tokenId)
61
- assert.property(list, 'decimals')
62
- assert.property(list, 'symbol')
63
- assert.property(list, 'documentUri')
64
- assert.property(list, 'name')
65
- })
66
-
67
- it('should list multiple SLP tokens by array of ids', async () => {
68
- // Mock the call to the REST API
69
- sandbox
70
- .stub(uut.Utils.axios, 'post')
71
- .resolves({ data: mockData.mockList })
72
-
73
- const tokenIds = [
74
- '4276533bb702e7f8c9afd8aa61ebf016e95011dc3d54e55faa847ac1dd461e84',
75
- '8fc284dcbc922f7bb7e2a443dc3af792f52923bba403fcf67ca028c88e89da0e'
76
- ]
77
-
78
- const list = await uut.Utils.list(tokenIds)
79
- // console.log(`list: ${JSON.stringify(list, null, 2)}`)
80
-
81
- assert.isArray(list)
82
- assert.property(list[0], 'symbol')
83
- assert.property(list[1], 'symbol')
84
- })
85
- })
86
-
87
- describe('#balancesForAddress', () => {
88
- it('should throw an error if input is not a string or array of strings', async () => {
89
- try {
90
- const address = 1234
91
-
92
- await uut.Utils.balancesForAddress(address)
93
-
94
- assert.equal(true, false, 'Uh oh. Code path should not end here.')
95
- } catch (err) {
96
- // console.log(`Error: `, err)
97
- assert.include(
98
- err.message,
99
- 'Input address must be a string or array of strings'
100
- )
101
- }
102
- })
103
-
104
- it('should fetch all balances for address: simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9', async () => {
105
- // Mock the call to the REST API
106
- if (process.env.TEST === 'unit') {
107
- sandbox
108
- .stub(uut.Utils.axios, 'get')
109
- .resolves({ data: mockData.balancesForAddress })
110
- }
111
- // sandbox
112
- // .stub(uut.Utils, "balancesForAddress")
113
- // .resolves(mockData.balancesForAddress)
114
-
115
- const balances = await uut.Utils.balancesForAddress(
116
- 'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9'
117
- )
118
- // console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
119
-
120
- assert.isArray(balances)
121
- assert.hasAllKeys(balances[0], [
122
- 'tokenId',
123
- 'balanceString',
124
- 'balance',
125
- 'decimalCount',
126
- 'slpAddress'
127
- ])
128
- })
129
-
130
- it('should fetch balances for multiple addresses.', async () => {
131
- const addresses = [
132
- 'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9',
133
- 'simpleledger:qqss4zp80hn6szsa4jg2s9fupe7g5tcg5ucdyl3r57'
134
- ]
135
-
136
- // Mock the call to the REST API
137
- if (process.env.TEST === 'unit') {
138
- sandbox
139
- .stub(uut.Utils.axios, 'post')
140
- .resolves({ data: mockData.balancesForAddresses })
141
- }
142
-
143
- const balances = await uut.Utils.balancesForAddress(addresses)
144
- // console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
145
-
146
- assert.isArray(balances)
147
- assert.isArray(balances[0])
148
- assert.hasAllKeys(balances[0][0], [
149
- 'tokenId',
150
- 'balanceString',
151
- 'balance',
152
- 'decimalCount',
153
- 'slpAddress'
154
- ])
155
- })
156
- })
157
-
158
- describe('#validateTxid', () => {
159
- it('should validate slp txid', async () => {
160
- // Mock the call to the REST API
161
- sandbox
162
- .stub(uut.Utils.axios, 'post')
163
- .resolves({ data: mockData.mockIsValidTxid })
164
-
165
- const isValid = await uut.Utils.validateTxid(
166
- 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb'
167
- )
168
- assert.deepEqual(isValid, [
169
- {
170
- txid:
171
- 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
172
- valid: true
173
- }
174
- ])
175
- })
176
- })
177
-
178
- describe('#balancesForToken', () => {
179
- it('should retrieve token balances for a given tokenId', async () => {
180
- // Mock the call to the REST API
181
- sandbox
182
- .stub(uut.Utils.axios, 'get')
183
- .resolves({ data: mockData.mockBalancesForToken })
184
-
185
- const balances = await uut.Utils.balancesForToken(
186
- 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb'
187
- )
188
-
189
- assert.hasAnyKeys(balances[0], ['tokenBalance', 'slpAddress'])
190
- })
191
- })
192
-
193
- describe('#tokenStats', () => {
194
- it('should retrieve stats for a given tokenId', async () => {
195
- // Mock the call to the REST API
196
- sandbox
197
- .stub(uut.Utils.axios, 'get')
198
- .resolves({ data: mockData.mockTokenStats })
199
-
200
- const tokenStats = await uut.Utils.tokenStats(
201
- 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb'
202
- )
203
-
204
- assert.hasAnyKeys(tokenStats, [
205
- 'circulatingSupply',
206
- 'decimals',
207
- 'documentUri',
208
- 'name',
209
- 'satoshisLockedUp',
210
- 'symbol',
211
- 'tokenId',
212
- 'totalBurned',
213
- 'totalMinted',
214
- 'txnsSinceGenesis',
215
- 'validAddresses',
216
- 'validUtxos'
217
- ])
218
- })
219
- })
220
-
221
- describe('#transactions', () => {
222
- it('should retrieve transactions for a given tokenId and address', async () => {
223
- // Mock the call to the REST API
224
- sandbox
225
- .stub(uut.Utils.axios, 'get')
226
- .resolves({ data: mockData.mockTransactions })
227
-
228
- const transactions = await uut.Utils.transactions(
229
- '495322b37d6b2eae81f045eda612b95870a0c2b6069c58f70cf8ef4e6a9fd43a',
230
- 'simpleledger:qrhvcy5xlegs858fjqf8ssl6a4f7wpstaqnt0wauwu'
231
- )
232
-
233
- assert.hasAnyKeys(transactions[0], ['txid', 'tokenDetails'])
234
- })
235
- })
236
-
237
- describe('#burnTotal', () => {
238
- it('should retrieve input, output and burn totals', async () => {
239
- // Mock the call to the REST API
240
- sandbox
241
- .stub(uut.Utils.axios, 'get')
242
- .resolves({ data: mockData.mockBurnTotal })
243
-
244
- const burnTotal = await uut.Utils.burnTotal(
245
- 'c7078a6c7400518a513a0bde1f4158cf740d08d3b5bfb19aa7b6657e2f4160de'
246
- )
247
- // console.log(`burnTotal: ${JSON.stringify(burnTotal, null, 2)}`)
248
-
249
- assert.hasAnyKeys(burnTotal, [
250
- 'transactionId',
251
- 'inputTotal',
252
- 'outputTotal',
253
- 'burnTotal'
254
- ])
255
- })
256
- })
257
-
258
48
  describe('#decodeOpReturn', () => {
259
49
  it('should throw an error for a non-string input', async () => {
260
50
  try {
@@ -529,1899 +319,4 @@ describe('#SLP Utils', () => {
529
319
  }
530
320
  })
531
321
  })
532
-
533
- describe('#_hydrateUtxo', () => {
534
- // // This captures an important corner-case. When an SLP token is created, the
535
- // // change UTXO will contain the same SLP txid, but it is not an SLP UTXO.
536
- it('should return details on minting baton from genesis transaction', async () => {
537
- // Mock the call to REST API
538
- // sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
539
-
540
- // Stub the calls to decodeOpReturn.
541
- sandbox.stub(uut.Utils, 'decodeOpReturn').resolves({
542
- tokenType: 1,
543
- txType: 'GENESIS',
544
- ticker: 'SLPSDK',
545
- name: 'SLP SDK example using BITBOX',
546
- tokenId:
547
- 'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
548
- documentUri: 'developer.bitcoin.com',
549
- documentHash: '',
550
- decimals: 8,
551
- mintBatonVout: 2,
552
- qty: '50700000000'
553
- })
554
-
555
- const utxos = [
556
- {
557
- txid:
558
- 'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
559
- vout: 3,
560
- amount: 0.00002015,
561
- satoshis: 2015,
562
- height: 594892,
563
- confirmations: 5
564
- },
565
- {
566
- txid:
567
- 'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
568
- vout: 2,
569
- amount: 0.00000546,
570
- satoshis: 546,
571
- height: 594892,
572
- confirmations: 5
573
- }
574
- ]
575
-
576
- const data = await uut.Utils._hydrateUtxo(utxos)
577
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
578
-
579
- // assert.equal(data[0], false, "Change UTXO marked as false.")
580
- assert.property(data[0], 'txid')
581
- assert.property(data[0], 'vout')
582
- assert.property(data[0], 'amount')
583
- assert.property(data[0], 'satoshis')
584
- assert.property(data[0], 'height')
585
- assert.property(data[0], 'confirmations')
586
- assert.property(data[0], 'isValid')
587
- assert.equal(data[0].isValid, false)
588
-
589
- assert.property(data[1], 'txid')
590
- assert.property(data[1], 'vout')
591
- assert.property(data[1], 'amount')
592
- assert.property(data[1], 'satoshis')
593
- assert.property(data[1], 'height')
594
- assert.property(data[1], 'confirmations')
595
- assert.property(data[1], 'utxoType')
596
- assert.property(data[1], 'tokenId')
597
- assert.property(data[1], 'tokenTicker')
598
- assert.property(data[1], 'tokenName')
599
- assert.property(data[1], 'tokenDocumentUrl')
600
- assert.property(data[1], 'tokenDocumentHash')
601
- assert.property(data[1], 'decimals')
602
- })
603
-
604
- // 429 means the user is exceeding the rate limits.
605
- it('should return isValid=null for 429 rate limit error', async () => {
606
- // Force decodeOpReturn() to throw a 429 error.
607
- sandbox.stub(uut.Utils, 'decodeOpReturn').rejects(mockData.mock429Error)
608
-
609
- const utxos = [
610
- {
611
- txid:
612
- 'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
613
- vout: 3,
614
- amount: 0.00002015,
615
- satoshis: 2015,
616
- height: 594892,
617
- confirmations: 5
618
- },
619
- {
620
- txid:
621
- 'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
622
- vout: 2,
623
- amount: 0.00000546,
624
- satoshis: 546,
625
- height: 594892,
626
- confirmations: 5
627
- }
628
- ]
629
-
630
- const result = await uut.Utils._hydrateUtxo(utxos)
631
- // console.log(`result: ${JSON.stringify(result, null, 2)}`)
632
-
633
- assert.equal(result[0].isValid, null)
634
- assert.equal(result[1].isValid, null)
635
- })
636
-
637
- // 503 means the server is down or is not responding.
638
- it('should return isValid=null for 503 rate limit error', async () => {
639
- // Force decodeOpReturn() to throw a 429 error.
640
- sandbox.stub(uut.Utils, 'decodeOpReturn').rejects(mockData.mock503Error)
641
-
642
- const utxos = [
643
- {
644
- txid:
645
- 'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
646
- vout: 3,
647
- amount: 0.00002015,
648
- satoshis: 2015,
649
- height: 594892,
650
- confirmations: 5
651
- },
652
- {
653
- txid:
654
- 'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
655
- vout: 2,
656
- amount: 0.00000546,
657
- satoshis: 546,
658
- height: 594892,
659
- confirmations: 5
660
- }
661
- ]
662
-
663
- const result = await uut.Utils._hydrateUtxo(utxos)
664
- // console.log(`result: ${JSON.stringify(result, null, 2)}`)
665
-
666
- assert.equal(result[0].isValid, null)
667
- assert.equal(result[1].isValid, null)
668
- })
669
-
670
- it('should return details for a simple SEND SLP token utxo', async () => {
671
- // Mock the call to REST API
672
- // Stub the calls to decodeOpReturn.
673
- sandbox
674
- .stub(uut.Utils, 'decodeOpReturn')
675
- .onCall(0)
676
- .resolves({
677
- tokenType: 1,
678
- txType: 'SEND',
679
- tokenId:
680
- '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
681
- amounts: ['200000000', '99887500000000']
682
- })
683
- .onCall(1)
684
- .resolves({
685
- tokenType: 1,
686
- txType: 'GENESIS',
687
- ticker: 'TOK-CH',
688
- name: 'TokyoCash',
689
- tokenId:
690
- '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
691
- documentUri: '',
692
- documentHash: '',
693
- decimals: 8,
694
- mintBatonVout: 0,
695
- qty: '2100000000000000'
696
- })
697
-
698
- // sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
699
-
700
- const utxos = [
701
- {
702
- txid:
703
- 'fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb',
704
- vout: 1,
705
- amount: 0.00000546,
706
- satoshis: 546,
707
- height: 596089,
708
- confirmations: 748
709
- }
710
- ]
711
-
712
- const data = await uut.Utils._hydrateUtxo(utxos)
713
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
714
-
715
- assert.property(data[0], 'txid')
716
- assert.property(data[0], 'vout')
717
- assert.property(data[0], 'amount')
718
- assert.property(data[0], 'satoshis')
719
- assert.property(data[0], 'height')
720
- assert.property(data[0], 'confirmations')
721
- assert.property(data[0], 'utxoType')
722
- assert.property(data[0], 'tokenId')
723
- assert.property(data[0], 'tokenTicker')
724
- assert.property(data[0], 'tokenName')
725
- assert.property(data[0], 'tokenDocumentUrl')
726
- assert.property(data[0], 'tokenDocumentHash')
727
- assert.property(data[0], 'decimals')
728
- assert.property(data[0], 'tokenQty')
729
- assert.property(data[0], 'isValid')
730
- assert.equal(data[0].isValid, null)
731
- })
732
-
733
- // I don't know if this is the ideal behavior, but this is the behavior
734
- // that is in production, so I wanted to capture it in a test case. This
735
- // behavior can always be changed in the future.
736
- it('should throw error if 429 when querying Genesis transaction', async () => {
737
- try {
738
- // Mock the call to REST API
739
- // Stub the calls to decodeOpReturn.
740
- sandbox
741
- .stub(uut.Utils, 'decodeOpReturn')
742
- .onCall(0)
743
- .resolves({
744
- tokenType: 1,
745
- txType: 'SEND',
746
- tokenId:
747
- '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
748
- amounts: ['200000000', '99887500000000']
749
- })
750
- .onCall(1)
751
- .rejects(mockData.mock429Error)
752
-
753
- const utxos = [
754
- {
755
- txid:
756
- 'fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb',
757
- vout: 1,
758
- amount: 0.00000546,
759
- satoshis: 546,
760
- height: 596089,
761
- confirmations: 748
762
- }
763
- ]
764
-
765
- await uut.Utils._hydrateUtxo(utxos)
766
-
767
- assert.fail('Unexpected result')
768
- } catch (err) {
769
- // console.log('error: ', err)
770
-
771
- assert.property(err, 'message')
772
- assert.property(err, 'response')
773
- assert.equal(err.response.status, 429)
774
- assert.equal(err.response.statusText, 'Too Many Requests')
775
- assert.include(err.response.data.error, 'Too many requests')
776
- }
777
- })
778
-
779
- it('should add delay if delay is specified', async () => {
780
- // Mock the call to REST API
781
- // Stub the calls to decodeOpReturn.
782
- sandbox
783
- .stub(uut.Utils, 'decodeOpReturn')
784
- .onCall(0)
785
- .resolves({
786
- tokenType: 1,
787
- txType: 'SEND',
788
- tokenId:
789
- '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
790
- amounts: ['200000000', '99887500000000']
791
- })
792
- .onCall(1)
793
- .resolves({
794
- tokenType: 1,
795
- txType: 'GENESIS',
796
- ticker: 'TOK-CH',
797
- name: 'TokyoCash',
798
- tokenId:
799
- '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
800
- documentUri: '',
801
- documentHash: '',
802
- decimals: 8,
803
- mintBatonVout: 0,
804
- qty: '2100000000000000'
805
- })
806
-
807
- // sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
808
-
809
- const utxos = [
810
- {
811
- txid:
812
- 'fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb',
813
- vout: 1,
814
- amount: 0.00000546,
815
- satoshis: 546,
816
- height: 596089,
817
- confirmations: 748
818
- }
819
- ]
820
-
821
- const usrObj = {
822
- utxoDelay: 100
823
- }
824
-
825
- await uut.Utils._hydrateUtxo(utxos, usrObj)
826
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
827
-
828
- // TODO: This test should realy assert that the test took at least 100mS
829
- // to complete. However, as-is, it exercises the code path, so not
830
- // throwing an error can be considered a pass.
831
- assert.equal(true, true)
832
- })
833
- })
834
-
835
- describe('#tokenUtxoDetails', () => {
836
- it('should throw error if input is not an array.', async () => {
837
- try {
838
- await uut.Utils.tokenUtxoDetails('test')
839
-
840
- assert.equal(true, false, 'Unexpected result.')
841
- } catch (err) {
842
- assert.include(
843
- err.message,
844
- 'Input must be an array',
845
- 'Expected error message.'
846
- )
847
- }
848
- })
849
-
850
- it('should throw error if utxo does not have txid or tx_hash property.', async () => {
851
- try {
852
- const utxos = [
853
- {
854
- txid:
855
- 'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
856
- vout: 3,
857
- amount: 0.00002015,
858
- satoshis: 2015,
859
- height: 594892,
860
- confirmations: 5
861
- },
862
- {
863
- vout: 2,
864
- amount: 0.00000546,
865
- satoshis: 546,
866
- height: 594892,
867
- confirmations: 5
868
- }
869
- ]
870
-
871
- await uut.Utils.tokenUtxoDetails(utxos)
872
-
873
- assert.equal(true, false, 'Unexpected result.')
874
- } catch (err) {
875
- assert.include(
876
- err.message,
877
- 'utxo 1 does not have a txid or tx_hash property',
878
- 'Expected error message.'
879
- )
880
- }
881
- })
882
-
883
- // // This captures an important corner-case. When an SLP token is created, the
884
- // // change UTXO will contain the same SLP txid, but it is not an SLP UTXO.
885
- it('should return details on minting baton from genesis transaction', async () => {
886
- // Mock the call to REST API
887
- sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
888
-
889
- // Stub the calls to decodeOpReturn.
890
- sandbox.stub(uut.Utils, 'decodeOpReturn').resolves({
891
- tokenType: 1,
892
- txType: 'GENESIS',
893
- ticker: 'SLPSDK',
894
- name: 'SLP SDK example using BITBOX',
895
- tokenId:
896
- 'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
897
- documentUri: 'developer.bitcoin.com',
898
- documentHash: '',
899
- decimals: 8,
900
- mintBatonVout: 2,
901
- qty: '50700000000'
902
- })
903
-
904
- const utxos = [
905
- {
906
- txid:
907
- 'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
908
- vout: 3,
909
- amount: 0.00002015,
910
- satoshis: 2015,
911
- height: 594892,
912
- confirmations: 5
913
- },
914
- {
915
- txid:
916
- 'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
917
- vout: 2,
918
- amount: 0.00000546,
919
- satoshis: 546,
920
- height: 594892,
921
- confirmations: 5
922
- }
923
- ]
924
-
925
- const data = await uut.Utils.tokenUtxoDetails(utxos)
926
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
927
-
928
- // assert.equal(data[0], false, "Change UTXO marked as false.")
929
- assert.property(data[0], 'txid')
930
- assert.property(data[0], 'vout')
931
- assert.property(data[0], 'amount')
932
- assert.property(data[0], 'satoshis')
933
- assert.property(data[0], 'height')
934
- assert.property(data[0], 'confirmations')
935
- assert.property(data[0], 'isValid')
936
- assert.equal(data[0].isValid, false)
937
-
938
- assert.property(data[1], 'txid')
939
- assert.property(data[1], 'vout')
940
- assert.property(data[1], 'amount')
941
- assert.property(data[1], 'satoshis')
942
- assert.property(data[1], 'height')
943
- assert.property(data[1], 'confirmations')
944
- assert.property(data[1], 'utxoType')
945
- assert.property(data[1], 'tokenId')
946
- assert.property(data[1], 'tokenTicker')
947
- assert.property(data[1], 'tokenName')
948
- assert.property(data[1], 'tokenDocumentUrl')
949
- assert.property(data[1], 'tokenDocumentHash')
950
- assert.property(data[1], 'decimals')
951
- assert.property(data[1], 'isValid')
952
- assert.equal(data[1].isValid, true)
953
- })
954
-
955
- it('should return details for a MINT token utxo', async () => {
956
- // Mock the call to REST API
957
-
958
- // Stub the calls to decodeOpReturn.
959
- sandbox
960
- .stub(uut.Utils, 'decodeOpReturn')
961
- .onCall(0)
962
- .resolves({
963
- tokenType: 1,
964
- txType: 'MINT',
965
- tokenId:
966
- '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0',
967
- mintBatonVout: 2,
968
- qty: '1000000000000'
969
- })
970
- .onCall(1)
971
- .resolves({
972
- tokenType: 1,
973
- txType: 'GENESIS',
974
- ticker: 'PSF',
975
- name: 'Permissionless Software Foundation',
976
- tokenId:
977
- '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0',
978
- documentUri: 'psfoundation.cash',
979
- documentHash: '',
980
- decimals: 8,
981
- mintBatonVout: 2,
982
- qty: '1988209163133'
983
- })
984
-
985
- // Stub the call to validateTxid
986
- sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
987
-
988
- const utxos = [
989
- {
990
- txid:
991
- 'cf4b922d1e1aa56b52d752d4206e1448ea76c3ebe69b3b97d8f8f65413bd5c76',
992
- vout: 1,
993
- amount: 0.00000546,
994
- satoshis: 546,
995
- height: 600297,
996
- confirmations: 76
997
- }
998
- ]
999
-
1000
- const data = await uut.Utils.tokenUtxoDetails(utxos)
1001
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
1002
-
1003
- assert.property(data[0], 'txid')
1004
- assert.property(data[0], 'vout')
1005
- assert.property(data[0], 'amount')
1006
- assert.property(data[0], 'satoshis')
1007
- assert.property(data[0], 'height')
1008
- assert.property(data[0], 'confirmations')
1009
- assert.property(data[0], 'utxoType')
1010
- assert.property(data[0], 'transactionType')
1011
- assert.property(data[0], 'tokenId')
1012
- assert.property(data[0], 'tokenTicker')
1013
- assert.property(data[0], 'tokenName')
1014
- assert.property(data[0], 'tokenDocumentUrl')
1015
- assert.property(data[0], 'tokenDocumentHash')
1016
- assert.property(data[0], 'decimals')
1017
- assert.property(data[0], 'mintBatonVout')
1018
- assert.property(data[0], 'tokenQty')
1019
- assert.property(data[0], 'isValid')
1020
- assert.equal(data[0].isValid, true)
1021
- })
1022
-
1023
- it('should return details for a simple SEND SLP token utxo', async () => {
1024
- // Mock the call to REST API
1025
- // Stub the calls to decodeOpReturn.
1026
- sandbox
1027
- .stub(uut.Utils, 'decodeOpReturn')
1028
- .onCall(0)
1029
- .resolves({
1030
- tokenType: 1,
1031
- txType: 'SEND',
1032
- tokenId:
1033
- '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
1034
- amounts: ['200000000', '99887500000000']
1035
- })
1036
- .onCall(1)
1037
- .resolves({
1038
- tokenType: 1,
1039
- txType: 'GENESIS',
1040
- ticker: 'TOK-CH',
1041
- name: 'TokyoCash',
1042
- tokenId:
1043
- '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
1044
- documentUri: '',
1045
- documentHash: '',
1046
- decimals: 8,
1047
- mintBatonVout: 0,
1048
- qty: '2100000000000000'
1049
- })
1050
-
1051
- sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
1052
-
1053
- const utxos = [
1054
- {
1055
- txid:
1056
- 'fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb',
1057
- vout: 1,
1058
- amount: 0.00000546,
1059
- satoshis: 546,
1060
- height: 596089,
1061
- confirmations: 748
1062
- }
1063
- ]
1064
-
1065
- const data = await uut.Utils.tokenUtxoDetails(utxos)
1066
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
1067
-
1068
- assert.property(data[0], 'txid')
1069
- assert.property(data[0], 'vout')
1070
- assert.property(data[0], 'amount')
1071
- assert.property(data[0], 'satoshis')
1072
- assert.property(data[0], 'height')
1073
- assert.property(data[0], 'confirmations')
1074
- assert.property(data[0], 'utxoType')
1075
- assert.property(data[0], 'tokenId')
1076
- assert.property(data[0], 'tokenTicker')
1077
- assert.property(data[0], 'tokenName')
1078
- assert.property(data[0], 'tokenDocumentUrl')
1079
- assert.property(data[0], 'tokenDocumentHash')
1080
- assert.property(data[0], 'decimals')
1081
- assert.property(data[0], 'tokenQty')
1082
- assert.property(data[0], 'isValid')
1083
- assert.equal(data[0].isValid, true)
1084
- })
1085
-
1086
- it('should handle BCH and SLP utxos in the same TX', async () => {
1087
- // Mock external dependencies.
1088
- // sandbox
1089
- // .stub(uut.Utils, 'validateTxid')
1090
- // .resolves(mockData.mockDualValidation)
1091
- sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
1092
-
1093
- sandbox
1094
- .stub(uut.Utils, 'decodeOpReturn')
1095
- .onCall(0)
1096
- .resolves({
1097
- tokenType: 1,
1098
- txType: 'SEND',
1099
- tokenId:
1100
- 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d',
1101
- amounts: ['1', '5']
1102
- })
1103
- .onCall(1)
1104
- .resolves({
1105
- tokenType: 1,
1106
- txType: 'SEND',
1107
- tokenId:
1108
- 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d',
1109
- amounts: ['1', '5']
1110
- })
1111
- .onCall(2)
1112
- .resolves({
1113
- tokenType: 1,
1114
- txType: 'GENESIS',
1115
- ticker: 'TAP',
1116
- name: 'Thoughts and Prayers',
1117
- tokenId:
1118
- 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d',
1119
- documentUri: '',
1120
- documentHash: '',
1121
- decimals: 0,
1122
- mintBatonVout: 2,
1123
- qty: '1000000'
1124
- })
1125
-
1126
- const utxos = [
1127
- {
1128
- txid:
1129
- 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
1130
- vout: 3,
1131
- value: '6816',
1132
- height: 606848,
1133
- confirmations: 13,
1134
- satoshis: 6816
1135
- },
1136
- {
1137
- txid:
1138
- 'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
1139
- vout: 2,
1140
- value: '546',
1141
- height: 606848,
1142
- confirmations: 13,
1143
- satoshis: 546
1144
- }
1145
- ]
1146
-
1147
- const result = await uut.Utils.tokenUtxoDetails(utxos)
1148
- // console.log(`result: ${JSON.stringify(result, null, 2)}`)
1149
-
1150
- assert.isArray(result)
1151
- assert.equal(result.length, 2)
1152
-
1153
- assert.property(result[0], 'txid')
1154
- assert.property(result[0], 'vout')
1155
- assert.property(result[0], 'value')
1156
- assert.property(result[0], 'satoshis')
1157
- assert.property(result[0], 'height')
1158
- assert.property(result[0], 'confirmations')
1159
- assert.property(result[0], 'isValid')
1160
- assert.equal(result[0].isValid, false)
1161
-
1162
- assert.equal(result[1].isValid, true)
1163
- assert.equal(result[1].utxoType, 'token')
1164
- assert.equal(result[1].transactionType, 'send')
1165
- })
1166
-
1167
- it('should handle problematic utxos', async () => {
1168
- // Mock external dependencies.
1169
- // Stub the calls to decodeOpReturn.
1170
- sandbox
1171
- .stub(uut.Utils, 'decodeOpReturn')
1172
- .onCall(0)
1173
- .throws({ message: 'scriptpubkey not op_return' })
1174
- .onCall(1)
1175
- .resolves({
1176
- tokenType: 1,
1177
- txType: 'SEND',
1178
- tokenId:
1179
- 'f05faf13a29c7f5e54ab921750aafb6afaa953db863bd2cf432e918661d4132f',
1180
- amounts: ['5000000', '395010942']
1181
- })
1182
- .onCall(2)
1183
- .resolves({
1184
- tokenType: 1,
1185
- txType: 'GENESIS',
1186
- ticker: 'AUDC',
1187
- name: 'AUD Coin',
1188
- tokenId:
1189
- 'f05faf13a29c7f5e54ab921750aafb6afaa953db863bd2cf432e918661d4132f',
1190
- documentUri: 'audcoino@gmail.com',
1191
- documentHash: '',
1192
- decimals: 6,
1193
- mintBatonVout: 0,
1194
- qty: '2000000000000000000'
1195
- })
1196
-
1197
- sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
1198
-
1199
- const utxos = [
1200
- {
1201
- txid:
1202
- '0e3a217fc22612002031d317b4cecd9b692b66b52951a67b23c43041aefa3959',
1203
- vout: 0,
1204
- amount: 0.00018362,
1205
- satoshis: 18362,
1206
- height: 613483,
1207
- confirmations: 124
1208
- },
1209
- {
1210
- txid:
1211
- '67fd3c7c3a6eb0fea9ab311b91039545086220f7eeeefa367fa28e6e43009f19',
1212
- vout: 1,
1213
- amount: 0.00000546,
1214
- satoshis: 546,
1215
- height: 612075,
1216
- confirmations: 1532
1217
- }
1218
- ]
1219
-
1220
- const result = await uut.Utils.tokenUtxoDetails(utxos)
1221
- // console.log(`result: ${JSON.stringify(result, null, 2)}`)
1222
-
1223
- assert.isArray(result)
1224
- assert.equal(result.length, 2)
1225
-
1226
- assert.property(result[0], 'txid')
1227
- assert.property(result[0], 'vout')
1228
- assert.property(result[0], 'amount')
1229
- assert.property(result[0], 'satoshis')
1230
- assert.property(result[0], 'height')
1231
- assert.property(result[0], 'confirmations')
1232
- assert.property(result[0], 'isValid')
1233
- assert.equal(result[0].isValid, false)
1234
-
1235
- assert.equal(result[1].isValid, true)
1236
- assert.equal(result[1].utxoType, 'token')
1237
- assert.equal(result[1].transactionType, 'send')
1238
- })
1239
-
1240
- it('should return isValid=false for BCH-only UTXOs', async () => {
1241
- // Mock live network calls
1242
-
1243
- sandbox
1244
- .stub(uut.Utils, 'decodeOpReturn')
1245
- .throws(new Error('scriptpubkey not op_return'))
1246
-
1247
- const utxos = [
1248
- {
1249
- txid:
1250
- 'a937f792c7c9eb23b4f344ce5c233d1ac0909217d0a504d71e6b1e4efb864a3b',
1251
- vout: 0,
1252
- amount: 0.00001,
1253
- satoshis: 1000,
1254
- confirmations: 0,
1255
- ts: 1578424704
1256
- },
1257
- {
1258
- txid:
1259
- '53fd141c2e999e080a5860887441a2c45e9cbe262027e2bd2ac998fc76e43c44',
1260
- vout: 0,
1261
- amount: 0.00001,
1262
- satoshis: 1000,
1263
- confirmations: 0,
1264
- ts: 1578424634
1265
- }
1266
- ]
1267
-
1268
- const result = await uut.Utils.tokenUtxoDetails(utxos)
1269
- // console.log(`result: ${JSON.stringify(result, null, 2)}`)
1270
-
1271
- assert.isArray(result)
1272
-
1273
- assert.property(result[0], 'txid')
1274
- assert.property(result[0], 'vout')
1275
- assert.property(result[0], 'amount')
1276
- assert.property(result[0], 'satoshis')
1277
- assert.property(result[0], 'confirmations')
1278
- assert.property(result[0], 'isValid')
1279
- assert.equal(result[0].isValid, false)
1280
-
1281
- assert.property(result[1], 'txid')
1282
- assert.property(result[1], 'vout')
1283
- assert.property(result[1], 'amount')
1284
- assert.property(result[1], 'satoshis')
1285
- assert.property(result[1], 'confirmations')
1286
- assert.property(result[1], 'isValid')
1287
- assert.equal(result[1].isValid, false)
1288
- })
1289
-
1290
- it('should decode a Genesis transaction', async () => {
1291
- const slpData = {
1292
- tokenType: 1,
1293
- txType: 'GENESIS',
1294
- ticker: 'SLPTEST',
1295
- name: 'SLP Test Token',
1296
- tokenId:
1297
- 'd2ec6abff5d1c8ed9ab5db6d140dcaebb813463e42933a4a4db171e7222a0954',
1298
- documentUri: 'https://FullStack.cash',
1299
- documentHash: '',
1300
- decimals: 8,
1301
- mintBatonVout: 2,
1302
- qty: '10000000000'
1303
- }
1304
-
1305
- // Mock external dependencies.
1306
- // Stub the calls to decodeOpReturn.
1307
- sandbox.stub(uut.Utils, 'decodeOpReturn').resolves(slpData)
1308
-
1309
- sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
1310
-
1311
- const utxos = [
1312
- {
1313
- txid:
1314
- 'd2ec6abff5d1c8ed9ab5db6d140dcaebb813463e42933a4a4db171e7222a0954',
1315
- vout: 1,
1316
- value: '546',
1317
- confirmations: 0,
1318
- satoshis: 546
1319
- },
1320
- {
1321
- txid:
1322
- 'd2ec6abff5d1c8ed9ab5db6d140dcaebb813463e42933a4a4db171e7222a0954',
1323
- vout: 2,
1324
- value: '546',
1325
- confirmations: 0,
1326
- satoshis: 546
1327
- },
1328
- {
1329
- txid:
1330
- 'd2ec6abff5d1c8ed9ab5db6d140dcaebb813463e42933a4a4db171e7222a0954',
1331
- vout: 3,
1332
- value: '12178',
1333
- confirmations: 0,
1334
- satoshis: 12178
1335
- }
1336
- ]
1337
-
1338
- const data = await uut.Utils.tokenUtxoDetails(utxos)
1339
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
1340
-
1341
- assert.isArray(data)
1342
-
1343
- assert.equal(data[0].utxoType, 'token')
1344
- assert.equal(data[0].tokenQty, 100)
1345
- assert.equal(data[0].isValid, true)
1346
- assert.equal(data[0].tokenType, 1)
1347
-
1348
- assert.equal(data[1].utxoType, 'minting-baton')
1349
- assert.equal(data[1].isValid, true)
1350
- assert.equal(data[1].tokenType, 1)
1351
-
1352
- assert.equal(data[2].isValid, false)
1353
- })
1354
-
1355
- it('should decode a Mint transaction', async () => {
1356
- // Define stubbed data.
1357
- const slpData = {
1358
- tokenType: 1,
1359
- txType: 'MINT',
1360
- tokenId:
1361
- '9d35c1803ed3ab8bd23c198b027f7b3b530586494dc265de6391b74a6b090136',
1362
- mintBatonVout: 2,
1363
- qty: '10000000000'
1364
- }
1365
-
1366
- const genesisData = {
1367
- tokenType: 1,
1368
- txType: 'GENESIS',
1369
- ticker: 'SLPTEST',
1370
- name: 'SLP Test Token',
1371
- tokenId:
1372
- '9d35c1803ed3ab8bd23c198b027f7b3b530586494dc265de6391b74a6b090136',
1373
- documentUri: 'https://FullStack.cash',
1374
- documentHash: '',
1375
- decimals: 8,
1376
- mintBatonVout: 2,
1377
- qty: '10000000000'
1378
- }
1379
-
1380
- // Mock external dependencies.
1381
- // Stub the calls to decodeOpReturn.
1382
- sandbox
1383
- .stub(uut.Utils, 'decodeOpReturn')
1384
- .resolves(slpData)
1385
- .onCall(1)
1386
- .resolves(genesisData)
1387
- .onCall(2)
1388
- .resolves(slpData)
1389
- .onCall(3)
1390
- .resolves(genesisData)
1391
- .onCall(4)
1392
- .resolves(slpData)
1393
-
1394
- // Stub the call to validateTxid
1395
- // sandbox
1396
- // .stub(uut.Utils, 'validateTxid')
1397
- // .resolves(stubValid)
1398
- // .onCall(1)
1399
- // .resolves(stubValid)
1400
- sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
1401
-
1402
- const utxos = [
1403
- {
1404
- txid:
1405
- '880587f01e3112e779c0fdf1b9b859c242a28e56ead85483eeedcaa52f051a04',
1406
- vout: 1,
1407
- value: '546',
1408
- confirmations: 0,
1409
- satoshis: 546
1410
- },
1411
- {
1412
- txid:
1413
- '880587f01e3112e779c0fdf1b9b859c242a28e56ead85483eeedcaa52f051a04',
1414
- vout: 2,
1415
- value: '546',
1416
- confirmations: 0,
1417
- satoshis: 546
1418
- },
1419
- {
1420
- txid:
1421
- '880587f01e3112e779c0fdf1b9b859c242a28e56ead85483eeedcaa52f051a04',
1422
- vout: 3,
1423
- value: '10552',
1424
- confirmations: 0,
1425
- satoshis: 10552
1426
- }
1427
- ]
1428
-
1429
- const data = await uut.Utils.tokenUtxoDetails(utxos)
1430
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
1431
-
1432
- assert.isArray(data)
1433
-
1434
- assert.equal(data[0].utxoType, 'token')
1435
- assert.equal(data[0].tokenQty, 100)
1436
- assert.equal(data[0].isValid, true)
1437
- assert.equal(data[0].tokenType, 1)
1438
-
1439
- assert.equal(data[1].utxoType, 'minting-baton')
1440
- assert.equal(data[1].isValid, true)
1441
- assert.equal(data[1].tokenType, 1)
1442
-
1443
- assert.equal(data[2].isValid, false)
1444
- })
1445
-
1446
- it('should decode a NFT Group Genesis transaction', async () => {
1447
- // Define stubbed data.
1448
- const slpData = {
1449
- tokenType: 129,
1450
- txType: 'GENESIS',
1451
- ticker: 'NFTTT',
1452
- name: 'NFT Test Token',
1453
- tokenId:
1454
- '4ef6eb92950a13a69e97c2c02c7967d806aa874c0e2a6b5546a8880f2cd14bc4',
1455
- documentUri: 'https://FullStack.cash',
1456
- documentHash: '',
1457
- decimals: 0,
1458
- mintBatonVout: 2,
1459
- qty: '1'
1460
- }
1461
-
1462
- // Mock external dependencies.
1463
- // Stub the calls to decodeOpReturn.
1464
- sandbox
1465
- .stub(uut.Utils, 'decodeOpReturn')
1466
- .resolves(slpData)
1467
- .onCall(1)
1468
- .resolves(slpData)
1469
- .onCall(2)
1470
- .resolves(slpData)
1471
- .onCall(3)
1472
- .resolves(slpData)
1473
- .onCall(4)
1474
- .resolves(slpData)
1475
-
1476
- sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
1477
-
1478
- const utxos = [
1479
- {
1480
- txid:
1481
- '4ef6eb92950a13a69e97c2c02c7967d806aa874c0e2a6b5546a8880f2cd14bc4',
1482
- vout: 3,
1483
- value: '15620',
1484
- height: 638207,
1485
- confirmations: 3,
1486
- satoshis: 15620
1487
- },
1488
- {
1489
- txid:
1490
- '4ef6eb92950a13a69e97c2c02c7967d806aa874c0e2a6b5546a8880f2cd14bc4',
1491
- vout: 2,
1492
- value: '546',
1493
- height: 638207,
1494
- confirmations: 3,
1495
- satoshis: 546
1496
- },
1497
- {
1498
- txid:
1499
- '4ef6eb92950a13a69e97c2c02c7967d806aa874c0e2a6b5546a8880f2cd14bc4',
1500
- vout: 1,
1501
- value: '546',
1502
- height: 638207,
1503
- confirmations: 3,
1504
- satoshis: 546
1505
- }
1506
- ]
1507
-
1508
- const data = await uut.Utils.tokenUtxoDetails(utxos)
1509
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
1510
-
1511
- assert.isArray(data)
1512
-
1513
- assert.equal(data[0].isValid, false)
1514
-
1515
- assert.equal(data[1].utxoType, 'minting-baton')
1516
- assert.equal(data[1].isValid, true)
1517
- assert.equal(data[1].tokenType, 129)
1518
-
1519
- assert.equal(data[2].utxoType, 'token')
1520
- assert.equal(data[2].tokenType, 129)
1521
- assert.equal(data[1].isValid, true)
1522
- })
1523
-
1524
- it('should decode a NFT Group Mint transaction', async () => {
1525
- // Define stubbed data.
1526
- const slpData = {
1527
- tokenType: 129,
1528
- txType: 'MINT',
1529
- tokenId:
1530
- 'eee4b82e4bb7113eca433829144363fc45f110693c286494fbf5b5c8043cc981',
1531
- mintBatonVout: 2,
1532
- qty: '10'
1533
- }
1534
-
1535
- const genesisData = {
1536
- tokenType: 129,
1537
- txType: 'GENESIS',
1538
- ticker: 'NFTTT',
1539
- name: 'NFT Test Token',
1540
- tokenId:
1541
- 'eee4b82e4bb7113eca433829144363fc45f110693c286494fbf5b5c8043cc981',
1542
- documentUri: 'https://FullStack.cash',
1543
- documentHash: '',
1544
- decimals: 0,
1545
- mintBatonVout: 2,
1546
- qty: '1'
1547
- }
1548
-
1549
- // Mock external dependencies.
1550
- // Stub the calls to decodeOpReturn.
1551
- sandbox
1552
- .stub(uut.Utils, 'decodeOpReturn')
1553
- .resolves(slpData)
1554
- .onCall(1)
1555
- .resolves(slpData)
1556
- .onCall(2)
1557
- .resolves(genesisData)
1558
- .onCall(3)
1559
- .resolves(slpData)
1560
- .onCall(4)
1561
- .resolves(genesisData)
1562
-
1563
- sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
1564
-
1565
- const utxos = [
1566
- {
1567
- txid:
1568
- '35846676e7514658bbd2fd60b1f0d4d86195908f6b2de5328d54c8e4a2d05919',
1569
- vout: 3,
1570
- value: '15620',
1571
- height: 638207,
1572
- confirmations: 3,
1573
- satoshis: 15620
1574
- },
1575
- {
1576
- txid:
1577
- '35846676e7514658bbd2fd60b1f0d4d86195908f6b2de5328d54c8e4a2d05919',
1578
- vout: 2,
1579
- value: '546',
1580
- height: 638207,
1581
- confirmations: 3,
1582
- satoshis: 546
1583
- },
1584
- {
1585
- txid:
1586
- '35846676e7514658bbd2fd60b1f0d4d86195908f6b2de5328d54c8e4a2d05919',
1587
- vout: 1,
1588
- value: '546',
1589
- height: 638207,
1590
- confirmations: 3,
1591
- satoshis: 546
1592
- }
1593
- ]
1594
-
1595
- const data = await uut.Utils.tokenUtxoDetails(utxos)
1596
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
1597
-
1598
- assert.isArray(data)
1599
-
1600
- assert.equal(data[0].isValid, false)
1601
-
1602
- assert.equal(data[1].utxoType, 'minting-baton')
1603
- assert.equal(data[1].tokenType, 129)
1604
- assert.equal(data[1].isValid, true)
1605
-
1606
- assert.equal(data[2].utxoType, 'token')
1607
- assert.equal(data[2].tokenType, 129)
1608
- assert.equal(data[2].isValid, true)
1609
- })
1610
-
1611
- it('should decode a NFT Child Genesis transaction', async () => {
1612
- // Define stubbed data.
1613
- const slpData = {
1614
- tokenType: 65,
1615
- txType: 'GENESIS',
1616
- ticker: 'NFTC',
1617
- name: 'NFT Child',
1618
- tokenId:
1619
- '9b6db26b64aedcedc0bd9a3037b29b3598573ec5cea99eec03faa838616cd683',
1620
- documentUri: 'https://FullStack.cash',
1621
- documentHash: '',
1622
- decimals: 0,
1623
- mintBatonVout: 0,
1624
- qty: '1'
1625
- }
1626
-
1627
- // Mock external dependencies.
1628
- // Stub the calls to decodeOpReturn.
1629
- sandbox
1630
- .stub(uut.Utils, 'decodeOpReturn')
1631
- .resolves(slpData)
1632
- .onCall(1)
1633
- .resolves(slpData)
1634
-
1635
- sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
1636
-
1637
- const utxos = [
1638
- {
1639
- txid:
1640
- '9b6db26b64aedcedc0bd9a3037b29b3598573ec5cea99eec03faa838616cd683',
1641
- vout: 1,
1642
- value: '546',
1643
- confirmations: 0,
1644
- satoshis: 546
1645
- },
1646
- {
1647
- txid:
1648
- '9b6db26b64aedcedc0bd9a3037b29b3598573ec5cea99eec03faa838616cd683',
1649
- vout: 2,
1650
- value: '13478',
1651
- confirmations: 0,
1652
- satoshis: 13478
1653
- }
1654
- ]
1655
-
1656
- const data = await uut.Utils.tokenUtxoDetails(utxos)
1657
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
1658
-
1659
- assert.isArray(data)
1660
-
1661
- assert.equal(data[0].utxoType, 'token')
1662
- assert.equal(data[0].tokenType, 65)
1663
- assert.equal(data[0].isValid, true)
1664
-
1665
- assert.equal(data[1].isValid, false)
1666
- })
1667
-
1668
- it('should decode an NFT Child Send transaction', async () => {
1669
- // Define stubbed data.
1670
- const slpData = {
1671
- tokenType: 65,
1672
- txType: 'SEND',
1673
- tokenId:
1674
- '9b6db26b64aedcedc0bd9a3037b29b3598573ec5cea99eec03faa838616cd683',
1675
- amounts: ['1']
1676
- }
1677
-
1678
- const genesisData = {
1679
- tokenType: 65,
1680
- txType: 'GENESIS',
1681
- ticker: 'NFTC',
1682
- name: 'NFT Child',
1683
- tokenId:
1684
- '9b6db26b64aedcedc0bd9a3037b29b3598573ec5cea99eec03faa838616cd683',
1685
- documentUri: 'https://FullStack.cash',
1686
- documentHash: '',
1687
- decimals: 0,
1688
- mintBatonVout: 0,
1689
- qty: '1'
1690
- }
1691
-
1692
- // Mock external dependencies.
1693
- // Stub the calls to decodeOpReturn.
1694
- sandbox
1695
- .stub(uut.Utils, 'decodeOpReturn')
1696
- .resolves(slpData)
1697
- .onCall(1)
1698
- .resolves(genesisData)
1699
- .onCall(2)
1700
- .resolves(slpData)
1701
-
1702
- sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
1703
-
1704
- const utxos = [
1705
- {
1706
- txid:
1707
- '6d68a7ffbb63ef851c43025f801a1d365cddda50b00741bca022c743d74cd61a',
1708
- vout: 1,
1709
- value: '546',
1710
- confirmations: 0,
1711
- satoshis: 546
1712
- },
1713
- {
1714
- txid:
1715
- '6d68a7ffbb63ef851c43025f801a1d365cddda50b00741bca022c743d74cd61a',
1716
- vout: 2,
1717
- value: '12136',
1718
- confirmations: 0,
1719
- satoshis: 12136
1720
- }
1721
- ]
1722
-
1723
- const data = await uut.Utils.tokenUtxoDetails(utxos)
1724
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
1725
-
1726
- assert.isArray(data)
1727
-
1728
- assert.equal(data[0].utxoType, 'token')
1729
- assert.equal(data[0].transactionType, 'send')
1730
- assert.equal(data[0].tokenType, 65)
1731
- assert.equal(data[0].isValid, true)
1732
-
1733
- assert.equal(data[1].isValid, false)
1734
- })
1735
-
1736
- it('should decode an NFT Group Send transaction', async () => {
1737
- // Define stubbed data.
1738
- const slpData = {
1739
- tokenType: 129,
1740
- txType: 'SEND',
1741
- tokenId:
1742
- 'eee4b82e4bb7113eca433829144363fc45f110693c286494fbf5b5c8043cc981',
1743
- amounts: ['1', '8']
1744
- }
1745
-
1746
- const genesisData = {
1747
- tokenType: 129,
1748
- txType: 'GENESIS',
1749
- ticker: 'NFTTT',
1750
- name: 'NFT Test Token',
1751
- tokenId:
1752
- 'eee4b82e4bb7113eca433829144363fc45f110693c286494fbf5b5c8043cc981',
1753
- documentUri: 'https://FullStack.cash',
1754
- documentHash: '',
1755
- decimals: 0,
1756
- mintBatonVout: 2,
1757
- qty: '1'
1758
- }
1759
-
1760
- // Mock external dependencies.
1761
- // Stub the calls to decodeOpReturn.
1762
- sandbox
1763
- .stub(uut.Utils, 'decodeOpReturn')
1764
- .resolves(slpData)
1765
- .onCall(1)
1766
- .resolves(genesisData)
1767
- .onCall(2)
1768
- .resolves(slpData)
1769
- .onCall(3)
1770
- .resolves(genesisData)
1771
- .onCall(4)
1772
- .resolves(slpData)
1773
-
1774
- sandbox.stub(uut.Utils, 'waterfallValidateTxid').resolves(true)
1775
-
1776
- const utxos = [
1777
- {
1778
- txid:
1779
- '57cc47c265ce878679e95e2cec510d8a1a9840f5c62feb4743cc5947d57d9766',
1780
- vout: 1,
1781
- value: '546',
1782
- confirmations: 0,
1783
- satoshis: 546
1784
- },
1785
- {
1786
- txid:
1787
- '57cc47c265ce878679e95e2cec510d8a1a9840f5c62feb4743cc5947d57d9766',
1788
- vout: 2,
1789
- value: '546',
1790
- confirmations: 0,
1791
- satoshis: 546
1792
- },
1793
- {
1794
- txid:
1795
- '57cc47c265ce878679e95e2cec510d8a1a9840f5c62feb4743cc5947d57d9766',
1796
- vout: 3,
1797
- value: '10794',
1798
- confirmations: 0,
1799
- satoshis: 10794
1800
- }
1801
- ]
1802
-
1803
- const data = await uut.Utils.tokenUtxoDetails(utxos)
1804
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
1805
-
1806
- assert.isArray(data)
1807
-
1808
- assert.equal(data[0].utxoType, 'token')
1809
- assert.equal(data[0].transactionType, 'send')
1810
- assert.equal(data[0].tokenType, 129)
1811
- assert.equal(data[0].isValid, true)
1812
-
1813
- assert.equal(data[1].utxoType, 'token')
1814
- assert.equal(data[1].transactionType, 'send')
1815
- assert.equal(data[1].tokenType, 129)
1816
- assert.equal(data[1].isValid, true)
1817
-
1818
- assert.equal(data[2].isValid, false)
1819
- })
1820
-
1821
- it('should return null value when 429 recieved', async () => {
1822
- const utxos = [
1823
- {
1824
- height: 654522,
1825
- tx_hash:
1826
- '072a1e2c2d5f1309bf4eef7f88684e4ecd544a903b386b07f3e04b91b13d8af1',
1827
- tx_pos: 0,
1828
- value: 6999,
1829
- satoshis: 6999,
1830
- txid:
1831
- '072a1e2c2d5f1309bf4eef7f88684e4ecd544a903b386b07f3e04b91b13d8af1',
1832
- vout: 0
1833
- },
1834
- {
1835
- height: 654522,
1836
- tx_hash:
1837
- 'a72db6a0883ecb8e379f317231b2571e41e041b7b1107e3e54c2e0b3386ac6ca',
1838
- tx_pos: 1,
1839
- value: 546,
1840
- satoshis: 546,
1841
- txid:
1842
- 'a72db6a0883ecb8e379f317231b2571e41e041b7b1107e3e54c2e0b3386ac6ca',
1843
- vout: 1
1844
- }
1845
- ]
1846
-
1847
- sandbox.stub(uut.Utils, 'decodeOpReturn').rejects({
1848
- error:
1849
- 'Too many requests. Your limits are currently 3 requests per minute. Increase rate limits at https://fullstack.cash'
1850
- })
1851
-
1852
- const data = await uut.Utils.tokenUtxoDetails(utxos)
1853
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
1854
-
1855
- // Values should be 'null' to signal that a determination could not be made
1856
- // due to a throttling issue.
1857
- assert.equal(data[0].isValid, null)
1858
- assert.equal(data[1].isValid, null)
1859
- })
1860
-
1861
- // it("should handle a dust attack", async () => {
1862
- it('should handle dust attack UTXOs', async () => {
1863
- // Mock external dependencies.
1864
- // Stub the calls to decodeOpReturn.
1865
- sandbox
1866
- .stub(uut.Utils, 'decodeOpReturn')
1867
- .rejects(new Error('lokad id wrong size'))
1868
-
1869
- const utxos = [
1870
- {
1871
- height: 655965,
1872
- tx_hash:
1873
- 'a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e',
1874
- tx_pos: 151,
1875
- value: 547,
1876
- satoshis: 547,
1877
- txid:
1878
- 'a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e',
1879
- vout: 151,
1880
- address: 'bitcoincash:qq4dw3sm8qvglspy6w2qg0u2ugsy9zcfcqrpeflwww',
1881
- hdIndex: 11
1882
- }
1883
- ]
1884
-
1885
- const data = await uut.Utils.tokenUtxoDetails(utxos)
1886
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
1887
-
1888
- assert.equal(data[0].isValid, false)
1889
- })
1890
-
1891
- it('should invalidate a malformed SLP OP_RETURN', async () => {
1892
- sandbox
1893
- .stub(uut.Utils, 'decodeOpReturn')
1894
- .rejects(new Error('trailing data'))
1895
-
1896
- const utxos = [
1897
- // Malformed SLP tx
1898
- {
1899
- note: 'Malformed SLP tx',
1900
- tx_hash:
1901
- 'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
1902
- tx_pos: 1,
1903
- value: 546
1904
- }
1905
- ]
1906
-
1907
- const data = await uut.Utils.tokenUtxoDetails(utxos)
1908
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
1909
-
1910
- assert.equal(data[0].isValid, false)
1911
- })
1912
- })
1913
-
1914
- describe('#tokenUtxoDetailsWL', () => {
1915
- it('should return details for a simple SEND SLP token utxo', async () => {
1916
- // Mock the call to REST API
1917
- // Stub the calls to decodeOpReturn.
1918
- sandbox
1919
- .stub(uut.Utils, 'decodeOpReturn')
1920
- .onCall(0)
1921
- .resolves({
1922
- tokenType: 1,
1923
- txType: 'SEND',
1924
- tokenId:
1925
- '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
1926
- amounts: ['200000000', '99887500000000']
1927
- })
1928
- .onCall(1)
1929
- .resolves({
1930
- tokenType: 1,
1931
- txType: 'GENESIS',
1932
- ticker: 'TOK-CH',
1933
- name: 'TokyoCash',
1934
- tokenId:
1935
- '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
1936
- documentUri: '',
1937
- documentHash: '',
1938
- decimals: 8,
1939
- mintBatonVout: 0,
1940
- qty: '2100000000000000'
1941
- })
1942
-
1943
- // Stub the call to validateTxid
1944
- sandbox.stub(uut.Utils, 'validateTxid3').resolves([
1945
- {
1946
- txid:
1947
- 'fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb',
1948
- valid: true
1949
- }
1950
- ])
1951
-
1952
- const utxos = [
1953
- {
1954
- txid:
1955
- 'fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb',
1956
- vout: 1,
1957
- amount: 0.00000546,
1958
- satoshis: 546,
1959
- height: 596089,
1960
- confirmations: 748
1961
- }
1962
- ]
1963
-
1964
- const data = await uut.Utils.tokenUtxoDetailsWL(utxos)
1965
- // console.log(`data: ${JSON.stringify(data, null, 2)}`)
1966
-
1967
- assert.property(data[0], 'txid')
1968
- assert.property(data[0], 'vout')
1969
- assert.property(data[0], 'height')
1970
- assert.property(data[0], 'utxoType')
1971
- assert.property(data[0], 'tokenId')
1972
- assert.property(data[0], 'tokenTicker')
1973
- assert.property(data[0], 'tokenName')
1974
- assert.property(data[0], 'tokenDocumentUrl')
1975
- assert.property(data[0], 'tokenDocumentHash')
1976
- assert.property(data[0], 'decimals')
1977
- assert.property(data[0], 'tokenQty')
1978
- assert.property(data[0], 'isValid')
1979
- assert.equal(data[0].isValid, true)
1980
- })
1981
- })
1982
-
1983
- describe('#txDetails', () => {
1984
- it('should throw an error if txid is not included', async () => {
1985
- try {
1986
- await uut.Utils.txDetails()
1987
- } catch (err) {
1988
- assert.include(
1989
- err.message,
1990
- 'txid string must be included',
1991
- 'Expected error message.'
1992
- )
1993
- }
1994
- })
1995
-
1996
- it('should throw error for non-existent txid', async () => {
1997
- try {
1998
- // Mock the call to the REST API
1999
- if (process.env.TEST === 'unit') {
2000
- sandbox
2001
- .stub(uut.Utils.axios, 'get')
2002
- // .resolves({ data: mockData.nonSLPTxDetailsWithoutOpReturn })
2003
- .throws({ error: 'TXID not found' })
2004
- }
2005
-
2006
- const txid =
2007
- 'd284e71227ec89f714b964d8eda595be6392bebd2fac46082bc5a9ce6fb7b33e'
2008
-
2009
- await uut.Utils.txDetails(txid)
2010
- // console.log(`result: ${JSON.stringify(result, null, 2)}`)
2011
-
2012
- assert.fail('Unexpected result')
2013
- } catch (err) {
2014
- // console.log(`err: `, err)
2015
- assert.include(err.error, 'TXID not found', 'Expected error message.')
2016
- }
2017
- })
2018
-
2019
- it('should return details for an SLP txid', async () => {
2020
- // Mock the call to the REST API
2021
- if (process.env.TEST === 'unit') {
2022
- sandbox
2023
- .stub(uut.Utils.axios, 'get')
2024
- .resolves({ data: mockData.mockTxDetails })
2025
- }
2026
-
2027
- const txid =
2028
- '9dbaaafc48c49a21beabada8de632009288a2cd52eecefd0c00edcffca9955d0'
2029
-
2030
- const result = await uut.Utils.txDetails(txid)
2031
- // console.log(`result: ${JSON.stringify(result, null, 2)}`)
2032
-
2033
- assert.hasAnyKeys(result, [
2034
- 'txid',
2035
- 'version',
2036
- 'locktime',
2037
- 'vin',
2038
- 'vout',
2039
- 'blockhash',
2040
- 'blockheight',
2041
- 'confirmations',
2042
- 'time',
2043
- 'blocktime',
2044
- 'valueOut',
2045
- 'size',
2046
- 'valueIn',
2047
- 'fees',
2048
- 'tokenInfo',
2049
- 'tokenIsValid'
2050
- ])
2051
- })
2052
- })
2053
-
2054
- describe('#hydrateUtxos', () => {
2055
- it('should throw an error if input is not an array', async () => {
2056
- try {
2057
- const utxos = 1234
2058
-
2059
- await uut.Utils.hydrateUtxos(utxos)
2060
-
2061
- assert.equal(true, false, 'Uh oh. Code path should not end here.')
2062
- } catch (err) {
2063
- // console.log(`Error: `, err)
2064
- assert.include(err.message, 'Input must be an array.')
2065
- }
2066
- })
2067
- })
2068
-
2069
- describe('#hydrateUtxosWL', () => {
2070
- it('should throw an error if input is not an array', async () => {
2071
- try {
2072
- const utxos = 1234
2073
-
2074
- await uut.Utils.hydrateUtxosWL(utxos)
2075
-
2076
- assert.equal(true, false, 'Uh oh. Code path should not end here.')
2077
- } catch (err) {
2078
- // console.log(`Error: `, err)
2079
- assert.include(err.message, 'Input must be an array.')
2080
- }
2081
- })
2082
- })
2083
-
2084
- describe('#validateTxid2', () => {
2085
- it('should throw an error if the input is an array', async () => {
2086
- try {
2087
- const txid = [
2088
- 'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
2089
- ]
2090
-
2091
- await uut.Utils.validateTxid2(txid)
2092
-
2093
- assert.equal(true, false, 'Unexpected result')
2094
- } catch (err) {
2095
- // console.log("err: ", err)
2096
- assert.include(err.message, 'txid must be 64 character string')
2097
- }
2098
- })
2099
-
2100
- it('should throw an error for a malformed txid', async () => {
2101
- try {
2102
- const txid =
2103
- 'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783'
2104
-
2105
- await uut.Utils.validateTxid2(txid)
2106
-
2107
- assert.equal(true, false, 'Unexpected result')
2108
- } catch (err) {
2109
- // console.log("err: ", err)
2110
- assert.include(err.message, 'txid must be 64 character string')
2111
- }
2112
- })
2113
-
2114
- it('should invalidate a known invalid TXID', async () => {
2115
- const txid =
2116
- 'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
2117
-
2118
- // Mock live network calls.
2119
- sandbox.stub(uut.Utils.axios, 'get').resolves({
2120
- data: {
2121
- txid: txid,
2122
- isValid: false,
2123
- msg: ''
2124
- }
2125
- })
2126
-
2127
- const result = await uut.Utils.validateTxid2(txid)
2128
- // console.log(`result: ${JSON.stringify(result, null, 2)}`)
2129
-
2130
- assert.property(result, 'txid')
2131
- assert.equal(result.txid, txid)
2132
-
2133
- assert.property(result, 'isValid')
2134
- assert.equal(result.isValid, false)
2135
- })
2136
-
2137
- it('should validate a known valid TXID', async () => {
2138
- const txid =
2139
- '3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488'
2140
-
2141
- // Mock live network calls.
2142
- sandbox.stub(uut.Utils.axios, 'get').resolves({
2143
- data: {
2144
- txid: txid,
2145
- isValid: true,
2146
- msg: ''
2147
- }
2148
- })
2149
-
2150
- const result = await uut.Utils.validateTxid2(txid)
2151
- // console.log(`result: ${JSON.stringify(result, null, 2)}`)
2152
-
2153
- assert.property(result, 'txid')
2154
- assert.equal(result.txid, txid)
2155
-
2156
- assert.property(result, 'isValid')
2157
- assert.equal(result.isValid, true)
2158
- })
2159
-
2160
- // slp-validate can take a long time. bch-api cuts it off if it fails to
2161
- // return is less than 10 seconds. This test case handle this situation.
2162
- it('should handle timeout errors', async () => {
2163
- try {
2164
- const txid =
2165
- 'eacb1085dfa296fef6d4ae2c0f4529a1bef096dd2325bdcc6dcb5241b3bdb579'
2166
-
2167
- // Mock live network calls.
2168
- sandbox.stub(uut.Utils.axios, 'get').rejects({
2169
- error:
2170
- 'Network error: Could not communicate with full node or other external service.'
2171
- })
2172
-
2173
- await uut.Utils.validateTxid2(txid)
2174
-
2175
- assert.equal(true, false, 'Unexpected result')
2176
- } catch (err) {
2177
- // console.log("err: ", err)
2178
- assert.include(err.message, 'slp-validate timed out')
2179
- }
2180
- })
2181
- })
2182
-
2183
- describe('#validateTxid', () => {
2184
- it('should invalidate a known invalid TXID', async () => {
2185
- const txid =
2186
- 'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
2187
-
2188
- // Mock live network calls.
2189
- sandbox.stub(uut.Utils.axios, 'post').resolves({
2190
- data: mockData.mockValidateTxid3Invalid
2191
- })
2192
-
2193
- const result = await uut.Utils.validateTxid(txid)
2194
- // console.log(`result: ${JSON.stringify(result, null, 2)}`)
2195
-
2196
- assert.isArray(result)
2197
-
2198
- assert.property(result[0], 'txid')
2199
- assert.equal(result[0].txid, txid)
2200
-
2201
- assert.property(result[0], 'valid')
2202
- assert.equal(result[0].valid, null)
2203
- })
2204
- /*
2205
- it("should handle a mix of valid, invalid, and non-SLP txs", async () => {
2206
- const txids = [
2207
- // Malformed SLP tx
2208
- "f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a",
2209
- // Normal TX (non-SLP)
2210
- "01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0",
2211
- // Valid PSF SLP tx
2212
- "daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd",
2213
- // Valid SLP token not in whitelist
2214
- "3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488"
2215
- ]
2216
-
2217
- const result = await uut.Utils.validateTxid(txids)
2218
- console.log(`result: ${JSON.stringify(result, null, 2)}`)
2219
- })
2220
- */
2221
- })
2222
-
2223
- describe('#waterfallValidateTxid', () => {
2224
- // This test ensures that the whitelist SLPDB is called before the
2225
- // general purpose SLPDB.
2226
- it('should call validateTxid3() first', async () => {
2227
- const txid = 'fakeTxid'
2228
-
2229
- const retVal = [{ txid, valid: true }]
2230
-
2231
- // Use stubs to force the desired code path.
2232
- sandbox.stub(uut.Utils, 'validateTxid3').resolves(retVal)
2233
- sandbox
2234
- .stub(uut.Utils, 'validateTxid')
2235
- .rejects(new Error('Unexpected code path'))
2236
- sandbox
2237
- .stub(uut.Utils, 'validateTxid2')
2238
- .rejects(new Error('Unexpected code path'))
2239
-
2240
- const result = await uut.Utils.waterfallValidateTxid(txid)
2241
- // console.log(`result: ${JSON.stringify(result, null, 2)}`)
2242
-
2243
- assert.equal(result, true)
2244
- })
2245
-
2246
- // This test ensures that the general purpose SLPDB is called after the
2247
- // whitelist SLPDB, but before slp-api.
2248
- it('should call validateTxid() second', async () => {
2249
- const txid = 'fakeTxid'
2250
-
2251
- const retVal1 = [{ txid, valid: null }]
2252
- const retVal2 = [{ txid, valid: true }]
2253
-
2254
- // Use stubs to force the desired code path.
2255
- sandbox.stub(uut.Utils, 'validateTxid3').resolves(retVal1)
2256
- sandbox.stub(uut.Utils, 'validateTxid').resolves(retVal2)
2257
- sandbox
2258
- .stub(uut.Utils, 'validateTxid2')
2259
- .rejects(new Error('Unexpected code path'))
2260
-
2261
- const result = await uut.Utils.waterfallValidateTxid(txid)
2262
- // console.log(`result: ${JSON.stringify(result, null, 2)}`)
2263
-
2264
- assert.equal(result, true)
2265
- })
2266
-
2267
- // This test ensures that slp-api is called if both SLPDBs return null.
2268
- it('should call slp-api last', async () => {
2269
- const txid = 'fakeTxid'
2270
-
2271
- const retVal1 = [{ txid, valid: null }]
2272
-
2273
- // Use stubs to force the desired code path.
2274
- sandbox.stub(uut.Utils, 'validateTxid3').resolves(retVal1)
2275
- sandbox.stub(uut.Utils, 'validateTxid').resolves(retVal1)
2276
- sandbox.stub(uut.Utils, 'validateTxid2').resolves({ isValid: true })
2277
-
2278
- const result = await uut.Utils.waterfallValidateTxid(txid)
2279
- // console.log(`result: ${JSON.stringify(result, null, 2)}`)
2280
-
2281
- assert.equal(result, true)
2282
- })
2283
-
2284
- // CT 08-09-21 Changed behavior. validateTxid3() is now wrapped in a
2285
- // try/catch statement that exits quietly if there is an error.
2286
- // it('catches and throws an error', async () => {
2287
- // try {
2288
- // const txid = 'fakeTxid'
2289
- //
2290
- // // Force an error
2291
- // sandbox
2292
- // .stub(uut.Utils, 'validateTxid3')
2293
- // .rejects(new Error('fake error'))
2294
- //
2295
- // await await uut.Utils.waterfallValidateTxid(txid)
2296
- //
2297
- // assert.fail('Unexpected result')
2298
- // } catch (err) {
2299
- // // console.log(`err.message: ${err.message}`)
2300
- // assert.include(err.message, 'fake error')
2301
- // }
2302
- // })
2303
- })
2304
-
2305
- describe('#getWhitelist', () => {
2306
- it('should return the list', async () => {
2307
- sandbox
2308
- .stub(uut.Utils.axios, 'get')
2309
- .resolves({ data: mockData.mockWhitelist })
2310
-
2311
- const result = await uut.Utils.getWhitelist()
2312
-
2313
- assert.isArray(result)
2314
- assert.property(result[0], 'name')
2315
- assert.property(result[1], 'tokenId')
2316
- })
2317
-
2318
- it('catches and throws an error', async () => {
2319
- try {
2320
- sandbox.stub(uut.Utils.axios, 'get').rejects({
2321
- error:
2322
- 'Network error: Could not communicate with full node or other external service.'
2323
- })
2324
-
2325
- await uut.Utils.getWhitelist()
2326
-
2327
- assert.fail('Unexpected result')
2328
- } catch (err) {
2329
- console.log('err: ', err)
2330
- assert.include(err.error, 'Network error')
2331
- }
2332
- })
2333
- })
2334
-
2335
- describe('#validateTxid3', () => {
2336
- it('should invalidate a known invalid TXID', async () => {
2337
- const txid =
2338
- 'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
2339
-
2340
- // Mock live network calls.
2341
- sandbox.stub(uut.Utils.axios, 'post').resolves({
2342
- data: mockData.mockValidateTxid3Invalid
2343
- })
2344
-
2345
- const result = await uut.Utils.validateTxid3(txid)
2346
- // console.log(`result: ${JSON.stringify(result, null, 2)}`)
2347
-
2348
- assert.isArray(result)
2349
-
2350
- assert.property(result[0], 'txid')
2351
- assert.equal(result[0].txid, txid)
2352
-
2353
- assert.property(result[0], 'valid')
2354
- assert.equal(result[0].valid, null)
2355
- })
2356
-
2357
- it('should handle an array with a single element', async () => {
2358
- sandbox
2359
- .stub(uut.Utils.axios, 'post')
2360
- .resolves({ data: mockData.mockValidateTxid3Valid })
2361
-
2362
- const txid = [
2363
- 'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd'
2364
- ]
2365
-
2366
- const result = await uut.Utils.validateTxid3(txid)
2367
-
2368
- assert.isArray(result)
2369
-
2370
- assert.property(result[0], 'txid')
2371
- assert.equal(result[0].txid, txid)
2372
-
2373
- assert.property(result[0], 'valid')
2374
- assert.equal(result[0].valid, true)
2375
- })
2376
-
2377
- it('should handle an single string input', async () => {
2378
- sandbox
2379
- .stub(uut.Utils.axios, 'post')
2380
- .resolves({ data: mockData.mockValidateTxid3Valid })
2381
-
2382
- const txid =
2383
- 'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd'
2384
-
2385
- const result = await uut.Utils.validateTxid3(txid)
2386
-
2387
- assert.isArray(result)
2388
-
2389
- assert.property(result[0], 'txid')
2390
- assert.equal(result[0].txid, txid)
2391
-
2392
- assert.property(result[0], 'valid')
2393
- assert.equal(result[0].valid, true)
2394
- })
2395
-
2396
- it('catches and throws an error', async () => {
2397
- try {
2398
- sandbox.stub(uut.Utils.axios, 'post').rejects({
2399
- error:
2400
- 'Network error: Could not communicate with full node or other external service.'
2401
- })
2402
-
2403
- await uut.Utils.validateTxid3()
2404
-
2405
- assert.equal(true, false, 'Unexpected result')
2406
- } catch (err) {
2407
- // console.log("err: ", err)
2408
- assert.include(err.error, 'Network error')
2409
- }
2410
- })
2411
- })
2412
-
2413
- describe('#getStatus', () => {
2414
- it('should return the current block height of the SLPDB indexer', async () => {
2415
- sandbox
2416
- .stub(uut.Utils.axios, 'get')
2417
- .resolves({ data: mockData.slpdbStatus })
2418
-
2419
- const result = await uut.Utils.getStatus()
2420
-
2421
- // console.log(`result: `, result)
2422
-
2423
- assert.property(result, 'bchBlockHeight')
2424
- assert.property(result, 'slpProcessedBlockHeight')
2425
- })
2426
- })
2427
322
  })