edge-currency-plugins 1.2.3 → 1.3.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.
@@ -5,7 +5,6 @@ var _bnjs = require('bn.js'); var _bnjs2 = _interopRequireDefault(_bnjs);
5
5
 
6
6
 
7
7
 
8
- var _keymanager = require('../../keymanager/keymanager');
9
8
 
10
9
 
11
10
 
@@ -58,39 +57,21 @@ var _keymanager = require('../../keymanager/keymanager');
58
57
 
59
58
 
60
59
 
60
+
61
61
  const toEdgeTransaction = async (
62
62
  args
63
63
  ) => {
64
- const { tx, processor, walletTools, pluginInfo } = args
65
- const { engineInfo, currencyInfo } = pluginInfo
64
+ const { tx, processor, walletTools, pluginInfo, walletId } = args
65
+ const { currencyInfo } = pluginInfo
66
66
  const ourReceiveAddresses = []
67
67
  for (const out of tx.ourOuts) {
68
68
  const { scriptPubkey } = tx.outputs[parseInt(out)]
69
69
  const address = await processor.fetchAddress(scriptPubkey)
70
70
 
71
- /*
72
- Hack to set replay protection tx to the correct script type through the
73
- address format.
74
-
75
- We use a function which can determine whether the derivationLevelScriptHash
76
- was used for the path's change index in order to detect whether an address
77
- is used for replay protection. We need to detect this because we must treat
78
- the address format as bip49 because the script is P2SH even though the
79
- address is on the bip44 derivation chain.
80
- */
81
- const scriptTemplate = _optionalChain([engineInfo, 'access', _ => _.scriptTemplates, 'optionalAccess', _2 => _2.replayProtection])
82
- if (
83
- scriptTemplate != null &&
84
- _optionalChain([address, 'optionalAccess', _3 => _3.path]) != null &&
85
- _keymanager.isPathUsingDerivationLevelScriptHash.call(void 0, scriptTemplate, address.path)
86
- ) {
87
- address.path.format = 'bip49'
88
- }
89
-
90
- if (_optionalChain([address, 'optionalAccess', _4 => _4.path]) != null) {
71
+ if (_optionalChain([address, 'optionalAccess', _ => _.path]) != null) {
91
72
  const { address: addrStr } = walletTools.scriptPubkeyToAddress({
92
- scriptPubkey,
93
- format: address.path.format
73
+ changePath: address.path,
74
+ scriptPubkey
94
75
  })
95
76
  ourReceiveAddresses.push(addrStr)
96
77
  }
@@ -114,6 +95,7 @@ var _keymanager = require('../../keymanager/keymanager');
114
95
  } catch (e) {}
115
96
 
116
97
  return {
98
+ walletId,
117
99
  currencyCode: currencyInfo.currencyCode,
118
100
  txid: tx.txid,
119
101
  blockHeight: tx.blockHeight,
@@ -13,6 +13,7 @@ var _disklet = require('disklet');
13
13
 
14
14
 
15
15
 
16
+
16
17
  var _types = require('edge-core-js/types');
17
18
 
18
19
  var _filterUndefined = require('../../../util/filterUndefined');
@@ -92,8 +93,8 @@ var _utils = require('./utils');
92
93
  }
93
94
 
94
95
  const walletTools = _makeUtxoWalletTools.makeUtxoWalletTools.call(void 0, {
95
- publicKey,
96
- coin: coinInfo.name
96
+ pluginInfo,
97
+ publicKey
97
98
  })
98
99
 
99
100
  const fees = await _makeFees.makeFees.call(void 0, {
@@ -227,9 +228,10 @@ var _utils = require('./utils');
227
228
  },
228
229
 
229
230
  async getFreshAddress(
230
- _opts
231
+ opts
231
232
  ) {
232
- return await engineState.getFreshAddress()
233
+ const { forceIndex } = opts
234
+ return await engineState.getFreshAddress({ forceIndex })
233
235
  },
234
236
 
235
237
  getNumTransactions(_opts) {
@@ -260,6 +262,7 @@ var _utils = require('./utils');
260
262
  txs.map(
261
263
  async (tx) =>
262
264
  await _ProcessorTransaction.toEdgeTransaction.call(void 0, {
265
+ walletId: walletInfo.id,
263
266
  tx,
264
267
  walletTools,
265
268
  processor,
@@ -281,7 +284,13 @@ var _utils = require('./utils');
281
284
  options
282
285
  ) {
283
286
  const { spendTargets } = edgeSpendInfo
284
- const { outputSort = 'bip69' } = _nullishCoalesce(edgeSpendInfo.otherParams, () => ( {}))
287
+ const { outputSort = 'bip69', utxoSourceAddress, forceChangeAddress } =
288
+ _nullishCoalesce(edgeSpendInfo.otherParams, () => ( {}))
289
+
290
+ let utxoScriptPubkey
291
+ if (utxoSourceAddress != null) {
292
+ utxoScriptPubkey = walletTools.addressToScriptPubkey(utxoSourceAddress)
293
+ }
285
294
 
286
295
  if (_optionalChain([options, 'optionalAccess', _5 => _5.CPFP]) == null && spendTargets.length < 1) {
287
296
  throw new Error('Need to provide Spend Targets')
@@ -293,7 +302,12 @@ var _utils = require('./utils');
293
302
  )
294
303
  const utxos =
295
304
  await _asyncNullishCoalesce(await _asyncOptionalChain([options, 'optionalAccess', async _6 => _6.utxos]), async () => (
296
- ((await processor.fetchUtxos({ utxoIds: [] })) )))
305
+ _filterUndefined.filterUndefined.call(void 0,
306
+ (await processor.fetchUtxos({
307
+ scriptPubkey: utxoScriptPubkey,
308
+ utxoIds: []
309
+ }))
310
+ )))
297
311
 
298
312
  if (
299
313
  bs.gt(totalAmountToSend, `${_utils.sumUtxos.call(void 0, utxos)}`) ||
@@ -353,9 +367,12 @@ var _utils = require('./utils');
353
367
  throw new Error('Need to provide Spend Targets')
354
368
  }
355
369
 
356
- const freshAddress = await engineState.getFreshAddress(1)
370
+ const freshAddress = await engineState.getFreshAddress({ branch: 1 })
357
371
  const freshChangeAddress =
358
- _nullishCoalesce(freshAddress.segwitAddress, () => ( freshAddress.publicAddress))
372
+ _nullishCoalesce(_nullishCoalesce(forceChangeAddress, () => (
373
+ freshAddress.segwitAddress)), () => (
374
+ freshAddress.publicAddress))
375
+
359
376
  const setRBF = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _9 => _9.setRBF]), () => ( false))
360
377
  const rbfTxid = edgeSpendInfo.rbfTxid
361
378
  let maxUtxo
@@ -443,6 +460,7 @@ var _utils = require('./utils');
443
460
  }
444
461
 
445
462
  const transaction = {
463
+ walletId: walletInfo.id,
446
464
  ourReceiveAddresses,
447
465
  otherParams,
448
466
  currencyCode: currencyInfo.currencyCode,
@@ -480,6 +498,7 @@ var _utils = require('./utils');
480
498
  async saveTx(edgeTx) {
481
499
  const tx = _ProcessorTransaction.fromEdgeTransaction.call(void 0, edgeTx)
482
500
  await _makeUtxoEngineState.transactionChanged.call(void 0, {
501
+ walletId: walletInfo.id,
483
502
  tx,
484
503
  pluginInfo,
485
504
  emitter,
@@ -568,6 +587,7 @@ var _utils = require('./utils');
568
587
  transaction.signedTx,
569
588
  transaction.currencyCode
570
589
  )
590
+ if (transaction.otherParams == null) transaction.otherParams = {}
571
591
  Object.assign(transaction.otherParams, {
572
592
  paymentProtocolInfo: {
573
593
  ...paymentProtocolInfo,
@@ -628,8 +648,8 @@ var _utils = require('./utils');
628
648
  const tmpMetadata = await _makeMetadata.makeMetadata.call(void 0, tmpConfig)
629
649
  const tmpProcessor = await _makeProcessor.makeProcessor.call(void 0, tmpConfig)
630
650
  const tmpWalletTools = _makeUtxoWalletTools.makeUtxoWalletTools.call(void 0, {
631
- publicKey: tmpWalletInfo.keys.publicKey,
632
- coin: coinInfo.name
651
+ pluginInfo,
652
+ publicKey: tmpWalletInfo.keys.publicKey
633
653
  })
634
654
 
635
655
  // Max spend after imported wallet finishes sync
@@ -54,6 +54,8 @@ var _makeServerStates = require('./makeServerStates');
54
54
 
55
55
 
56
56
 
57
+
58
+
57
59
  var _utils3 = require('./utils');
58
60
 
59
61
 
@@ -84,6 +86,9 @@ var _utils3 = require('./utils');
84
86
 
85
87
 
86
88
 
89
+
90
+
91
+
87
92
 
88
93
 
89
94
 
@@ -240,8 +245,7 @@ var _utils3 = require('./utils');
240
245
  addToAddressTransactionCache(
241
246
  commonArgs,
242
247
  response.address,
243
- path.format,
244
- path.changeIndex,
248
+ path,
245
249
  0,
246
250
  taskCache.addressTransactionCache
247
251
  ).catch(() => {
@@ -264,13 +268,16 @@ var _utils3 = require('./utils');
264
268
  = []
265
269
 
266
270
  for (const format of walletFormats) {
267
- const branches = _utils3.getFormatSupportedBranches.call(void 0, format)
271
+ const branches = _utils3.getFormatSupportedBranches.call(void 0, pluginInfo.engineInfo, format)
268
272
  for (const branch of branches) {
269
273
  const addressesToSubscribe = new Set()
270
- const branchAddressCount = processor.numAddressesByFormatPath({
274
+ const changePath = {
271
275
  format,
272
276
  changeIndex: branch
273
- })
277
+ }
278
+ const branchAddressCount = processor.numAddressesByFormatPath(
279
+ changePath
280
+ )
274
281
  // If the processor has not processed any addresses then the loop
275
282
  // condition will only iterate once when branchAddressCount is 0 for the
276
283
  // first address in the derivation path.
@@ -290,8 +297,8 @@ var _utils3 = require('./utils');
290
297
  )
291
298
  }
292
299
  const { address } = walletTools.scriptPubkeyToAddress({
293
- scriptPubkey: processorAddress.scriptPubkey,
294
- format
300
+ changePath,
301
+ scriptPubkey: processorAddress.scriptPubkey
295
302
  })
296
303
  addressesToSubscribe.add(address)
297
304
  addressBalanceChanges.push({
@@ -332,28 +339,48 @@ var _utils3 = require('./utils');
332
339
  running = false
333
340
  },
334
341
 
335
- async getFreshAddress(branch = 0) {
342
+ async getFreshAddress({
343
+ branch = 0,
344
+ forceIndex
345
+ }) {
336
346
  const walletPurpose = _utils3.currencyFormatToPurposeType.call(void 0,
337
347
  walletInfo.keys.primaryFormat
338
348
  )
339
349
  if (walletPurpose === _keymanager.BIP43PurposeTypeEnum.Segwit) {
340
- const { address: publicAddress } = await internalGetFreshAddress({
350
+ const {
351
+ address: publicAddress,
352
+ nativeBalance = '0',
353
+ legacyAddress
354
+ } = await internalGetFreshAddress({
341
355
  ...commonArgs,
342
356
  format: _utils3.getCurrencyFormatFromPurposeType.call(void 0,
343
357
  _keymanager.BIP43PurposeTypeEnum.WrappedSegwit
344
358
  ),
359
+ forceIndex,
345
360
  changeIndex: branch
346
361
  })
347
362
 
348
- const { address: segwitAddress } = await internalGetFreshAddress({
363
+ const {
364
+ address: segwitAddress,
365
+ nativeBalance: segwitNativeBalance = '0'
366
+ } = await internalGetFreshAddress({
349
367
  ...commonArgs,
350
368
  format: _utils3.getCurrencyFormatFromPurposeType.call(void 0, _keymanager.BIP43PurposeTypeEnum.Segwit),
369
+ forceIndex,
351
370
  changeIndex: branch
352
371
  })
353
372
 
354
373
  return {
374
+ nativeBalance,
355
375
  publicAddress,
356
- segwitAddress
376
+ legacyNativeBalance:
377
+ legacyAddress !== publicAddress ? nativeBalance : undefined,
378
+ // Legacy address is just a different encoding of the standard public address
379
+ // and therefore would have the same balance
380
+ legacyAddress:
381
+ legacyAddress !== publicAddress ? legacyAddress : undefined,
382
+ segwitAddress,
383
+ segwitNativeBalance
357
384
  }
358
385
  } else {
359
386
  // Airbitz wallets only use branch 0
@@ -363,15 +390,22 @@ var _utils3 = require('./utils');
363
390
 
364
391
  const {
365
392
  address: publicAddress,
393
+ nativeBalance = '0',
366
394
  legacyAddress
367
395
  } = await internalGetFreshAddress({
368
396
  ...commonArgs,
369
397
  format: _utils3.getCurrencyFormatFromPurposeType.call(void 0, walletPurpose),
398
+ forceIndex,
370
399
  changeIndex: branch
371
400
  })
372
401
 
373
402
  return {
403
+ nativeBalance,
374
404
  publicAddress,
405
+ legacyNativeBalance:
406
+ legacyAddress !== publicAddress ? nativeBalance : undefined,
407
+ // Legacy address is just a different encoding of the standard public address
408
+ // and therefore would have the same balance
375
409
  legacyAddress:
376
410
  legacyAddress !== publicAddress ? legacyAddress : undefined
377
411
  }
@@ -437,8 +471,8 @@ var _utils3 = require('./utils');
437
471
  redeemScript
438
472
  } = walletTools.getScriptPubkeyFromWif(wif, format)
439
473
  const { address } = walletTools.scriptPubkeyToAddress({
440
- scriptPubkey,
441
- format: path.format
474
+ changePath: path,
475
+ scriptPubkey
442
476
  })
443
477
 
444
478
  // Make a new IAddress and save it
@@ -555,6 +589,7 @@ var _utils3 = require('./utils');
555
589
 
556
590
 
557
591
 
592
+
558
593
 
559
594
 
560
595
  const setLookAhead = async (common) => {
@@ -572,7 +607,7 @@ const setLookAhead = async (common) => {
572
607
 
573
608
  try {
574
609
  for (const format of walletFormats) {
575
- const branches = _utils3.getFormatSupportedBranches.call(void 0, format)
610
+ const branches = _utils3.getFormatSupportedBranches.call(void 0, engineInfo, format)
576
611
  for (const branch of branches) {
577
612
  await deriveKeys({ format, changeIndex: branch })
578
613
  }
@@ -597,8 +632,8 @@ const setLookAhead = async (common) => {
597
632
 
598
633
  const { scriptPubkey, redeemScript } = walletTools.getScriptPubkey(path)
599
634
  const { address } = walletTools.scriptPubkeyToAddress({
600
- scriptPubkey,
601
- format: path.format
635
+ changePath: path,
636
+ scriptPubkey
602
637
  })
603
638
 
604
639
  // Make a new IAddress and save it
@@ -638,14 +673,13 @@ const addToAddressSubscribeCache = (
638
673
  }
639
674
 
640
675
  const addToAddressTransactionCache = async (
641
- args,
676
+ common,
642
677
  address,
643
- format,
644
- branch,
678
+ changePath,
645
679
  blockHeight,
646
680
  addressTransactionCache
647
681
  ) => {
648
- const { walletTools, processor } = args
682
+ const { walletTools, processor } = common
649
683
  // Fetch the blockHeight for the address from the database
650
684
  const scriptPubkey = walletTools.addressToScriptPubkey(address)
651
685
 
@@ -657,10 +691,7 @@ const addToAddressTransactionCache = async (
657
691
 
658
692
  addressTransactionCache[address] = {
659
693
  processing: false,
660
- path: {
661
- format,
662
- changeIndex: branch
663
- },
694
+ path: changePath,
664
695
  page: 1, // Page starts on 1
665
696
  blockHeight
666
697
  }
@@ -674,12 +705,14 @@ const addToAddressTransactionCache = async (
674
705
 
675
706
 
676
707
 
708
+
677
709
  const transactionChanged = async (
678
710
  args
679
711
  ) => {
680
- const { emitter, walletTools, processor, pluginInfo, tx } = args
712
+ const { emitter, walletTools, processor, pluginInfo, tx, walletId } = args
681
713
  emitter.emit(_makeEngineEmitter.EngineEvent.TRANSACTIONS_CHANGED, [
682
714
  await _ProcessorTransaction.toEdgeTransaction.call(void 0, {
715
+ walletId,
683
716
  tx,
684
717
  walletTools,
685
718
  processor,
@@ -742,21 +775,25 @@ const addToAddressTransactionCache = async (
742
775
  }
743
776
 
744
777
  // Loop unparsed utxos, some require a network call to get the full tx data
745
- for (const [utxoString, state] of Object.entries(rawUtxoCache)) {
746
- const utxo = JSON.parse(utxoString)
778
+ for (const [utxoId, state] of Object.entries(rawUtxoCache)) {
779
+ const utxo = state.blockbookUtxo
747
780
  if (utxo == null) continue
748
781
  if (!state.processing) {
749
782
  // check if we need to fetch additional network content for legacy purpose type
750
- const purposeType = _utils3.currencyFormatToPurposeType.call(void 0, state.path.format)
783
+ const purposeType = _utils3.pathToPurposeType.call(void 0,
784
+ state.path,
785
+ pluginInfo.engineInfo.scriptTemplates
786
+ )
751
787
  if (
752
788
  purposeType === _keymanager.BIP43PurposeTypeEnum.Airbitz ||
753
- purposeType === _keymanager.BIP43PurposeTypeEnum.Legacy
789
+ purposeType === _keymanager.BIP43PurposeTypeEnum.Legacy ||
790
+ purposeType === _keymanager.BIP43PurposeTypeEnum.ReplayProtection
754
791
  ) {
755
792
  // if we do need to make a network call, check with the serverState
756
793
  if (!serverStates.serverCanGetTx(uri, utxo.txid)) return
757
794
  }
758
795
  state.processing = true
759
- _utils.removeItem.call(void 0, rawUtxoCache, utxoString)
796
+ _utils.removeItem.call(void 0, rawUtxoCache, utxoId)
760
797
  const wsTask = await processRawUtxo({
761
798
  ...args,
762
799
  ...state,
@@ -797,30 +834,38 @@ const addToAddressTransactionCache = async (
797
834
 
798
835
  // Check if there are any addresses pending to be subscribed
799
836
  if (Object.keys(addressSubscribeCache).length > 0) {
800
- // These are addresse to which the server has not subscribed
801
- const newAddress = []
837
+ // These are addresses to which the server has not subscribed
838
+ const newAddresses = []
802
839
  const blockHeight = serverStates.getBlockHeight(uri)
803
840
 
804
841
  // Loop each address in the cache
805
842
  for (const [address, state] of Object.entries(addressSubscribeCache)) {
843
+ const isAddressNewlySubscribed = !serverStates.serverIsAwareOfAddress(
844
+ uri,
845
+ address
846
+ )
847
+
806
848
  // Add address in the cache to the set of addresses to watch
807
- if (!serverStates.serverIsAwareOfAddress(uri, address)) {
808
- newAddress.push(address)
849
+ if (isAddressNewlySubscribed) {
850
+ newAddresses.push(address)
809
851
  }
810
852
 
811
853
  // Add to the addressTransactionCache if they're not yet added:
812
854
  // Only process newly watched addresses
813
855
  if (state.processing) continue
856
+
814
857
  // Add the newly watched addresses to the UTXO cache
815
- addressUtxoCache[address] = {
816
- processing: false,
817
- path: state.path
858
+ if (isAddressNewlySubscribed) {
859
+ addressUtxoCache[address] = {
860
+ processing: false,
861
+ path: state.path
862
+ }
818
863
  }
864
+
819
865
  await addToAddressTransactionCache(
820
866
  args,
821
867
  address,
822
- state.path.format,
823
- state.path.changeIndex,
868
+ state.path,
824
869
  blockHeight,
825
870
  addressTransactionCache
826
871
  )
@@ -828,8 +873,8 @@ const addToAddressTransactionCache = async (
828
873
  }
829
874
 
830
875
  // Subscribe to any new addresses
831
- if (newAddress.length > 0) {
832
- serverStates.watchAddresses(uri, newAddress)
876
+ if (newAddresses.length > 0) {
877
+ serverStates.watchAddresses(uri, newAddresses)
833
878
  return true
834
879
  }
835
880
  }
@@ -930,7 +975,15 @@ const addToAddressTransactionCache = async (
930
975
  const updateTransactionsSpecific = (
931
976
  args
932
977
  ) => {
933
- const { emitter, walletTools, txId, pluginInfo, processor, taskCache } = args
978
+ const {
979
+ walletInfo,
980
+ emitter,
981
+ walletTools,
982
+ txId,
983
+ pluginInfo,
984
+ processor,
985
+ taskCache
986
+ } = args
934
987
  const deferred = new _Deferred2.default()
935
988
  deferred.promise
936
989
  .then(async (txResponse) => {
@@ -950,6 +1003,7 @@ const updateTransactionsSpecific = (
950
1003
  })
951
1004
 
952
1005
  await exports.transactionChanged.call(void 0, {
1006
+ walletId: walletInfo.id,
953
1007
  emitter,
954
1008
  walletTools,
955
1009
  processor,
@@ -977,6 +1031,7 @@ const updateTransactions = (
977
1031
  args
978
1032
  ) => {
979
1033
  const {
1034
+ walletInfo,
980
1035
  emitter,
981
1036
  walletTools,
982
1037
  txId,
@@ -1012,6 +1067,7 @@ const updateTransactions = (
1012
1067
  })
1013
1068
 
1014
1069
  await exports.transactionChanged.call(void 0, {
1070
+ walletId: walletInfo.id,
1015
1071
  emitter,
1016
1072
  walletTools,
1017
1073
  processor,
@@ -1098,10 +1154,19 @@ const internalDeriveScriptAddress = async ({
1098
1154
 
1099
1155
 
1100
1156
 
1157
+
1158
+
1159
+
1101
1160
  const internalGetFreshAddress = async (
1102
1161
  args
1103
1162
  ) => {
1104
- const { format, changeIndex: branch, walletTools, processor } = args
1163
+ const {
1164
+ format,
1165
+ changeIndex: branch,
1166
+ walletTools,
1167
+ processor,
1168
+ forceIndex
1169
+ } = args
1105
1170
 
1106
1171
  const numAddresses = processor.numAddressesByFormatPath({
1107
1172
  format,
@@ -1117,16 +1182,33 @@ const internalGetFreshAddress = async (
1117
1182
  0
1118
1183
  )
1119
1184
  }
1120
- const { scriptPubkey } =
1121
- await _asyncNullishCoalesce((await processor.fetchAddress(path)), async () => (
1122
- (await walletTools.getScriptPubkey(path))))
1185
+ if (forceIndex != null) {
1186
+ path.addressIndex = forceIndex
1187
+ }
1188
+
1189
+ let nativeBalance = '0'
1190
+ let scriptPubkey
1191
+ const iAddress = await processor.fetchAddress(path)
1192
+ if (iAddress != null) {
1193
+ nativeBalance = iAddress.balance
1194
+ scriptPubkey = iAddress.scriptPubkey
1195
+ } else {
1196
+ const scriptPubKeyRet = await walletTools.getScriptPubkey(path)
1197
+ scriptPubkey = scriptPubKeyRet.scriptPubkey
1198
+ }
1199
+
1123
1200
  if (scriptPubkey == null) {
1124
1201
  throw new Error('Unknown address path')
1125
1202
  }
1126
- return walletTools.scriptPubkeyToAddress({
1127
- scriptPubkey,
1128
- format
1203
+ const address = walletTools.scriptPubkeyToAddress({
1204
+ changePath: path,
1205
+ scriptPubkey
1129
1206
  })
1207
+
1208
+ return {
1209
+ ...address,
1210
+ nativeBalance
1211
+ }
1130
1212
  }
1131
1213
 
1132
1214
 
@@ -1140,6 +1222,7 @@ const processAddressTransactions = async (
1140
1222
  args
1141
1223
  ) => {
1142
1224
  const {
1225
+ walletInfo,
1143
1226
  address,
1144
1227
  addressTransactionState,
1145
1228
  emitter,
@@ -1184,6 +1267,7 @@ const processAddressTransactions = async (
1184
1267
  scriptPubkeys: [scriptPubkey]
1185
1268
  })
1186
1269
  await exports.transactionChanged.call(void 0, {
1270
+ walletId: walletInfo.id,
1187
1271
  emitter,
1188
1272
  walletTools,
1189
1273
  processor,
@@ -1344,7 +1428,9 @@ const processAddressUtxos = async (
1344
1428
  }
1345
1429
 
1346
1430
  for (const utxo of utxos) {
1347
- rawUtxoCache[JSON.stringify(utxo)] = {
1431
+ const utxoId = `${utxo.txid}_${utxo.vout}`
1432
+ rawUtxoCache[utxoId] = {
1433
+ blockbookUtxo: utxo,
1348
1434
  processing: false,
1349
1435
  requiredCount: utxos.length,
1350
1436
  path,
@@ -1486,6 +1572,7 @@ const processRawUtxo = async (
1486
1572
  utxo,
1487
1573
  id,
1488
1574
  address,
1575
+ pluginInfo,
1489
1576
  processor,
1490
1577
  path,
1491
1578
  taskCache,
@@ -1495,7 +1582,11 @@ const processRawUtxo = async (
1495
1582
  log
1496
1583
  } = args
1497
1584
  const { rawUtxoCache, processorUtxoCache } = taskCache
1498
- let scriptType
1585
+ const purposeType = _utils3.pathToPurposeType.call(void 0,
1586
+ path,
1587
+ pluginInfo.engineInfo.scriptTemplates
1588
+ )
1589
+ const scriptType = _utils3.getScriptTypeFromPurposeType.call(void 0, purposeType)
1499
1590
  let script
1500
1591
  let redeemScript
1501
1592
 
@@ -1520,19 +1611,18 @@ const processRawUtxo = async (
1520
1611
  }
1521
1612
  )
1522
1613
 
1523
- switch (_utils3.currencyFormatToPurposeType.call(void 0, path.format)) {
1614
+ switch (purposeType) {
1524
1615
  case _keymanager.BIP43PurposeTypeEnum.Airbitz:
1525
1616
  case _keymanager.BIP43PurposeTypeEnum.Legacy:
1526
- scriptType = _keymanager.ScriptTypeEnum.p2pkh
1527
- if (address.redeemScript != null) {
1528
- scriptType = _keymanager.ScriptTypeEnum.p2sh
1529
- redeemScript = address.redeemScript
1530
- }
1617
+ case _keymanager.BIP43PurposeTypeEnum.ReplayProtection:
1618
+ redeemScript = address.redeemScript
1531
1619
 
1532
1620
  // Legacy UTXOs need the previous transaction hex as the script
1533
1621
  // If we do not currently have it, add it to the queue to fetch it
1534
1622
  {
1535
- const [tx] = await processor.fetchTransactions({ txId: utxo.txid })
1623
+ const [tx] = await processor.fetchTransactions({
1624
+ txId: utxo.txid
1625
+ })
1536
1626
  if (tx == null) {
1537
1627
  const queryTime = Date.now()
1538
1628
  const deferred = new _Deferred2.default()
@@ -1550,7 +1640,9 @@ const processRawUtxo = async (
1550
1640
  .catch(err => {
1551
1641
  // If something went wrong, add the UTXO back to the queue
1552
1642
  log('error in processRawUtxo:', err)
1553
- rawUtxoCache[JSON.stringify(utxo)] = {
1643
+ const utxoId = `${utxo.txid}_${utxo.vout}`
1644
+ rawUtxoCache[utxoId] = {
1645
+ blockbookUtxo: utxo,
1554
1646
  processing: false,
1555
1647
  path,
1556
1648
  address,
@@ -1568,7 +1660,6 @@ const processRawUtxo = async (
1568
1660
 
1569
1661
  break
1570
1662
  case _keymanager.BIP43PurposeTypeEnum.WrappedSegwit:
1571
- scriptType = _keymanager.ScriptTypeEnum.p2wpkhp2sh
1572
1663
  script = address.scriptPubkey
1573
1664
  if (address.redeemScript == null) {
1574
1665
  throw new Error(
@@ -1579,7 +1670,6 @@ const processRawUtxo = async (
1579
1670
 
1580
1671
  break
1581
1672
  case _keymanager.BIP43PurposeTypeEnum.Segwit:
1582
- scriptType = _keymanager.ScriptTypeEnum.p2wpkh
1583
1673
  script = address.scriptPubkey
1584
1674
 
1585
1675
  break
@@ -13,12 +13,18 @@
13
13
 
14
14
 
15
15
 
16
+
17
+
18
+
19
+
20
+
16
21
  var _keymanager = require('../keymanager/keymanager');
17
22
 
18
23
 
19
24
 
20
25
 
21
26
 
27
+
22
28
  var _utils = require('./utils');
23
29
 
24
30
 
@@ -91,7 +97,9 @@ var _utils = require('./utils');
91
97
  function makeUtxoWalletTools(
92
98
  config
93
99
  ) {
94
- const { coin, publicKey } = config
100
+ const { pluginInfo, publicKey } = config
101
+ const { engineInfo } = pluginInfo
102
+ const { name: coin } = pluginInfo.coinInfo
95
103
 
96
104
  const xpubKeys = publicKey.publicKeys
97
105
 
@@ -112,10 +120,11 @@ var _utils = require('./utils');
112
120
  },
113
121
 
114
122
  getScriptPubkey(args) {
115
- const purposeType = _utils.currencyFormatToPurposeType.call(void 0, args.format)
123
+ const purposeType = _utils.pathToPurposeType.call(void 0, args, engineInfo.scriptTemplates)
116
124
  const scriptType = _utils.getScriptTypeFromPurposeType.call(void 0, purposeType)
117
125
  return _keymanager.pubkeyToScriptPubkey.call(void 0, {
118
126
  pubkey: fns.getPubkey(args),
127
+ scriptTemplates: engineInfo.scriptTemplates,
119
128
  scriptType
120
129
  })
121
130
  },
@@ -147,12 +156,16 @@ var _utils = require('./utils');
147
156
  const pubkey = _keymanager.privateKeyEncodingToPubkey.call(void 0, privateKeyEncoding)
148
157
  return _keymanager.pubkeyToScriptPubkey.call(void 0, {
149
158
  pubkey: pubkey,
159
+ scriptTemplates: engineInfo.scriptTemplates,
150
160
  scriptType
151
161
  })
152
162
  },
153
163
 
154
164
  getAddress(args) {
155
- const purposeType = _utils.currencyFormatToPurposeType.call(void 0, args.format)
165
+ const purposeType = _utils.pathToPurposeType.call(void 0,
166
+ args,
167
+ pluginInfo.engineInfo.scriptTemplates
168
+ )
156
169
  const { scriptPubkey } = fns.getScriptPubkey(args)
157
170
  const addressType = _utils.getAddressTypeFromPurposeType.call(void 0, purposeType)
158
171
  return _keymanager.scriptPubkeyToAddress.call(void 0, {
@@ -167,8 +180,13 @@ var _utils = require('./utils');
167
180
  },
168
181
 
169
182
  scriptPubkeyToAddress(args) {
170
- const purposeType = _utils.currencyFormatToPurposeType.call(void 0, args.format)
183
+ const { changePath } = args
184
+ const purposeType = _utils.pathToPurposeType.call(void 0,
185
+ changePath,
186
+ pluginInfo.engineInfo.scriptTemplates
187
+ )
171
188
  const addressType = _utils.getAddressTypeFromPurposeType.call(void 0, purposeType)
189
+
172
190
  return _keymanager.scriptPubkeyToAddress.call(void 0, {
173
191
  scriptPubkey: args.scriptPubkey,
174
192
  addressType,
@@ -2,9 +2,6 @@
2
2
 
3
3
 
4
4
  var _keymanager = require('../../keymanager/keymanager');
5
-
6
-
7
-
8
5
  var _utils = require('../utils');
9
6
 
10
7
  const getOwnUtxosFromTx = async (
@@ -43,18 +40,15 @@ var _utils = require('../utils');
43
40
  const path = address.path
44
41
  if (path != null) {
45
42
  const redeemScript = address.redeemScript
46
- const purposeType = _utils.currencyFormatToPurposeType.call(void 0, path.format)
43
+ const purposeType = _utils.pathToPurposeType.call(void 0, path, engineInfo.scriptTemplates)
47
44
 
48
45
  const isAirbitzOrLegacy = [
49
46
  _keymanager.BIP43PurposeTypeEnum.Airbitz,
50
- _keymanager.BIP43PurposeTypeEnum.Legacy
47
+ _keymanager.BIP43PurposeTypeEnum.Legacy,
48
+ _keymanager.BIP43PurposeTypeEnum.ReplayProtection
51
49
  ].includes(purposeType)
52
50
 
53
- const scriptType = _utils.getScriptTypeFromPurposeType.call(void 0,
54
- purposeType,
55
- redeemScript,
56
- engineInfo.scriptTemplates
57
- )
51
+ const scriptType = _utils.getScriptTypeFromPurposeType.call(void 0, purposeType)
58
52
  const script = isAirbitzOrLegacy ? tx.hex : address.scriptPubkey
59
53
  const utxo = {
60
54
  id,
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } 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'); var bs = _interopRequireWildcard(_biggystring);
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } }var _biggystring = require('biggystring'); var bs = _interopRequireWildcard(_biggystring);
2
2
 
3
3
 
4
4
 
@@ -18,6 +18,8 @@ var _cleaners = require('../keymanager/cleaners');
18
18
 
19
19
 
20
20
 
21
+
22
+
21
23
  var _keymanager = require('../keymanager/keymanager');
22
24
 
23
25
  const getCurrencyFormatFromPurposeType = (
@@ -32,6 +34,8 @@ var _keymanager = require('../keymanager/keymanager');
32
34
  return 'bip49'
33
35
  case _keymanager.BIP43PurposeTypeEnum.Segwit:
34
36
  return 'bip84'
37
+ case _keymanager.BIP43PurposeTypeEnum.ReplayProtection:
38
+ return 'bip44' // Only bip44 formatted wallets contain this purpose type (BCH)
35
39
  }
36
40
  }; exports.getCurrencyFormatFromPurposeType = getCurrencyFormatFromPurposeType
37
41
 
@@ -69,27 +73,18 @@ var _keymanager = require('../keymanager/keymanager');
69
73
 
70
74
  case _keymanager.BIP43PurposeTypeEnum.Segwit:
71
75
  return _keymanager.AddressTypeEnum.p2wpkh
76
+
77
+ case _keymanager.BIP43PurposeTypeEnum.ReplayProtection:
78
+ return _keymanager.AddressTypeEnum.p2sh
72
79
  }
73
80
  }; exports.getAddressTypeFromPurposeType = getAddressTypeFromPurposeType
74
81
 
75
82
  const getScriptTypeFromPurposeType = (
76
- purpose,
77
- redeemScript,
78
- scriptTemplates
83
+ purpose
79
84
  ) => {
80
85
  switch (purpose) {
81
86
  case _keymanager.BIP43PurposeTypeEnum.Airbitz:
82
87
  case _keymanager.BIP43PurposeTypeEnum.Legacy:
83
- if (redeemScript != null) {
84
- if (_optionalChain([scriptTemplates, 'optionalAccess', _ => _.replayProtection]) != null) {
85
- const replayProtectionPartialScript = scriptTemplates
86
- .replayProtection('')
87
- .slice(0, -4)
88
- if (redeemScript.indexOf(replayProtectionPartialScript) === 0) {
89
- return _keymanager.ScriptTypeEnum.replayProtection
90
- }
91
- }
92
- }
93
88
  return _keymanager.ScriptTypeEnum.p2pkh
94
89
 
95
90
  case _keymanager.BIP43PurposeTypeEnum.WrappedSegwit:
@@ -97,6 +92,9 @@ var _keymanager = require('../keymanager/keymanager');
97
92
 
98
93
  case _keymanager.BIP43PurposeTypeEnum.Segwit:
99
94
  return _keymanager.ScriptTypeEnum.p2wpkh
95
+
96
+ case _keymanager.BIP43PurposeTypeEnum.ReplayProtection:
97
+ return _keymanager.ScriptTypeEnum.replayProtection
100
98
  }
101
99
  }; exports.getScriptTypeFromPurposeType = getScriptTypeFromPurposeType
102
100
 
@@ -109,15 +107,63 @@ var _keymanager = require('../keymanager/keymanager');
109
107
  }); exports.validScriptPubkeyFromAddress = validScriptPubkeyFromAddress
110
108
 
111
109
  const getFormatSupportedBranches = (
110
+ engineInfo,
112
111
  format
113
112
  ) => {
114
113
  const branches = [0]
115
114
  if (exports.currencyFormatToPurposeType.call(void 0, format) !== _keymanager.BIP43PurposeTypeEnum.Airbitz) {
116
115
  branches.push(1)
117
116
  }
117
+ if (engineInfo.scriptTemplates != null) {
118
+ if (engineInfo.scriptTemplates.replayProtection != null) {
119
+ branches.push(
120
+ _keymanager.derivationLevelScriptHash.call(void 0, engineInfo.scriptTemplates.replayProtection)
121
+ )
122
+ }
123
+ }
118
124
  return branches
119
125
  }; exports.getFormatSupportedBranches = getFormatSupportedBranches
120
126
 
127
+ /**
128
+ * The reason for this function is to consider the address path for
129
+ * determining the purpose-type for the address. This is because some parts
130
+ * of the address such as the changeIndex have special meaning for the
131
+ * purpose-type. Specifically for scriptTemplates, the hash of the template
132
+ * is used to deterministically identify the changeIndex used constantly for
133
+ * the addresses spending to those scriptTemplates.
134
+ *
135
+ * In the future, we will want to strictly use only the format of the path
136
+ * in order to determine the purpose-type per the BIP43 spec. This will require
137
+ * a significant lift to reconsider the type for the path's format (currently
138
+ * CurrencyFormat). The scriptTemplates could define a format index and this
139
+ * could be used in address paths instead of a CurrencyType.
140
+ */
141
+ const pathToPurposeType = (
142
+ path,
143
+ scriptTemplates
144
+ ) => {
145
+ // Script Template Purpose Types
146
+ if (scriptTemplates != null) {
147
+ // TODO: Change ScriptTemplates map type to couple the key to the ScriptTypeEnum; make this algorithm generic and move it to key-manager
148
+ // Handle each hard-coded case for the supported script templates
149
+ if (
150
+ scriptTemplates.replayProtection != null &&
151
+ _keymanager.isPathUsingDerivationLevelScriptHash.call(void 0,
152
+ scriptTemplates.replayProtection,
153
+ path
154
+ )
155
+ ) {
156
+ return _keymanager.BIP43PurposeTypeEnum.ReplayProtection
157
+ }
158
+ }
159
+ return exports.currencyFormatToPurposeType.call(void 0, path.format)
160
+ }; exports.pathToPurposeType = pathToPurposeType
161
+
162
+ /**
163
+ * Only use this function when needing to infer the purpose-type for a wallet
164
+ * format (CurrencyFormat). To get the purpose-type for an address use
165
+ * pathToPurposeType passing the address path.
166
+ */
121
167
  const currencyFormatToPurposeType = (
122
168
  format
123
169
  ) =>
@@ -52,7 +52,7 @@ const currencyInfo = {
52
52
 
53
53
  const engineInfo = {
54
54
  formats: ['bip44', 'bip32'],
55
- // forks: ['bitcoinsv'],
55
+ forks: ['bitcoinsv'],
56
56
  gapLimit: 10,
57
57
  defaultFee: 10000,
58
58
  feeUpdateInterval: 60000,
@@ -28,6 +28,7 @@ var BIP43PurposeTypeEnum; (function (BIP43PurposeTypeEnum) {
28
28
  const Legacy = 'legacy'; BIP43PurposeTypeEnum["Legacy"] = Legacy; // xpub/xprv tpub/tprv etc.
29
29
  const Segwit = 'segwit'; BIP43PurposeTypeEnum["Segwit"] = Segwit; // zpub/zprv vpub/vprv etc.
30
30
  const WrappedSegwit = 'wrappedSegwit'; BIP43PurposeTypeEnum["WrappedSegwit"] = WrappedSegwit; // ypub/yprv upub/uprv etc.
31
+ const ReplayProtection = 'replayProtection'; BIP43PurposeTypeEnum["ReplayProtection"] = ReplayProtection;
31
32
  })(BIP43PurposeTypeEnum || (exports.BIP43PurposeTypeEnum = BIP43PurposeTypeEnum = {}));
32
33
 
33
34
  // supported address types.
@@ -239,6 +240,7 @@ var VerifyAddressEnum; (function (VerifyAddressEnum) {
239
240
 
240
241
 
241
242
 
243
+
242
244
 
243
245
 
244
246
  function bip43PurposeNumberToTypeEnum(
@@ -510,12 +512,18 @@ const addressToScriptPubkeyInternal = (
510
512
  default:
511
513
  throw new Error('invalid address type in address to script pubkey')
512
514
  }
513
- const scriptPubkey = payment({
514
- address: args.address,
515
- network: network,
516
- bs58DecodeFunc: coin.bs58DecodeFunc,
517
- bs58EncodeFunc: coin.bs58EncodeFunc
518
- }).output
515
+ let scriptPubkey
516
+ try {
517
+ scriptPubkey = payment({
518
+ address: args.address,
519
+ network: network,
520
+ bs58DecodeFunc: coin.bs58DecodeFunc,
521
+ bs58EncodeFunc: coin.bs58EncodeFunc
522
+ }).output
523
+ } catch (error) {
524
+ console.trace(error)
525
+ throw error
526
+ }
519
527
  if (scriptPubkey == null) {
520
528
  throw new Error('failed converting address to scriptPubkey')
521
529
  }
@@ -621,23 +629,28 @@ const addressToScriptPubkeyInternal = (
621
629
  default:
622
630
  throw new Error('invalid address type in address to script pubkey')
623
631
  }
624
- address =
625
- _nullishCoalesce(address, () => (
626
- payment({
627
- output: Buffer.from(args.scriptPubkey, 'hex'),
628
- network: network,
629
- bs58DecodeFunc: coinClass.bs58DecodeFunc,
630
- bs58EncodeFunc: coinClass.bs58EncodeFunc
631
- }).address))
632
-
633
- legacyAddress =
634
- _nullishCoalesce(legacyAddress, () => (
635
- payment({
636
- output: Buffer.from(args.scriptPubkey, 'hex'),
637
- network: legacyNetwork,
638
- bs58DecodeFunc: coinClass.bs58DecodeFunc,
639
- bs58EncodeFunc: coinClass.bs58EncodeFunc
640
- }).address))
632
+ try {
633
+ address =
634
+ _nullishCoalesce(address, () => (
635
+ payment({
636
+ output: Buffer.from(args.scriptPubkey, 'hex'),
637
+ network: network,
638
+ bs58DecodeFunc: coinClass.bs58DecodeFunc,
639
+ bs58EncodeFunc: coinClass.bs58EncodeFunc
640
+ }).address))
641
+
642
+ legacyAddress =
643
+ _nullishCoalesce(legacyAddress, () => (
644
+ payment({
645
+ output: Buffer.from(args.scriptPubkey, 'hex'),
646
+ network: legacyNetwork,
647
+ bs58DecodeFunc: coinClass.bs58DecodeFunc,
648
+ bs58EncodeFunc: coinClass.bs58EncodeFunc
649
+ }).address))
650
+ } catch (error) {
651
+ console.trace(error)
652
+ throw error
653
+ }
641
654
 
642
655
  if (address == null || legacyAddress == null) {
643
656
  throw new Error('failed converting scriptPubkey to address')
@@ -666,10 +679,16 @@ const addressToScriptPubkeyInternal = (
666
679
  default:
667
680
  throw new Error('invalid address type in address to script pubkey')
668
681
  }
669
- const scriptHash = payment({
670
- output: Buffer.from(args.scriptPubkey, 'hex'),
671
- network: network
672
- }).hash
682
+ let scriptHash
683
+ try {
684
+ scriptHash = payment({
685
+ output: Buffer.from(args.scriptPubkey, 'hex'),
686
+ network: network
687
+ }).hash
688
+ } catch (error) {
689
+ console.trace(error)
690
+ throw error
691
+ }
673
692
  if (scriptHash == null) {
674
693
  throw new Error('failed converting scriptPubkey to address')
675
694
  }
@@ -693,13 +712,34 @@ const addressToScriptPubkeyInternal = (
693
712
  output: Buffer.from(scriptPubkey, 'hex')
694
713
  }
695
714
  })
696
- if (p2sh.output == null || _optionalChain([p2sh, 'access', _ => _.redeem, 'optionalAccess', _2 => _2.output]) == null) {
715
+ const scriptPubkeyFromLib = _optionalChain([p2sh, 'access', _ => _.output, 'optionalAccess', _2 => _2.toString, 'call', _3 => _3('hex')])
716
+ const redeemScript = _optionalChain([p2sh, 'access', _4 => _4.redeem, 'optionalAccess', _5 => _5.output, 'optionalAccess', _6 => _6.toString, 'call', _7 => _7('hex')])
717
+ const scriptHash = _optionalChain([p2sh, 'access', _8 => _8.hash, 'optionalAccess', _9 => _9.toString, 'call', _10 => _10('hex')])
718
+
719
+ if (scriptPubkeyFromLib == null || redeemScript == null) {
697
720
  throw new Error('unable to convert script to p2sh')
698
721
  }
722
+
723
+ let address = p2sh.address
724
+
725
+ // Special cashaddr handling
726
+ if (coin != null && scriptHash != null) {
727
+ const coinClass = _coinmapper.getCoinFromString.call(void 0, coin)
728
+ const coinPrefixes = coinClass.prefixes
729
+ const standardPrefixes = selectedCoinPrefixes(coinPrefixes, 0)
730
+ if (standardPrefixes.cashaddr != null) {
731
+ address = _cashAddress.hashToCashAddress.call(void 0,
732
+ scriptHash,
733
+ _cashAddress.CashaddrTypeEnum.scripthash,
734
+ standardPrefixes.cashaddr
735
+ )
736
+ }
737
+ }
738
+
699
739
  return {
700
- scriptPubkey: p2sh.output.toString('hex'),
701
- redeemScript: p2sh.redeem.output.toString('hex'),
702
- address: p2sh.address
740
+ scriptPubkey: scriptPubkeyFromLib,
741
+ redeemScript: redeemScript,
742
+ address
703
743
  }
704
744
  } exports.scriptPubkeyToP2SH = scriptPubkeyToP2SH;
705
745
 
@@ -731,6 +771,14 @@ const addressToScriptPubkeyInternal = (
731
771
  throw new Error('failed converting pubkey to script pubkey')
732
772
  }
733
773
  return { scriptPubkey: payment.output.toString('hex') }
774
+ case ScriptTypeEnum.replayProtection: {
775
+ if (args.scriptTemplates == null)
776
+ throw new Error('Missing replayProtection script template')
777
+ const redeemScript = args.scriptTemplates.replayProtection(args.pubkey)
778
+ return scriptPubkeyToP2SH({
779
+ scriptPubkey: redeemScript
780
+ })
781
+ }
734
782
  default:
735
783
  throw new Error('invalid address type in pubkey to script pubkey')
736
784
  }
@@ -761,9 +809,9 @@ const xprivToPrivateKeyInternal = (
761
809
  const bip32FromBase58Func = _nullishCoalesce(coin.bip32FromBase58Func, () => ( bip32.fromBase58))
762
810
  const node = bip32FromBase58Func(args.xpriv, network)
763
811
  return _optionalChain([node
764
- , 'access', _3 => _3.derive, 'call', _4 => _4(args.bip44ChangeIndex)
765
- , 'access', _5 => _5.derive, 'call', _6 => _6(args.bip44AddressIndex)
766
- , 'access', _7 => _7.privateKey, 'optionalAccess', _8 => _8.toString, 'call', _9 => _9('hex')])
812
+ , 'access', _11 => _11.derive, 'call', _12 => _12(args.bip44ChangeIndex)
813
+ , 'access', _13 => _13.derive, 'call', _14 => _14(args.bip44AddressIndex)
814
+ , 'access', _15 => _15.privateKey, 'optionalAccess', _16 => _16.toString, 'call', _17 => _17('hex')])
767
815
  }
768
816
 
769
817
  const xprivToPrivateKey = (args) => {
@@ -992,7 +1040,7 @@ const wifToPrivateKeyEncodingInternal = (
992
1040
  psbt.addInputs(sortedInputs)
993
1041
  psbt.addOutputs(sortedOutputs)
994
1042
  } catch (error) {
995
- _optionalChain([log, 'optionalAccess', _10 => _10.error, 'call', _11 => _11(`Failed makeTx: ${String(error)}`)])
1043
+ _optionalChain([log, 'optionalAccess', _18 => _18.error, 'call', _19 => _19(`Failed makeTx: ${String(error)}`)])
996
1044
  throw error
997
1045
  }
998
1046
 
@@ -1002,7 +1050,7 @@ const wifToPrivateKeyEncodingInternal = (
1002
1050
  changeUsed: result.changeUsed,
1003
1051
  fee: result.fee,
1004
1052
  psbtBase64: psbt.toBase64(),
1005
- hex: _optionalChain([psbt, 'access', _12 => _12.data, 'optionalAccess', _13 => _13.globalMap, 'optionalAccess', _14 => _14.unsignedTx, 'optionalAccess', _15 => _15.toBuffer, 'call', _16 => _16(), 'optionalAccess', _17 => _17.toString, 'call', _18 => _18('hex')])
1053
+ hex: _optionalChain([psbt, 'access', _20 => _20.data, 'optionalAccess', _21 => _21.globalMap, 'optionalAccess', _22 => _22.unsignedTx, 'optionalAccess', _23 => _23.toBuffer, 'call', _24 => _24(), 'optionalAccess', _25 => _25.toString, 'call', _26 => _26('hex')])
1006
1054
  }
1007
1055
  } exports.makeTx = makeTx;
1008
1056
 
@@ -1126,6 +1174,8 @@ const bip43PurposeTypeEnumToNumber = (
1126
1174
  return 49
1127
1175
  case BIP43PurposeTypeEnum.Segwit:
1128
1176
  return 84
1177
+ case BIP43PurposeTypeEnum.ReplayProtection:
1178
+ return 44 // Only bip44 formatted wallets contain this purpose type (BCH)
1129
1179
  }
1130
1180
  }
1131
1181
 
@@ -1256,10 +1306,16 @@ const scriptHashToScriptPubkey = (
1256
1306
  default:
1257
1307
  throw new Error('invalid address type in address to script pubkey')
1258
1308
  }
1259
- const scriptPubkey = payment({
1260
- hash: Buffer.from(args.scriptHash, 'hex'),
1261
- network: network
1262
- }).output
1309
+ let scriptPubkey
1310
+ try {
1311
+ scriptPubkey = payment({
1312
+ hash: Buffer.from(args.scriptHash, 'hex'),
1313
+ network: network
1314
+ }).output
1315
+ } catch (error) {
1316
+ console.trace(error)
1317
+ throw error
1318
+ }
1263
1319
  if (scriptPubkey == null) {
1264
1320
  throw new Error('failed converting scriptPubkey to address')
1265
1321
  }
@@ -5,6 +5,7 @@ import { Processor } from '../makeProcessor';
5
5
  import { IProcessorTransaction } from '../types';
6
6
  export declare const fromEdgeTransaction: (tx: EdgeTransaction) => IProcessorTransaction;
7
7
  interface ToEdgeTransactionArgs {
8
+ walletId: string;
8
9
  tx: IProcessorTransaction;
9
10
  walletTools: UTXOPluginWalletTools;
10
11
  processor: Processor;
@@ -5,6 +5,7 @@ import { ChangePath, CurrencyFormat, EngineConfig, PluginInfo } from '../../plug
5
5
  import { Processor } from '../db/makeProcessor';
6
6
  import { IAddress, IProcessorTransaction, IUTXO } from '../db/types';
7
7
  import { NumbWalletInfo } from '../keymanager/cleaners';
8
+ import { BlockbookAccountUtxo } from '../network/BlockBookAPI';
8
9
  import { WsTask } from '../network/Socket';
9
10
  import AwaitLock from './await-lock';
10
11
  import { ServerStates } from './makeServerStates';
@@ -14,7 +15,10 @@ export interface UtxoEngineState {
14
15
  start: () => Promise<void>;
15
16
  stop: () => Promise<void>;
16
17
  deriveScriptAddress: (script: string) => Promise<EdgeFreshAddress>;
17
- getFreshAddress: (branch?: number) => Promise<EdgeFreshAddress>;
18
+ getFreshAddress: (params: {
19
+ branch?: number;
20
+ forceIndex?: number;
21
+ }) => Promise<EdgeFreshAddress>;
18
22
  addGapLimitAddresses: (addresses: string[]) => Promise<void>;
19
23
  broadcastTx: (transaction: EdgeTransaction) => Promise<string>;
20
24
  refillServers: () => void;
@@ -86,6 +90,7 @@ interface ProcessorUtxoCache {
86
90
  }
87
91
  interface RawUtxoCache {
88
92
  [key: string]: {
93
+ blockbookUtxo: BlockbookAccountUtxo;
89
94
  processing: boolean;
90
95
  path: ChangePath;
91
96
  address: IAddress;
@@ -101,6 +106,7 @@ interface AddressTransactionCache {
101
106
  };
102
107
  }
103
108
  interface TransactionChangedArgs {
109
+ walletId: string;
104
110
  tx: IProcessorTransaction;
105
111
  emitter: EngineEmitter;
106
112
  walletTools: UTXOPluginWalletTools;
@@ -1,11 +1,11 @@
1
- import { AddressPath, CurrencyFormat } from '../../plugin/types';
1
+ import { AddressPath, ChangePath, CurrencyFormat, PluginInfo } from '../../plugin/types';
2
2
  import { ScriptTemplate } from '../info/scriptTemplates/types';
3
3
  import { PublicKey } from '../keymanager/cleaners';
4
4
  import { PrivateKeyEncoding } from '../keymanager/keymanager';
5
5
  import { CurrencyFormatKeys } from './utils';
6
6
  export interface WalletToolsConfig {
7
+ pluginInfo: PluginInfo;
7
8
  publicKey: PublicKey;
8
- coin: string;
9
9
  }
10
10
  export interface UTXOPluginWalletTools {
11
11
  getPubkey: (args: AddressPath) => string;
@@ -24,8 +24,8 @@ interface ScriptPubkeyReturn {
24
24
  redeemScript?: string;
25
25
  }
26
26
  interface ScriptPubkeyToAddressArgs {
27
+ changePath: ChangePath;
27
28
  scriptPubkey: string;
28
- format: CurrencyFormat;
29
29
  }
30
30
  interface GetPrivateKeyArgs {
31
31
  path: AddressPath;
@@ -1,6 +1,6 @@
1
1
  import { Disklet } from 'disklet';
2
2
  import { EdgeMemoRules, EdgeParsedUri } from 'edge-core-js/types';
3
- import { CurrencyFormat } from '../../plugin/types';
3
+ import { ChangePath, CurrencyFormat, EngineInfo } from '../../plugin/types';
4
4
  import { IUTXO } from '../db/types';
5
5
  import { ScriptTemplates } from '../info/scriptTemplates/types';
6
6
  import { PrivateKey } from '../keymanager/cleaners';
@@ -9,12 +9,32 @@ export declare const getCurrencyFormatFromPurposeType: (purpose: BIP43PurposeTyp
9
9
  export declare const validateMemo: (memo: string) => EdgeMemoRules;
10
10
  export declare const getAddressTypeFromKeys: (privateKey: PrivateKey) => AddressTypeEnum;
11
11
  export declare const getAddressTypeFromPurposeType: (purpose: BIP43PurposeTypeEnum) => AddressTypeEnum;
12
- export declare const getScriptTypeFromPurposeType: (purpose: BIP43PurposeTypeEnum, redeemScript?: string | undefined, scriptTemplates?: ScriptTemplates | undefined) => ScriptTypeEnum;
12
+ export declare const getScriptTypeFromPurposeType: (purpose: BIP43PurposeTypeEnum) => ScriptTypeEnum;
13
13
  export declare const validScriptPubkeyFromAddress: (args: {
14
14
  address: string;
15
15
  coin: string;
16
16
  }) => string;
17
- export declare const getFormatSupportedBranches: (format: CurrencyFormat) => number[];
17
+ export declare const getFormatSupportedBranches: (engineInfo: EngineInfo, format: CurrencyFormat) => number[];
18
+ /**
19
+ * The reason for this function is to consider the address path for
20
+ * determining the purpose-type for the address. This is because some parts
21
+ * of the address such as the changeIndex have special meaning for the
22
+ * purpose-type. Specifically for scriptTemplates, the hash of the template
23
+ * is used to deterministically identify the changeIndex used constantly for
24
+ * the addresses spending to those scriptTemplates.
25
+ *
26
+ * In the future, we will want to strictly use only the format of the path
27
+ * in order to determine the purpose-type per the BIP43 spec. This will require
28
+ * a significant lift to reconsider the type for the path's format (currently
29
+ * CurrencyFormat). The scriptTemplates could define a format index and this
30
+ * could be used in address paths instead of a CurrencyType.
31
+ */
32
+ export declare const pathToPurposeType: (path: ChangePath, scriptTemplates?: ScriptTemplates | undefined) => BIP43PurposeTypeEnum;
33
+ /**
34
+ * Only use this function when needing to infer the purpose-type for a wallet
35
+ * format (CurrencyFormat). To get the purpose-type for an address use
36
+ * pathToPurposeType passing the address path.
37
+ */
18
38
  export declare const currencyFormatToPurposeType: (format: CurrencyFormat) => BIP43PurposeTypeEnum;
19
39
  export declare type CurrencyFormatKeys = {
20
40
  [format in CurrencyFormat]?: string;
@@ -1,13 +1,14 @@
1
1
  import { EdgeLog } from 'edge-core-js/types';
2
- import { AddressPath } from '../../plugin/types';
2
+ import { ChangePath } from '../../plugin/types';
3
3
  import { IUTXO } from '../db/types';
4
- import { ScriptTemplate } from '../info/scriptTemplates/types';
4
+ import { ScriptTemplate, ScriptTemplates } from '../info/scriptTemplates/types';
5
5
  import * as utxopicker from './utxopicker';
6
6
  export declare enum BIP43PurposeTypeEnum {
7
7
  Airbitz = "airbitz",
8
8
  Legacy = "legacy",
9
9
  Segwit = "segwit",
10
- WrappedSegwit = "wrappedSegwit"
10
+ WrappedSegwit = "wrappedSegwit",
11
+ ReplayProtection = "replayProtection"
11
12
  }
12
13
  export declare enum AddressTypeEnum {
13
14
  p2pkh = "p2pkh",
@@ -71,6 +72,7 @@ export interface AddressToScriptPubkeyArgs {
71
72
  }
72
73
  export interface PubkeyToScriptPubkeyArgs {
73
74
  pubkey: string;
75
+ scriptTemplates?: ScriptTemplates;
74
76
  scriptType: ScriptTypeEnum;
75
77
  }
76
78
  export interface PubkeyToScriptPubkeyReturn {
@@ -189,7 +191,7 @@ export declare const getAddressTypeFromAddress: (address: string, coinName: stri
189
191
  export declare function seedOrMnemonicToXPriv(args: SeedOrMnemonicToXPrivArgs): string;
190
192
  export declare const xprivToXPub: (args: XPrivToXPubArgs) => string;
191
193
  export declare function derivationLevelScriptHash(scriptTemplate: ScriptTemplate): number;
192
- export declare const isPathUsingDerivationLevelScriptHash: (scriptTemplate: ScriptTemplate, path: AddressPath) => boolean;
194
+ export declare const isPathUsingDerivationLevelScriptHash: (scriptTemplate: ScriptTemplate, path: ChangePath) => boolean;
193
195
  export declare const xpubToPubkey: (args: XPubToPubkeyArgs) => string;
194
196
  export declare const addressToScriptPubkey: (args: AddressToScriptPubkeyArgs) => string;
195
197
  export declare function scriptPubkeyToAddress(args: ScriptPubkeyToAddressArgs): ScriptPubkeyToAddressReturn;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edge-currency-plugins",
3
- "version": "1.2.3",
3
+ "version": "1.3.1",
4
4
  "description": "Edge currency plugins to fetch and process wallet accounts, balances and transactions.",
5
5
  "repository": "https://github.com/EdgeApp/edge-currency-plugins",
6
6
  "license": "MIT",
@@ -48,7 +48,7 @@
48
48
  "bs58smartcheck": "^2.0.4",
49
49
  "cleaners": "^0.3.12",
50
50
  "disklet": "^0.4.5",
51
- "edge-core-js": "^0.19.20",
51
+ "edge-core-js": "^0.19.33",
52
52
  "edge-sync-client": "^0.2.7",
53
53
  "memlet": "^0.1.6",
54
54
  "uri-js": "^4.4.0",