edge-currency-plugins 1.0.0-rc.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.
Files changed (233) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/lib/bch.js +15 -0
  4. package/lib/bsv.js +15 -0
  5. package/lib/btc.js +15 -0
  6. package/lib/common/constants.js +11 -0
  7. package/lib/common/fees/calcMinerFeePerByte.js +62 -0
  8. package/lib/common/fees/makeFees.js +182 -0
  9. package/lib/common/fees/processInfoServerFees.js +30 -0
  10. package/lib/common/fees/processMempoolSpaceFees.js +38 -0
  11. package/lib/common/plugin/makeCurrencyPlugin.js +66 -0
  12. package/lib/common/plugin/makeCurrencyTools.js +211 -0
  13. package/lib/common/plugin/makeEngineEmitter.js +102 -0
  14. package/lib/common/plugin/makeMetadata.js +99 -0
  15. package/lib/common/plugin/pluginState.js +253 -0
  16. package/lib/common/plugin/serverScores.js +328 -0
  17. package/lib/common/plugin/types.js +173 -0
  18. package/lib/common/plugin/utils.js +18 -0
  19. package/lib/common/utxobased/db/Models/ProcessorTransaction.js +122 -0
  20. package/lib/common/utxobased/db/Models/baselet.js +81 -0
  21. package/lib/common/utxobased/db/makeBaselets.js +123 -0
  22. package/lib/common/utxobased/db/makeMutex.js +17 -0
  23. package/lib/common/utxobased/db/makeProcessor.js +554 -0
  24. package/lib/common/utxobased/db/types.js +67 -0
  25. package/lib/common/utxobased/engine/await-lock.js +65 -0
  26. package/lib/common/utxobased/engine/constants.js +7 -0
  27. package/lib/common/utxobased/engine/makeServerStates.js +394 -0
  28. package/lib/common/utxobased/engine/makeUtxoEngine.js +690 -0
  29. package/lib/common/utxobased/engine/makeUtxoEngineState.js +1443 -0
  30. package/lib/common/utxobased/engine/makeUtxoWalletTools.js +216 -0
  31. package/lib/common/utxobased/engine/paymentRequest.js +102 -0
  32. package/lib/common/utxobased/engine/types.js +21 -0
  33. package/lib/common/utxobased/engine/util/defaultValidateConfirmations.js +19 -0
  34. package/lib/common/utxobased/engine/util/getOwnUtxosFromTx.js +54 -0
  35. package/lib/common/utxobased/engine/utils.js +239 -0
  36. package/lib/common/utxobased/info/all.js +67 -0
  37. package/lib/common/utxobased/info/badcoin.js +73 -0
  38. package/lib/common/utxobased/info/bitcoin.js +91 -0
  39. package/lib/common/utxobased/info/bitcoincash.js +93 -0
  40. package/lib/common/utxobased/info/bitcoincashtestnet.js +72 -0
  41. package/lib/common/utxobased/info/bitcoingold.js +85 -0
  42. package/lib/common/utxobased/info/bitcoingoldtestnet.js +71 -0
  43. package/lib/common/utxobased/info/bitcoinsv.js +76 -0
  44. package/lib/common/utxobased/info/bitcointestnet.js +81 -0
  45. package/lib/common/utxobased/info/dash.js +76 -0
  46. package/lib/common/utxobased/info/digibyte.js +76 -0
  47. package/lib/common/utxobased/info/dogecoin.js +76 -0
  48. package/lib/common/utxobased/info/eboost.js +70 -0
  49. package/lib/common/utxobased/info/feathercoin.js +76 -0
  50. package/lib/common/utxobased/info/groestlcoin.js +88 -0
  51. package/lib/common/utxobased/info/litecoin.js +82 -0
  52. package/lib/common/utxobased/info/qtum.js +67 -0
  53. package/lib/common/utxobased/info/ravencoin.js +70 -0
  54. package/lib/common/utxobased/info/scriptTemplates/bitcoincashScriptTemplates.js +56 -0
  55. package/lib/common/utxobased/info/scriptTemplates/types.js +14 -0
  56. package/lib/common/utxobased/info/smartcash.js +78 -0
  57. package/lib/common/utxobased/info/ufo.js +75 -0
  58. package/lib/common/utxobased/info/utxoPickers/dogeUtxoPicker.js +34 -0
  59. package/lib/common/utxobased/info/vertcoin.js +82 -0
  60. package/lib/common/utxobased/info/zcoin.js +72 -0
  61. package/lib/common/utxobased/keymanager/base.js +60 -0
  62. package/lib/common/utxobased/keymanager/bip69.js +31 -0
  63. package/lib/common/utxobased/keymanager/bitcoincashUtils/base32.js +88 -0
  64. package/lib/common/utxobased/keymanager/bitcoincashUtils/bn.js +210 -0
  65. package/lib/common/utxobased/keymanager/bitcoincashUtils/cashAddress.js +282 -0
  66. package/lib/common/utxobased/keymanager/cleaners.js +198 -0
  67. package/lib/common/utxobased/keymanager/coinmapper.js +12 -0
  68. package/lib/common/utxobased/keymanager/declarations/base58grscheck.d.js +1 -0
  69. package/lib/common/utxobased/keymanager/declarations/blake-hash.d.js +1 -0
  70. package/lib/common/utxobased/keymanager/declarations/bn.d.js +1 -0
  71. package/lib/common/utxobased/keymanager/declarations/bs58smartcheck.d.js +1 -0
  72. package/lib/common/utxobased/keymanager/declarations/wif-smart.d.js +1 -0
  73. package/lib/common/utxobased/keymanager/declarations/wifgrs.d.js +1 -0
  74. package/lib/common/utxobased/keymanager/keymanager.js +1214 -0
  75. package/lib/common/utxobased/keymanager/utxopicker/accumulative.js +52 -0
  76. package/lib/common/utxobased/keymanager/utxopicker/forceUseUtxo.js +59 -0
  77. package/lib/common/utxobased/keymanager/utxopicker/subtractFee.js +17 -0
  78. package/lib/common/utxobased/keymanager/utxopicker/types.js +42 -0
  79. package/lib/common/utxobased/keymanager/utxopicker/utils.js +159 -0
  80. package/lib/common/utxobased/keymanager/utxopicker.js +17 -0
  81. package/lib/common/utxobased/network/BlockBook.js +200 -0
  82. package/lib/common/utxobased/network/BlockBookAPI.js +335 -0
  83. package/lib/common/utxobased/network/Deferred.js +29 -0
  84. package/lib/common/utxobased/network/MakeSocketEmitter.js +35 -0
  85. package/lib/common/utxobased/network/Socket.js +362 -0
  86. package/lib/common/utxobased/network/nodejsWS.js +59 -0
  87. package/lib/common/utxobased/network/socketQueue.js +60 -0
  88. package/lib/common/utxobased/network/types.js +19 -0
  89. package/lib/common/utxobased/network/windowWS.js +54 -0
  90. package/lib/firo.js +15 -0
  91. package/lib/ftc.js +15 -0
  92. package/lib/index.js +19 -0
  93. package/lib/ltc.js +15 -0
  94. package/lib/src/bch.d.ts +3 -0
  95. package/lib/src/bsv.d.ts +3 -0
  96. package/lib/src/btc.d.ts +3 -0
  97. package/lib/src/common/constants.d.ts +9 -0
  98. package/lib/src/common/fees/calcMinerFeePerByte.d.ts +13 -0
  99. package/lib/src/common/fees/makeFees.d.ts +20 -0
  100. package/lib/src/common/fees/processInfoServerFees.d.ts +7 -0
  101. package/lib/src/common/fees/processMempoolSpaceFees.d.ts +13 -0
  102. package/lib/src/common/plugin/makeCurrencyPlugin.d.ts +3 -0
  103. package/lib/src/common/plugin/makeCurrencyTools.d.ts +8 -0
  104. package/lib/src/common/plugin/makeEngineEmitter.d.ts +23 -0
  105. package/lib/src/common/plugin/makeMetadata.d.ts +14 -0
  106. package/lib/src/common/plugin/pluginState.d.ts +34 -0
  107. package/lib/src/common/plugin/serverScores.d.ts +61 -0
  108. package/lib/src/common/plugin/types.d.ts +135 -0
  109. package/lib/src/common/plugin/utils.d.ts +6 -0
  110. package/lib/src/common/utxobased/db/Models/ProcessorTransaction.d.ts +16 -0
  111. package/lib/src/common/utxobased/db/Models/baselet.d.ts +28 -0
  112. package/lib/src/common/utxobased/db/makeBaselets.d.ts +33 -0
  113. package/lib/src/common/utxobased/db/makeMutex.d.ts +3 -0
  114. package/lib/src/common/utxobased/db/makeProcessor.d.ts +42 -0
  115. package/lib/src/common/utxobased/db/types.d.ts +47 -0
  116. package/lib/src/common/utxobased/engine/await-lock.d.ts +29 -0
  117. package/lib/src/common/utxobased/engine/constants.d.ts +4 -0
  118. package/lib/src/common/utxobased/engine/makeServerStates.d.ts +37 -0
  119. package/lib/src/common/utxobased/engine/makeUtxoEngine.d.ts +3 -0
  120. package/lib/src/common/utxobased/engine/makeUtxoEngineState.d.ts +108 -0
  121. package/lib/src/common/utxobased/engine/makeUtxoWalletTools.d.ts +52 -0
  122. package/lib/src/common/utxobased/engine/paymentRequest.d.ts +18 -0
  123. package/lib/src/common/utxobased/engine/types.d.ts +19 -0
  124. package/lib/src/common/utxobased/engine/util/defaultValidateConfirmations.d.ts +3 -0
  125. package/lib/src/common/utxobased/engine/util/getOwnUtxosFromTx.d.ts +4 -0
  126. package/lib/src/common/utxobased/engine/utils.d.ts +43 -0
  127. package/lib/src/common/utxobased/info/all.d.ts +22 -0
  128. package/lib/src/common/utxobased/info/badcoin.d.ts +3 -0
  129. package/lib/src/common/utxobased/info/bitcoin.d.ts +3 -0
  130. package/lib/src/common/utxobased/info/bitcoincash.d.ts +3 -0
  131. package/lib/src/common/utxobased/info/bitcoincashtestnet.d.ts +3 -0
  132. package/lib/src/common/utxobased/info/bitcoingold.d.ts +3 -0
  133. package/lib/src/common/utxobased/info/bitcoingoldtestnet.d.ts +3 -0
  134. package/lib/src/common/utxobased/info/bitcoinsv.d.ts +3 -0
  135. package/lib/src/common/utxobased/info/bitcointestnet.d.ts +6 -0
  136. package/lib/src/common/utxobased/info/dash.d.ts +3 -0
  137. package/lib/src/common/utxobased/info/digibyte.d.ts +3 -0
  138. package/lib/src/common/utxobased/info/dogecoin.d.ts +3 -0
  139. package/lib/src/common/utxobased/info/eboost.d.ts +3 -0
  140. package/lib/src/common/utxobased/info/feathercoin.d.ts +6 -0
  141. package/lib/src/common/utxobased/info/groestlcoin.d.ts +3 -0
  142. package/lib/src/common/utxobased/info/litecoin.d.ts +6 -0
  143. package/lib/src/common/utxobased/info/qtum.d.ts +3 -0
  144. package/lib/src/common/utxobased/info/ravencoin.d.ts +3 -0
  145. package/lib/src/common/utxobased/info/scriptTemplates/bitcoincashScriptTemplates.d.ts +2 -0
  146. package/lib/src/common/utxobased/info/scriptTemplates/types.d.ts +9 -0
  147. package/lib/src/common/utxobased/info/smartcash.d.ts +3 -0
  148. package/lib/src/common/utxobased/info/ufo.d.ts +3 -0
  149. package/lib/src/common/utxobased/info/utxoPickers/dogeUtxoPicker.d.ts +2 -0
  150. package/lib/src/common/utxobased/info/vertcoin.d.ts +3 -0
  151. package/lib/src/common/utxobased/info/zcoin.d.ts +6 -0
  152. package/lib/src/common/utxobased/keymanager/base.d.ts +9 -0
  153. package/lib/src/common/utxobased/keymanager/bip69.d.ts +19 -0
  154. package/lib/src/common/utxobased/keymanager/bitcoincashUtils/base32.d.ts +19 -0
  155. package/lib/src/common/utxobased/keymanager/bitcoincashUtils/bn.d.ts +2 -0
  156. package/lib/src/common/utxobased/keymanager/bitcoincashUtils/cashAddress.d.ts +12 -0
  157. package/lib/src/common/utxobased/keymanager/cleaners.d.ts +55 -0
  158. package/lib/src/common/utxobased/keymanager/coinmapper.d.ts +2 -0
  159. package/lib/src/common/utxobased/keymanager/keymanager.d.ts +198 -0
  160. package/lib/src/common/utxobased/keymanager/utxopicker/accumulative.d.ts +2 -0
  161. package/lib/src/common/utxobased/keymanager/utxopicker/forceUseUtxo.d.ts +2 -0
  162. package/lib/src/common/utxobased/keymanager/utxopicker/subtractFee.d.ts +2 -0
  163. package/lib/src/common/utxobased/keymanager/utxopicker/types.d.ts +36 -0
  164. package/lib/src/common/utxobased/keymanager/utxopicker/utils.d.ts +15 -0
  165. package/lib/src/common/utxobased/keymanager/utxopicker.d.ts +8 -0
  166. package/lib/src/common/utxobased/network/BlockBook.d.ts +33 -0
  167. package/lib/src/common/utxobased/network/BlockBookAPI.d.ts +163 -0
  168. package/lib/src/common/utxobased/network/Deferred.d.ts +8 -0
  169. package/lib/src/common/utxobased/network/MakeSocketEmitter.d.ts +13 -0
  170. package/lib/src/common/utxobased/network/Socket.d.ts +41 -0
  171. package/lib/src/common/utxobased/network/nodejsWS.d.ts +2 -0
  172. package/lib/src/common/utxobased/network/socketQueue.d.ts +8 -0
  173. package/lib/src/common/utxobased/network/types.d.ts +17 -0
  174. package/lib/src/common/utxobased/network/windowWS.d.ts +2 -0
  175. package/lib/src/firo.d.ts +3 -0
  176. package/lib/src/ftc.d.ts +3 -0
  177. package/lib/src/index.d.ts +4 -0
  178. package/lib/src/ltc.d.ts +3 -0
  179. package/lib/src/tbch.d.ts +3 -0
  180. package/lib/src/tbtc.d.ts +3 -0
  181. package/lib/src/tbtg.d.ts +3 -0
  182. package/lib/src/types.d.ts +6 -0
  183. package/lib/src/util/delay.d.ts +1 -0
  184. package/lib/src/util/filterUndefined.d.ts +1 -0
  185. package/lib/src/util/indexAtProtected.d.ts +5 -0
  186. package/lib/src/util/typeUtil.d.ts +8 -0
  187. package/lib/src/util/undefinedIfEmptyString.d.ts +1 -0
  188. package/lib/src/util/unixTime.d.ts +1 -0
  189. package/lib/tbch.js +15 -0
  190. package/lib/tbtc.js +15 -0
  191. package/lib/tbtg.js +15 -0
  192. package/lib/test/common/fees/calcMinerFeePerByte.spec.d.ts +1 -0
  193. package/lib/test/common/fees/fees.spec.d.ts +1 -0
  194. package/lib/test/common/plugin/currencyPlugin.fixtures/common.d.ts +29 -0
  195. package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/bitcoin.d.ts +2 -0
  196. package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/bitcoincash.d.ts +2 -0
  197. package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/bitcoinsv.d.ts +2 -0
  198. package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/digibyte.d.ts +2 -0
  199. package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/feathercoin.d.ts +2 -0
  200. package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/groestlcoin.d.ts +2 -0
  201. package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/litecoin.d.ts +2 -0
  202. package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/smartcash.d.ts +2 -0
  203. package/lib/test/common/plugin/currencyPlugin.fixtures/currencies/zcoin.d.ts +2 -0
  204. package/lib/test/common/plugin/currencyPlugin.fixtures/index.d.ts +2 -0
  205. package/lib/test/common/plugin/currencyPlugin.spec.d.ts +1 -0
  206. package/lib/test/common/plugin/makeMetadata.spec.d.ts +1 -0
  207. package/lib/test/common/plugin/serverScores.spec.d.ts +1 -0
  208. package/lib/test/common/utxobased/addressFormat/addressFormatIndex/addressFormat.spec.d.ts +1 -0
  209. package/lib/test/common/utxobased/db/Processor.spec.d.ts +1 -0
  210. package/lib/test/common/utxobased/engine/PaymentRequest.spec.d.ts +1 -0
  211. package/lib/test/common/utxobased/engine/UtxoWalletTools.spec.d.ts +1 -0
  212. package/lib/test/common/utxobased/engine/engine.fixtures/bitcoinTestnet/tests.d.ts +70 -0
  213. package/lib/test/common/utxobased/engine/engine.fixtures/index.d.ts +65 -0
  214. package/lib/test/common/utxobased/engine/engine.spec.d.ts +1 -0
  215. package/lib/test/common/utxobased/keymanager/coins/altcointestfixtures.d.ts +54 -0
  216. package/lib/test/common/utxobased/keymanager/coins/bitcoincashtransactiontest.spec.d.ts +1 -0
  217. package/lib/test/common/utxobased/keymanager/coins/bitcointransactiontest.spec.d.ts +1 -0
  218. package/lib/test/common/utxobased/keymanager/coins/cashaddr.spec.d.ts +1 -0
  219. package/lib/test/common/utxobased/keymanager/coins/checkdatasig.spec.d.ts +1 -0
  220. package/lib/test/common/utxobased/keymanager/coins/groestlcointransactiontest.spec.d.ts +1 -0
  221. package/lib/test/common/utxobased/keymanager/coins/keymanagertest.spec.d.ts +1 -0
  222. package/lib/test/common/utxobased/network/BlockBook.spec.d.ts +1 -0
  223. package/lib/test/util/objectKeys.d.ts +8 -0
  224. package/lib/test/util/testLog.d.ts +3 -0
  225. package/lib/test/utils.d.ts +10 -0
  226. package/lib/types.js +7 -0
  227. package/lib/util/delay.js +4 -0
  228. package/lib/util/filterUndefined.js +4 -0
  229. package/lib/util/indexAtProtected.js +9 -0
  230. package/lib/util/typeUtil.js +9 -0
  231. package/lib/util/undefinedIfEmptyString.js +2 -0
  232. package/lib/util/unixTime.js +2 -0
  233. package/package.json +101 -0
@@ -0,0 +1,1443 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _biggystring = require('biggystring');
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+ var _makeEngineEmitter = require('../../plugin/makeEngineEmitter');
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+ var _utils = require('../../plugin/utils');
19
+
20
+ var _ProcessorTransaction = require('../db/Models/ProcessorTransaction');
21
+
22
+
23
+
24
+
25
+
26
+ var _types5 = require('../db/types');
27
+
28
+
29
+
30
+
31
+
32
+ var _keymanager = require('../keymanager/keymanager');
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+
42
+
43
+ var _BlockBookAPI = require('../network/BlockBookAPI');
44
+ var _Deferred = require('../network/Deferred'); var _Deferred2 = _interopRequireDefault(_Deferred);
45
+
46
+ var _awaitlock = require('./await-lock'); var _awaitlock2 = _interopRequireDefault(_awaitlock);
47
+ var _constants = require('./constants');
48
+ var _makeServerStates = require('./makeServerStates');
49
+
50
+
51
+
52
+
53
+
54
+
55
+ var _utils3 = require('./utils');
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+
68
+
69
+
70
+
71
+
72
+
73
+
74
+
75
+
76
+
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+
85
+
86
+
87
+ function makeUtxoEngineState(
88
+ config
89
+ ) {
90
+ const {
91
+ pluginInfo,
92
+ walletInfo,
93
+ walletTools,
94
+ options: { emitter, log },
95
+ processor,
96
+ pluginState
97
+ } = config
98
+
99
+ const { walletFormats } = walletInfo.keys
100
+
101
+ const taskCache = {
102
+ addressWatching: false,
103
+ blockWatching: false,
104
+ addressSubscribeCache: {},
105
+ addressTransactionCache: {},
106
+ addressUtxoCache: {},
107
+ rawUtxoCache: {},
108
+ processorUtxoCache: {},
109
+ updateTransactionCache: {}
110
+ }
111
+
112
+ const clearTaskCache = () => {
113
+ taskCache.addressWatching = false
114
+ taskCache.blockWatching = false
115
+ taskCache.addressSubscribeCache = {}
116
+ taskCache.addressTransactionCache = {}
117
+ taskCache.addressUtxoCache = {}
118
+ taskCache.rawUtxoCache = {}
119
+ taskCache.processorUtxoCache = {}
120
+ taskCache.updateTransactionCache = {}
121
+ }
122
+
123
+ /**
124
+ * There are two processes that need to complete per address:
125
+ * 1. Address transaction processing
126
+ * 2. Address UTXO processing
127
+ **/
128
+ const processesPerAddress = 2
129
+ let processedCount = 0
130
+ let processedPercent = 0
131
+ const updateProgressRatio = async () => {
132
+ // We expect the total number of progress updates to equal the number of
133
+ // addresses multiplied the number of processes per address.
134
+ const expectedProccessCount =
135
+ Object.keys(taskCache.addressSubscribeCache).length * processesPerAddress
136
+
137
+ // Increment the processed count
138
+ processedCount = processedCount + 1
139
+
140
+ // If we have no addresses, we should not have not yet began processing.
141
+ if (expectedProccessCount === 0) throw new Error('No addresses to process')
142
+
143
+ const percent = processedCount / expectedProccessCount
144
+ if (percent - processedPercent > _constants.CACHE_THROTTLE || percent === 1) {
145
+ log(
146
+ `processed changed, percent: ${percent}, processedCount: ${processedCount}, totalCount: ${expectedProccessCount}`
147
+ )
148
+ processedPercent = percent
149
+ emitter.emit(_makeEngineEmitter.EngineEvent.ADDRESSES_CHECKED, percent)
150
+ }
151
+ }
152
+
153
+ const lock = new (0, _awaitlock2.default)()
154
+
155
+ const serverStates = _makeServerStates.makeServerStates.call(void 0, {
156
+ engineEmitter: emitter,
157
+ log,
158
+ pluginInfo,
159
+ pluginState,
160
+ walletInfo
161
+ })
162
+ const commonArgs = {
163
+ pluginInfo,
164
+ walletInfo,
165
+ walletTools,
166
+ processor,
167
+ emitter,
168
+ taskCache,
169
+ updateProgressRatio,
170
+ io: config.io,
171
+ log,
172
+ serverStates,
173
+ walletFormats,
174
+ lock
175
+ }
176
+ const { currencyInfo } = pluginInfo
177
+ const { requiredConfirmations = 1 } = currencyInfo
178
+
179
+ const pickNextTaskCB = async (
180
+ uri
181
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
182
+ ) => {
183
+ return await exports.pickNextTask.call(void 0, { ...commonArgs, uri })
184
+ }
185
+
186
+ serverStates.setPickNextTaskCB(pickNextTaskCB)
187
+
188
+ let running = false
189
+ const run = async () => {
190
+ if (running) return
191
+ running = true
192
+
193
+ await initializeAddressSubscriptions()
194
+ await setLookAhead(commonArgs)
195
+ }
196
+
197
+ emitter.on(
198
+ _makeEngineEmitter.EngineEvent.BLOCK_HEIGHT_CHANGED,
199
+ async (_uri, walletBlockHeight) => {
200
+ // Check if unconfirmed transaction have been confirmed.
201
+ const unconfirmedTxs = await processor.fetchTransactions({
202
+ blockHeight: 0
203
+ })
204
+ for (const tx of unconfirmedTxs) {
205
+ if (tx == null) continue
206
+ taskCache.updateTransactionCache[tx.txid] = { processing: false }
207
+ }
208
+
209
+ // Trigger transactions change event to update its confirmation status
210
+ const pendingTxs = await processor.fetchTransactions({
211
+ blockHeight: walletBlockHeight - requiredConfirmations,
212
+ blockHeightMax: walletBlockHeight
213
+ })
214
+ for (const tx of pendingTxs) {
215
+ if (tx == null) continue
216
+ await exports.transactionChanged.call(void 0, {
217
+ emitter,
218
+ processor,
219
+ pluginInfo,
220
+ tx,
221
+ walletBlockHeight,
222
+ walletTools
223
+ })
224
+ }
225
+ }
226
+ )
227
+
228
+ emitter.on(
229
+ _makeEngineEmitter.EngineEvent.NEW_ADDRESS_TRANSACTION,
230
+ async (_uri, response) => {
231
+ const state = taskCache.addressSubscribeCache[response.address]
232
+ if (state != null) {
233
+ const { path } = state
234
+ taskCache.addressUtxoCache[response.address] = {
235
+ processing: false,
236
+ path
237
+ }
238
+ addToAddressTransactionCache(
239
+ commonArgs,
240
+ response.address,
241
+ path.format,
242
+ path.changeIndex,
243
+ 0,
244
+ taskCache.addressTransactionCache
245
+ ).catch(() => {
246
+ throw new Error('failed to add to transaction cache')
247
+ })
248
+ setLookAhead(commonArgs).catch(e => {
249
+ log(e)
250
+ })
251
+ }
252
+ }
253
+ )
254
+
255
+ // Initialize the addressSubscribeCache with the existing addresses already
256
+ // processed by the processor. This happens only once before any call to
257
+ // setLookAhead.
258
+ const initializeAddressSubscriptions = async () => {
259
+ for (const format of walletFormats) {
260
+ const branches = _utils3.getFormatSupportedBranches.call(void 0, format)
261
+ for (const branch of branches) {
262
+ const addressesToSubscribe = new Set()
263
+ const branchAddressCount = processor.numAddressesByFormatPath({
264
+ format,
265
+ changeIndex: branch
266
+ })
267
+ // If the processor has not processed any addresses then the loop
268
+ // condition will only iterate once when branchAddressCount is 0 for the
269
+ // first address in the derivation path.
270
+ for (
271
+ let addressIndex = 0;
272
+ addressIndex < branchAddressCount;
273
+ addressIndex++
274
+ ) {
275
+ const processorAddress = await processor.fetchAddress({
276
+ format,
277
+ changeIndex: branch,
278
+ addressIndex
279
+ })
280
+ if (processorAddress == null) {
281
+ throw new Error(
282
+ 'Missing processor during address subscription initialization'
283
+ )
284
+ }
285
+ const { address } = walletTools.scriptPubkeyToAddress({
286
+ scriptPubkey: processorAddress.scriptPubkey,
287
+ format
288
+ })
289
+ addressesToSubscribe.add(address)
290
+ }
291
+ addToAddressSubscribeCache(commonArgs.taskCache, addressesToSubscribe, {
292
+ format,
293
+ changeIndex: branch
294
+ })
295
+ }
296
+ }
297
+ }
298
+
299
+ return {
300
+ processedPercent,
301
+ async start() {
302
+ processedCount = 0
303
+ processedPercent = 0
304
+
305
+ await run()
306
+ serverStates.refillServers()
307
+ },
308
+
309
+ async stop() {
310
+ serverStates.stop()
311
+ clearTaskCache()
312
+ running = false
313
+ },
314
+
315
+ async getFreshAddress(branch = 0) {
316
+ const walletPurpose = _utils3.currencyFormatToPurposeType.call(void 0,
317
+ walletInfo.keys.primaryFormat
318
+ )
319
+ if (walletPurpose === _keymanager.BIP43PurposeTypeEnum.Segwit) {
320
+ const { address: publicAddress } = await internalGetFreshAddress({
321
+ ...commonArgs,
322
+ format: _utils3.getCurrencyFormatFromPurposeType.call(void 0,
323
+ _keymanager.BIP43PurposeTypeEnum.WrappedSegwit
324
+ ),
325
+ changeIndex: branch
326
+ })
327
+
328
+ const { address: segwitAddress } = await internalGetFreshAddress({
329
+ ...commonArgs,
330
+ format: _utils3.getCurrencyFormatFromPurposeType.call(void 0, _keymanager.BIP43PurposeTypeEnum.Segwit),
331
+ changeIndex: branch
332
+ })
333
+
334
+ return {
335
+ publicAddress,
336
+ segwitAddress
337
+ }
338
+ } else {
339
+ // Airbitz wallets only use branch 0
340
+ if (walletPurpose === _keymanager.BIP43PurposeTypeEnum.Airbitz) {
341
+ branch = 0
342
+ }
343
+
344
+ const {
345
+ address: publicAddress,
346
+ legacyAddress
347
+ } = await internalGetFreshAddress({
348
+ ...commonArgs,
349
+ format: _utils3.getCurrencyFormatFromPurposeType.call(void 0, walletPurpose),
350
+ changeIndex: branch
351
+ })
352
+
353
+ return {
354
+ publicAddress,
355
+ legacyAddress:
356
+ legacyAddress !== publicAddress ? legacyAddress : undefined
357
+ }
358
+ }
359
+ },
360
+
361
+ async deriveScriptAddress(script) {
362
+ const { address } = await internalDeriveScriptAddress({
363
+ walletTools: commonArgs.walletTools,
364
+ engineInfo: commonArgs.pluginInfo.engineInfo,
365
+ processor: commonArgs.processor,
366
+ taskCache: commonArgs.taskCache,
367
+ format: walletInfo.keys.primaryFormat,
368
+ script
369
+ })
370
+ return {
371
+ publicAddress: address
372
+ }
373
+ },
374
+
375
+ async addGapLimitAddresses(addresses) {
376
+ const promises = addresses.map(async address => {
377
+ const scriptPubkey = walletTools.addressToScriptPubkey(address)
378
+ await processor.saveAddress(
379
+ _types5.makeIAddress.call(void 0, {
380
+ scriptPubkey,
381
+ used: true
382
+ })
383
+ )
384
+ })
385
+ await Promise.all(promises)
386
+ await run()
387
+ },
388
+
389
+ async broadcastTx(transaction) {
390
+ const txId = await serverStates.broadcastTx(transaction)
391
+
392
+ /*
393
+ After successfully broadcasting the tx, we must mark each UTXO, used as
394
+ an input for the tx, as spent so we don't try to reuse the UTXO.
395
+ */
396
+ const txInputs = _nullishCoalesce(_optionalChain([transaction, 'access', _ => _.otherParams, 'optionalAccess', _2 => _2.psbt, 'access', _3 => _3.inputs]), () => ( []))
397
+ for (const input of txInputs) {
398
+ const scriptPubkey = Buffer.from(input.scriptPubkey).toString('hex')
399
+ const [utxo] = await processor.fetchUtxos({
400
+ scriptPubkey
401
+ })
402
+ if (utxo != null) {
403
+ utxo.spent = true
404
+ await processor.saveUtxo(utxo)
405
+ }
406
+ }
407
+
408
+ return txId
409
+ },
410
+ refillServers() {
411
+ serverStates.refillServers()
412
+ },
413
+ getServerList() {
414
+ return serverStates.getServerList()
415
+ },
416
+ setServerList(serverList) {
417
+ serverStates.setServerList(serverList)
418
+ },
419
+
420
+ async loadWifs(wifs) {
421
+ for (const wif of wifs) {
422
+ for (const format of walletFormats) {
423
+ const changePath = {
424
+ format,
425
+ changeIndex: 0
426
+ }
427
+ const path = {
428
+ ...changePath,
429
+ addressIndex: 0
430
+ }
431
+ const {
432
+ scriptPubkey,
433
+ redeemScript
434
+ } = walletTools.getScriptPubkeyFromWif(wif, format)
435
+ const { address } = walletTools.scriptPubkeyToAddress({
436
+ scriptPubkey,
437
+ format: path.format
438
+ })
439
+
440
+ // Make a new IAddress and save it
441
+ await processor.saveAddress(
442
+ _types5.makeIAddress.call(void 0, { scriptPubkey, redeemScript, path })
443
+ )
444
+
445
+ taskCache.addressSubscribeCache[address] = {
446
+ path: changePath,
447
+ processing: false
448
+ }
449
+ }
450
+ }
451
+ taskCache.addressWatching = false
452
+ }
453
+ }
454
+ } exports.makeUtxoEngineState = makeUtxoEngineState;
455
+
456
+
457
+
458
+
459
+
460
+
461
+
462
+
463
+
464
+
465
+
466
+
467
+
468
+
469
+
470
+
471
+
472
+
473
+
474
+
475
+
476
+
477
+
478
+
479
+
480
+
481
+
482
+
483
+
484
+
485
+
486
+
487
+
488
+
489
+
490
+
491
+
492
+
493
+
494
+
495
+
496
+
497
+
498
+
499
+
500
+
501
+
502
+
503
+
504
+
505
+
506
+
507
+
508
+
509
+
510
+
511
+
512
+
513
+
514
+
515
+
516
+
517
+
518
+ const setLookAhead = async (common) => {
519
+ const {
520
+ pluginInfo: { engineInfo },
521
+ lock,
522
+ processor,
523
+ walletFormats,
524
+ walletTools
525
+ } = common
526
+
527
+ // Wait for the lock to be released before continuing invocation.
528
+ // This is to ensure that setLockAhead is not called while the lock is held.
529
+ await lock.acquireAsync()
530
+
531
+ try {
532
+ for (const format of walletFormats) {
533
+ const branches = _utils3.getFormatSupportedBranches.call(void 0, format)
534
+ for (const branch of branches) {
535
+ await deriveKeys({ format, changeIndex: branch })
536
+ }
537
+ }
538
+ } finally {
539
+ lock.release()
540
+ }
541
+
542
+ async function deriveKeys(changePath) {
543
+ const addressesToSubscribe = new Set()
544
+ const totalAddressCount = processor.numAddressesByFormatPath(changePath)
545
+ let lastUsedIndex = await processor.lastUsedIndexByFormatPath(changePath)
546
+
547
+ // Loop until the total address count equals the lookahead count
548
+ let lookAheadIndex = lastUsedIndex + engineInfo.gapLimit
549
+ let nextAddressIndex = totalAddressCount
550
+ while (nextAddressIndex <= lookAheadIndex) {
551
+ const path = {
552
+ ...changePath,
553
+ addressIndex: nextAddressIndex
554
+ }
555
+
556
+ const { scriptPubkey, redeemScript } = walletTools.getScriptPubkey(path)
557
+ const { address } = walletTools.scriptPubkeyToAddress({
558
+ scriptPubkey,
559
+ format: path.format
560
+ })
561
+
562
+ // Make a new IAddress and save it
563
+ await processor.saveAddress(
564
+ _types5.makeIAddress.call(void 0, { scriptPubkey, redeemScript, path })
565
+ )
566
+
567
+ // Add the displayAddress to the set of addresses to subscribe to after loop
568
+ addressesToSubscribe.add(address)
569
+
570
+ // Update the state for the loop
571
+ lastUsedIndex = await processor.lastUsedIndexByFormatPath(changePath)
572
+ lookAheadIndex = lastUsedIndex + engineInfo.gapLimit
573
+ nextAddressIndex = processor.numAddressesByFormatPath(changePath)
574
+ }
575
+
576
+ // Add all the addresses to the subscribe cache for registering subscriptions later
577
+ addToAddressSubscribeCache(
578
+ common.taskCache,
579
+ addressesToSubscribe,
580
+ changePath
581
+ )
582
+ }
583
+ }
584
+
585
+ const addToAddressSubscribeCache = (
586
+ taskCache,
587
+ addresses,
588
+ path
589
+ ) => {
590
+ addresses.forEach(address => {
591
+ taskCache.addressSubscribeCache[address] = {
592
+ path,
593
+ processing: false
594
+ }
595
+ taskCache.addressWatching = false
596
+ })
597
+ }
598
+
599
+ const addToAddressTransactionCache = async (
600
+ args,
601
+ address,
602
+ format,
603
+ branch,
604
+ blockHeight,
605
+ addressTransactionCache
606
+ ) => {
607
+ const { walletTools, processor } = args
608
+ // Fetch the blockHeight for the address from the database
609
+ const scriptPubkey = walletTools.addressToScriptPubkey(address)
610
+
611
+ if (blockHeight === 0) {
612
+ const { lastQueriedBlockHeight = 0 } =
613
+ await _asyncNullishCoalesce((await processor.fetchAddress(scriptPubkey)), async () => ( {}))
614
+ blockHeight = lastQueriedBlockHeight
615
+ }
616
+
617
+ addressTransactionCache[address] = {
618
+ processing: false,
619
+ path: {
620
+ format,
621
+ changeIndex: branch
622
+ },
623
+ page: 1, // Page starts on 1
624
+ blockHeight
625
+ }
626
+ }
627
+
628
+
629
+
630
+
631
+
632
+
633
+
634
+
635
+
636
+
637
+ const transactionChanged = async (
638
+ args
639
+ ) => {
640
+ const {
641
+ emitter,
642
+ walletBlockHeight,
643
+ walletTools,
644
+ processor,
645
+ pluginInfo,
646
+ tx
647
+ } = args
648
+ const { currencyInfo } = pluginInfo
649
+
650
+ emitter.emit(_makeEngineEmitter.EngineEvent.TRANSACTIONS_CHANGED, [
651
+ await _ProcessorTransaction.toEdgeTransaction.call(void 0, {
652
+ tx,
653
+ currencyCode: currencyInfo.currencyCode,
654
+ pluginInfo,
655
+ processor,
656
+ walletBlockHeight: walletBlockHeight,
657
+ walletTools
658
+ })
659
+ ])
660
+ }; exports.transactionChanged = transactionChanged
661
+
662
+
663
+
664
+
665
+
666
+ const pickNextTask = async (
667
+ args
668
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
669
+ ) => {
670
+ const { taskCache, uri, serverStates } = args
671
+
672
+ const {
673
+ addressSubscribeCache,
674
+ addressUtxoCache,
675
+ rawUtxoCache,
676
+ processorUtxoCache,
677
+ addressTransactionCache,
678
+ updateTransactionCache
679
+ } = taskCache
680
+
681
+ const serverState = serverStates.getServerState(uri)
682
+ if (serverState == null) return
683
+
684
+ // subscribe all servers to new blocks
685
+ if (serverState.blockSubscriptionStatus === 'unsubscribed') {
686
+ serverStates.watchBlocks(uri)
687
+ return true
688
+ }
689
+
690
+ // Loop processed utxos, these are just database ops, triggers setLookAhead
691
+ if (Object.keys(processorUtxoCache).length > 0) {
692
+ for (const [scriptPubkey, state] of Object.entries(processorUtxoCache)) {
693
+ // Only process when all utxos for a specific address have been gathered
694
+ if (!state.processing && state.full) {
695
+ state.processing = true
696
+ await processProcessorUtxos({
697
+ ...args,
698
+ scriptPubkey,
699
+ utxos: state.utxos,
700
+ path: state.path
701
+ })
702
+ _utils.removeItem.call(void 0, processorUtxoCache, scriptPubkey)
703
+ return true
704
+ }
705
+ }
706
+ }
707
+
708
+ const blockHeight = serverStates.getBlockHeight(uri)
709
+
710
+ // Loop unparsed utxos, some require a network call to get the full tx data
711
+ for (const [utxoString, state] of Object.entries(rawUtxoCache)) {
712
+ const utxo = JSON.parse(utxoString)
713
+ if (utxo == null) continue
714
+ if (!state.processing) {
715
+ // check if we need to fetch additional network content for legacy purpose type
716
+ const purposeType = _utils3.currencyFormatToPurposeType.call(void 0, state.path.format)
717
+ if (
718
+ purposeType === _keymanager.BIP43PurposeTypeEnum.Airbitz ||
719
+ purposeType === _keymanager.BIP43PurposeTypeEnum.Legacy
720
+ ) {
721
+ // if we do need to make a network call, check with the serverState
722
+ if (!serverStates.serverCanGetTx(uri, utxo.txid)) return
723
+ }
724
+ state.processing = true
725
+ _utils.removeItem.call(void 0, rawUtxoCache, utxoString)
726
+ const wsTask = await processRawUtxo({
727
+ ...args,
728
+ ...state,
729
+ utxo,
730
+ id: `${utxo.txid}_${utxo.vout}`
731
+ })
732
+ return _nullishCoalesce(wsTask, () => ( true))
733
+ }
734
+ }
735
+
736
+ // Loop to process addresses to utxos
737
+ for (const [address, state] of Object.entries(addressUtxoCache)) {
738
+ // Check if we need to fetch address UTXOs
739
+ if (!state.processing && serverStates.serverCanGetAddress(uri, address)) {
740
+ state.processing = true
741
+
742
+ _utils.removeItem.call(void 0, addressUtxoCache, address)
743
+
744
+ // Fetch and process address UTXOs
745
+ const wsTask = await processAddressUtxos({
746
+ ...args,
747
+ ...state,
748
+ address
749
+ })
750
+ wsTask.deferred.promise
751
+ .then(() => {
752
+ serverState.addresses.add(address)
753
+ })
754
+ .catch(e => {
755
+ throw e
756
+ })
757
+ return wsTask
758
+ }
759
+ }
760
+
761
+ // Check if there are any addresses pending to be subscribed
762
+ if (
763
+ Object.keys(addressSubscribeCache).length > 0 &&
764
+ !taskCache.addressWatching
765
+ ) {
766
+ // Loop each address that needs to be subscribed
767
+ for (const [address, state] of Object.entries(addressSubscribeCache)) {
768
+ // Add address in the cache to the set of addresses to watch
769
+ const { path, processing: subscribed } = state
770
+ // only process newly watched addresses
771
+ if (subscribed) continue
772
+ if (path != null) {
773
+ // Add the newly watched addresses to the UTXO cache
774
+ addressUtxoCache[address] = {
775
+ processing: false,
776
+ path
777
+ }
778
+ await addToAddressTransactionCache(
779
+ args,
780
+ address,
781
+ path.format,
782
+ path.changeIndex,
783
+ blockHeight,
784
+ addressTransactionCache
785
+ )
786
+ }
787
+ state.processing = true
788
+ }
789
+
790
+ taskCache.addressWatching = true
791
+
792
+ const queryTime = Date.now()
793
+ const deferred = new _Deferred2.default()
794
+ deferred.promise
795
+ .then(() => {
796
+ serverStates.serverScoreUp(uri, Date.now() - queryTime)
797
+ })
798
+ .catch(() => {
799
+ taskCache.addressWatching = false
800
+ })
801
+ deferred.promise.catch(() => {
802
+ taskCache.addressWatching = false
803
+ })
804
+ serverStates.watchAddresses(
805
+ uri,
806
+ Array.from(Object.keys(addressSubscribeCache)),
807
+ deferred
808
+ )
809
+ return true
810
+ }
811
+
812
+ // filled when transactions potentially changed (e.g. through new block notification)
813
+ if (Object.keys(updateTransactionCache).length > 0) {
814
+ let hasProcessedAtLeastOnce = false
815
+ for (const [txId, state] of Object.entries(updateTransactionCache)) {
816
+ if (!state.processing && serverStates.serverCanGetTx(uri, txId)) {
817
+ hasProcessedAtLeastOnce = true
818
+ state.processing = true
819
+ _utils.removeItem.call(void 0, updateTransactionCache, txId)
820
+ const updateTransactionTask = updateTransactions({
821
+ ...args,
822
+ walletBlockHeight: blockHeight,
823
+ txId
824
+ })
825
+ // once resolved, add the txid to the server cache
826
+ updateTransactionTask.deferred.promise
827
+ .then(() => {
828
+ serverState.txids.add(txId)
829
+ })
830
+ .catch(e => {
831
+ throw e
832
+ })
833
+ return updateTransactionTask
834
+ }
835
+ }
836
+ // This condition prevents infinite loops
837
+ if (hasProcessedAtLeastOnce) return true
838
+ }
839
+
840
+ // loop to get and process transaction history of single addresses, triggers setLookAhead
841
+ for (const [address, state] of Object.entries(addressTransactionCache)) {
842
+ if (!state.processing && serverStates.serverCanGetAddress(uri, address)) {
843
+ state.processing = true
844
+
845
+ _utils.removeItem.call(void 0, addressTransactionCache, address)
846
+
847
+ // Fetch and process address UTXOs
848
+ const wsTask = await processAddressTransactions({
849
+ ...args,
850
+ ...state,
851
+ address
852
+ })
853
+ wsTask.deferred.promise
854
+ .then(() => {
855
+ serverState.addresses.add(address)
856
+ })
857
+ .catch(e => {
858
+ throw e
859
+ })
860
+ return wsTask
861
+ }
862
+ }
863
+ }; exports.pickNextTask = pickNextTask
864
+
865
+
866
+
867
+
868
+
869
+
870
+ const updateTransactions = (
871
+ args
872
+ ) => {
873
+ const {
874
+ walletBlockHeight,
875
+ emitter,
876
+ walletTools,
877
+ txId,
878
+ pluginInfo,
879
+ processor,
880
+ taskCache
881
+ } = args
882
+ const deferred = new _Deferred2.default()
883
+ deferred.promise
884
+ .then(async (txResponse) => {
885
+ // check if raw tx is still not confirmed, if so, don't change anything
886
+ if (txResponse.blockHeight < 1) return
887
+ // Create new tx from raw tx
888
+ const tx = processTransactionResponse({
889
+ ...args,
890
+ txResponse
891
+ })
892
+ // Remove any existing input utxos from the processor
893
+ for (const input of tx.inputs) {
894
+ await processor.removeUtxos([`${input.txId}_${input.outputIndex}`])
895
+ }
896
+ // Update output utxos's blockHeight any existing input utxos from the processor
897
+ const utxoIds = tx.outputs.map(output => `${tx.txid}_${output.n}`)
898
+ const utxos = await processor.fetchUtxos({
899
+ utxoIds
900
+ })
901
+ for (const utxo of utxos) {
902
+ if (utxo == null) continue
903
+ utxo.blockHeight = tx.blockHeight
904
+ await processor.saveUtxo(utxo)
905
+ }
906
+ // Process and save new tx
907
+ const processedTx = await processor.saveTransaction({
908
+ tx
909
+ })
910
+ await exports.transactionChanged.call(void 0, {
911
+ emitter,
912
+ processor,
913
+ pluginInfo,
914
+ tx: processedTx,
915
+ walletBlockHeight,
916
+ walletTools
917
+ })
918
+ })
919
+ .catch(() => {
920
+ taskCache.updateTransactionCache[txId] = { processing: false }
921
+ })
922
+ return {
923
+ ..._BlockBookAPI.transactionMessage.call(void 0, txId),
924
+ deferred
925
+ }
926
+ }
927
+
928
+
929
+
930
+
931
+
932
+
933
+
934
+
935
+
936
+
937
+
938
+
939
+
940
+
941
+
942
+
943
+ const internalDeriveScriptAddress = async ({
944
+ walletTools,
945
+ engineInfo,
946
+ processor,
947
+ format,
948
+ taskCache,
949
+ script
950
+ }) => {
951
+ if (engineInfo.scriptTemplates == null) {
952
+ throw new Error(
953
+ `cannot derive script address ${script} without defined script template`
954
+ )
955
+ }
956
+
957
+ const scriptTemplate = engineInfo.scriptTemplates[script]
958
+
959
+ const path = {
960
+ format,
961
+ changeIndex: _keymanager.derivationLevelScriptHash.call(void 0, scriptTemplate),
962
+ addressIndex: 0
963
+ }
964
+
965
+ // save the address to the processor and add it to the cache
966
+ const { address, scriptPubkey, redeemScript } = walletTools.getScriptAddress({
967
+ path,
968
+ scriptTemplate
969
+ })
970
+ await processor.saveAddress(
971
+ _types5.makeIAddress.call(void 0, { scriptPubkey, redeemScript, path })
972
+ )
973
+ const addresses = new Set()
974
+ addresses.add(address)
975
+ addToAddressSubscribeCache(taskCache, addresses, {
976
+ format: path.format,
977
+ changeIndex: path.changeIndex
978
+ })
979
+ return { address, scriptPubkey, redeemScript }
980
+ }
981
+
982
+
983
+
984
+
985
+
986
+
987
+
988
+
989
+ const internalGetFreshAddress = async (
990
+ args
991
+ ) => {
992
+ const { format, changeIndex: branch, walletTools, processor } = args
993
+
994
+ const numAddresses = processor.numAddressesByFormatPath({
995
+ format,
996
+ changeIndex: branch
997
+ })
998
+
999
+ const path = {
1000
+ format,
1001
+ changeIndex: branch,
1002
+ // while syncing, we may hit negative numbers when only subtracting. Use the address at /0 in that case.
1003
+ addressIndex: Math.max(
1004
+ numAddresses - args.pluginInfo.engineInfo.gapLimit,
1005
+ 0
1006
+ )
1007
+ }
1008
+ const { scriptPubkey } =
1009
+ await _asyncNullishCoalesce((await processor.fetchAddress(path)), async () => (
1010
+ (await walletTools.getScriptPubkey(path))))
1011
+ if (scriptPubkey == null) {
1012
+ throw new Error('Unknown address path')
1013
+ }
1014
+ return walletTools.scriptPubkeyToAddress({
1015
+ scriptPubkey,
1016
+ format
1017
+ })
1018
+ }
1019
+
1020
+
1021
+
1022
+
1023
+
1024
+
1025
+
1026
+
1027
+
1028
+
1029
+ const processAddressTransactions = async (
1030
+ args
1031
+ ) => {
1032
+ const {
1033
+ address,
1034
+ page = 1,
1035
+ blockHeight: walletBlockHeight,
1036
+ emitter,
1037
+ pluginInfo,
1038
+ processor,
1039
+ walletTools,
1040
+ path,
1041
+ taskCache,
1042
+ serverStates,
1043
+ uri
1044
+ } = args
1045
+ const {
1046
+ engineInfo: { asBlockbookAddress }
1047
+ } = pluginInfo
1048
+ const addressTransactionCache = taskCache.addressTransactionCache
1049
+
1050
+ const scriptPubkey = walletTools.addressToScriptPubkey(address)
1051
+ const addressData = await processor.fetchAddress(scriptPubkey)
1052
+ if (addressData == null) {
1053
+ throw new Error(`could not find address with script pubkey ${scriptPubkey}`)
1054
+ }
1055
+
1056
+ const queryTime = Date.now()
1057
+ const deferred = new _Deferred2.default()
1058
+ deferred.promise
1059
+ .then(async (value) => {
1060
+ serverStates.serverScoreUp(uri, Date.now() - queryTime)
1061
+ const { transactions = [], txs, unconfirmedTxs, totalPages } = value
1062
+
1063
+ // If address is used and previously not marked as used, mark as used.
1064
+ const used = txs > 0 || unconfirmedTxs > 0
1065
+ if (!addressData.used && used && page === 1) {
1066
+ addressData.used = true
1067
+ }
1068
+
1069
+ // Process and save the address's transactions
1070
+ for (const txResponse of transactions) {
1071
+ const tx = processTransactionResponse({
1072
+ ...args,
1073
+ txResponse
1074
+ })
1075
+ const processedTx = await processor.saveTransaction({
1076
+ tx,
1077
+ scriptPubkeys: [scriptPubkey]
1078
+ })
1079
+ await exports.transactionChanged.call(void 0, {
1080
+ emitter,
1081
+ processor,
1082
+ pluginInfo,
1083
+ tx: processedTx,
1084
+ walletBlockHeight,
1085
+ walletTools
1086
+ })
1087
+ }
1088
+
1089
+ // Halt on finishing the processing of address transaction until
1090
+ // we have progressed through all of the blockbook pages
1091
+ if (page < totalPages) {
1092
+ // Add the address back to the cache, incrementing the page
1093
+ addressTransactionCache[address] = {
1094
+ path,
1095
+ processing: false,
1096
+ blockHeight: walletBlockHeight,
1097
+ page: page + 1
1098
+ }
1099
+ return
1100
+ }
1101
+
1102
+ // Update the lastQueriedBlockHeight for the address
1103
+ addressData.lastQueriedBlockHeight = walletBlockHeight
1104
+
1105
+ // Save/update the fully-processed address
1106
+ await processor.saveAddress(addressData)
1107
+
1108
+ // Update the progress now that the transactions for an address have processed
1109
+ await args.updateProgressRatio()
1110
+
1111
+ // Call setLookAhead to update the lookahead
1112
+ await setLookAhead(args)
1113
+ })
1114
+ .catch(err => {
1115
+ // Log the error for debugging purposes without crashing the engine
1116
+ // This will cause frozen wallet syncs
1117
+ console.error(err.toString())
1118
+ console.log(err.stack)
1119
+ })
1120
+
1121
+ return {
1122
+ ..._BlockBookAPI.addressMessage.call(void 0, address, asBlockbookAddress, {
1123
+ details: 'txs',
1124
+ from: addressData.lastQueriedBlockHeight,
1125
+ pageSize: _constants.BLOCKBOOK_TXS_PER_PAGE,
1126
+ page
1127
+ }),
1128
+ deferred
1129
+ }
1130
+ }
1131
+
1132
+
1133
+
1134
+
1135
+
1136
+ const processTransactionResponse = (
1137
+ args
1138
+ ) => {
1139
+ const { txResponse, pluginInfo } = args
1140
+ const { coinInfo } = pluginInfo
1141
+
1142
+ return {
1143
+ txid: txResponse.txid,
1144
+ hex: txResponse.hex,
1145
+ // Blockbook can return a blockHeight of -1 when the tx is pending in the mempool
1146
+ blockHeight: txResponse.blockHeight > 0 ? txResponse.blockHeight : 0,
1147
+ date: txResponse.blockTime,
1148
+ fees: txResponse.fees,
1149
+ inputs: txResponse.vin.map(input => ({
1150
+ txId: input.txid,
1151
+ outputIndex: input.vout, // case for tx `fefac8c22ba1178df5d7c90b78cc1c203d1a9f5f5506f7b8f6f469fa821c2674` no `vout` for input
1152
+ n: input.n,
1153
+ scriptPubkey: _utils3.validScriptPubkeyFromAddress.call(void 0, {
1154
+ address: input.addresses[0],
1155
+ coin: coinInfo.name
1156
+ }),
1157
+ amount: input.value
1158
+ })),
1159
+ outputs: txResponse.vout.map(output => ({
1160
+ n: output.n,
1161
+ scriptPubkey:
1162
+ _nullishCoalesce(output.hex, () => (
1163
+ _utils3.validScriptPubkeyFromAddress.call(void 0, {
1164
+ address: output.addresses[0],
1165
+ coin: coinInfo.name
1166
+ }))),
1167
+ amount: output.value
1168
+ })),
1169
+ ourIns: [],
1170
+ ourOuts: [],
1171
+ ourAmount: '0'
1172
+ }
1173
+ }
1174
+
1175
+
1176
+
1177
+
1178
+
1179
+
1180
+
1181
+
1182
+ const processAddressUtxos = async (
1183
+ args
1184
+ ) => {
1185
+ const {
1186
+ address,
1187
+ walletTools,
1188
+ processor,
1189
+ taskCache,
1190
+ path,
1191
+ pluginInfo,
1192
+ serverStates,
1193
+ uri
1194
+ } = args
1195
+ const {
1196
+ engineInfo: { asBlockbookAddress }
1197
+ } = pluginInfo
1198
+ const { addressUtxoCache, rawUtxoCache, processorUtxoCache } = taskCache
1199
+ const queryTime = Date.now()
1200
+ const deferred = new _Deferred2.default()
1201
+ deferred.promise
1202
+ .then(async (utxos) => {
1203
+ serverStates.serverScoreUp(uri, Date.now() - queryTime)
1204
+ const scriptPubkey = walletTools.addressToScriptPubkey(address)
1205
+ const addressData = await processor.fetchAddress(scriptPubkey)
1206
+ if (addressData == null || addressData.path == null) {
1207
+ return
1208
+ }
1209
+
1210
+ if (utxos.length === 0) {
1211
+ addToProcessorUtxoCache(processorUtxoCache, path, scriptPubkey, 0)
1212
+ return
1213
+ }
1214
+
1215
+ for (const utxo of utxos) {
1216
+ rawUtxoCache[JSON.stringify(utxo)] = {
1217
+ processing: false,
1218
+ requiredCount: utxos.length,
1219
+ path,
1220
+ // TypeScript yells otherwise
1221
+ address: { ...addressData, path: addressData.path }
1222
+ }
1223
+ }
1224
+ })
1225
+ .catch(() => {
1226
+ args.processing = false
1227
+ addressUtxoCache[address] = {
1228
+ processing: args.processing,
1229
+ path
1230
+ }
1231
+ })
1232
+
1233
+ return {
1234
+ ..._BlockBookAPI.addressUtxosMessage.call(void 0, address, asBlockbookAddress),
1235
+ deferred
1236
+ }
1237
+ }
1238
+
1239
+
1240
+
1241
+
1242
+
1243
+
1244
+
1245
+ const processProcessorUtxos = async (
1246
+ args
1247
+ ) => {
1248
+ const {
1249
+ utxos,
1250
+ processor,
1251
+ scriptPubkey,
1252
+ log,
1253
+ emitter,
1254
+ pluginInfo: { currencyInfo }
1255
+ } = args
1256
+
1257
+ const currentUtxos = await processor.fetchUtxos({ scriptPubkey })
1258
+ const currentUtxoIds = []
1259
+ let oldBalance = '0'
1260
+ for (const utxo of currentUtxos) {
1261
+ if (utxo == null)
1262
+ throw new Error(
1263
+ 'Unexpected undefined utxo when processing unspent transactions'
1264
+ )
1265
+ oldBalance = _biggystring.add.call(void 0, utxo.value, oldBalance)
1266
+ currentUtxoIds.push(utxo.id)
1267
+ }
1268
+ await processor.removeUtxos(currentUtxoIds)
1269
+
1270
+ let newBalance = '0'
1271
+ for (const utxo of Array.from(utxos)) {
1272
+ newBalance = _biggystring.add.call(void 0, utxo.value, newBalance)
1273
+ await processor.saveUtxo(utxo)
1274
+ }
1275
+
1276
+ const diff = _biggystring.sub.call(void 0, newBalance, oldBalance)
1277
+ if (diff !== '0') {
1278
+ log('balance changed:', { scriptPubkey, diff })
1279
+ emitter.emit(
1280
+ _makeEngineEmitter.EngineEvent.ADDRESS_BALANCE_CHANGED,
1281
+ currencyInfo.currencyCode,
1282
+ diff
1283
+ )
1284
+
1285
+ // Update balances for address that have this scriptPubkey
1286
+ const address = await processor.fetchAddress(scriptPubkey)
1287
+
1288
+ if (address == null) {
1289
+ throw new Error('address not found when processing UTXO transactions')
1290
+ }
1291
+
1292
+ await processor.saveAddress({
1293
+ ...address,
1294
+ balance: newBalance,
1295
+ used: true
1296
+ })
1297
+ }
1298
+
1299
+ // Update the progress now that the UTXOs for an address have been processed
1300
+ await args.updateProgressRatio()
1301
+
1302
+ await setLookAhead(args).catch(err => {
1303
+ log.error(err)
1304
+ throw err
1305
+ })
1306
+ }
1307
+
1308
+
1309
+
1310
+
1311
+
1312
+
1313
+
1314
+
1315
+
1316
+
1317
+ const processRawUtxo = async (
1318
+ args
1319
+ ) => {
1320
+ const {
1321
+ utxo,
1322
+ id,
1323
+ address,
1324
+ processor,
1325
+ path,
1326
+ taskCache,
1327
+ requiredCount,
1328
+ serverStates,
1329
+ uri,
1330
+ log
1331
+ } = args
1332
+ const { rawUtxoCache, processorUtxoCache } = taskCache
1333
+ let scriptType
1334
+ let script
1335
+ let redeemScript
1336
+
1337
+ // Function to call once we are finished
1338
+ const done = () =>
1339
+ addToProcessorUtxoCache(
1340
+ processorUtxoCache,
1341
+ path,
1342
+ address.scriptPubkey,
1343
+ requiredCount,
1344
+ {
1345
+ id,
1346
+ txid: utxo.txid,
1347
+ vout: utxo.vout,
1348
+ value: utxo.value,
1349
+ scriptPubkey: address.scriptPubkey,
1350
+ script,
1351
+ redeemScript,
1352
+ scriptType,
1353
+ blockHeight: _nullishCoalesce(utxo.height, () => ( -1)),
1354
+ spent: false
1355
+ }
1356
+ )
1357
+
1358
+ switch (_utils3.currencyFormatToPurposeType.call(void 0, path.format)) {
1359
+ case _keymanager.BIP43PurposeTypeEnum.Airbitz:
1360
+ case _keymanager.BIP43PurposeTypeEnum.Legacy:
1361
+ scriptType = _keymanager.ScriptTypeEnum.p2pkh
1362
+ if (address.redeemScript != null) {
1363
+ scriptType = _keymanager.ScriptTypeEnum.p2sh
1364
+ redeemScript = address.redeemScript
1365
+ }
1366
+
1367
+ // Legacy UTXOs need the previous transaction hex as the script
1368
+ // If we do not currently have it, add it to the queue to fetch it
1369
+ {
1370
+ const [tx] = await processor.fetchTransactions({ txId: utxo.txid })
1371
+ if (tx == null) {
1372
+ const queryTime = Date.now()
1373
+ const deferred = new _Deferred2.default()
1374
+ deferred.promise
1375
+ .then((txResponse) => {
1376
+ serverStates.serverScoreUp(uri, Date.now() - queryTime)
1377
+ const processedTx = processTransactionResponse({
1378
+ ...args,
1379
+ txResponse
1380
+ })
1381
+ script = processedTx.hex
1382
+ // Only after we have successfully fetched the tx, set our script and call done
1383
+ done()
1384
+ })
1385
+ .catch(e => {
1386
+ // If something went wrong, add the UTXO back to the queue
1387
+ log('error in processed utxos cache, re-adding utxo to cache:', e)
1388
+ rawUtxoCache[JSON.stringify(utxo)] = {
1389
+ processing: false,
1390
+ path,
1391
+ address,
1392
+ requiredCount
1393
+ }
1394
+ })
1395
+ return {
1396
+ ..._BlockBookAPI.transactionMessage.call(void 0, utxo.txid),
1397
+ deferred
1398
+ }
1399
+ } else {
1400
+ script = tx.hex
1401
+ }
1402
+ }
1403
+
1404
+ break
1405
+ case _keymanager.BIP43PurposeTypeEnum.WrappedSegwit:
1406
+ scriptType = _keymanager.ScriptTypeEnum.p2wpkhp2sh
1407
+ script = address.scriptPubkey
1408
+ if (address.redeemScript == null) {
1409
+ throw new Error(
1410
+ 'Address redeem script not defined, but required for p2sh wrapped segwit utxo processing'
1411
+ )
1412
+ }
1413
+ redeemScript = address.redeemScript
1414
+
1415
+ break
1416
+ case _keymanager.BIP43PurposeTypeEnum.Segwit:
1417
+ scriptType = _keymanager.ScriptTypeEnum.p2wpkh
1418
+ script = address.scriptPubkey
1419
+
1420
+ break
1421
+ }
1422
+
1423
+ // Since we have everything, call done
1424
+ done()
1425
+ }
1426
+
1427
+ const addToProcessorUtxoCache = (
1428
+ processorUtxosCache,
1429
+ path,
1430
+ scriptPubkey,
1431
+ requiredCount,
1432
+ utxo
1433
+ ) => {
1434
+ const processorUtxos = _nullishCoalesce(processorUtxosCache[scriptPubkey], () => ( {
1435
+ utxos: new Set(),
1436
+ processing: false,
1437
+ path,
1438
+ full: false
1439
+ }))
1440
+ if (utxo != null) processorUtxos.utxos.add(utxo)
1441
+ processorUtxosCache[scriptPubkey] = processorUtxos
1442
+ processorUtxos.full = processorUtxos.utxos.size >= requiredCount
1443
+ }