@exodus/bitcoin-api 2.3.13 → 2.3.15

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 (2) hide show
  1. package/package.json +2 -2
  2. package/src/move-funds.js +45 -26
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/bitcoin-api",
3
- "version": "2.3.13",
3
+ "version": "2.3.15",
4
4
  "description": "Exodus bitcoin-api",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -41,5 +41,5 @@
41
41
  "@exodus/bitcoin-meta": "^1.0.1",
42
42
  "jest-when": "^3.5.1"
43
43
  },
44
- "gitHead": "f21eede554fe7a0b99f2f65121457ece5d18f2b6"
44
+ "gitHead": "90be61265b73fc6f3238604aea72368cf684faa5"
45
45
  }
package/src/move-funds.js CHANGED
@@ -4,26 +4,39 @@ import { createInputs, createOutput, getNonWitnessTxs } from './tx-send'
4
4
  import assert from 'minimalistic-assert'
5
5
  import secp256k1 from 'secp256k1'
6
6
 
7
- function wifToPublicKey({ coinInfo, privateKeyWIF }) {
7
+ const isValidPrivateKey = (privateKey) => {
8
+ try {
9
+ wif.decode(privateKey)
10
+ return true
11
+ } catch (err) {
12
+ return false
13
+ }
14
+ }
15
+
16
+ const wifToPublicKey = ({ coinInfo, privateKeyWIF }) => {
8
17
  assert(coinInfo, 'coinInfo is required')
9
18
  assert(privateKeyWIF, 'privateKeyWIF is required')
10
19
  const { versions } = coinInfo
11
20
 
12
21
  const { privateKey, compressed } = wif.decode(privateKeyWIF, versions.private)
13
- return secp256k1.publicKeyCreate(privateKey, compressed)
22
+ return { compressed, publicKey: secp256k1.publicKeyCreate(privateKey, compressed) }
14
23
  }
15
-
16
24
  export const getAddressesFromPrivateKeyFactory = ({ purposes, keys, coinInfo }) => {
17
25
  assert(purposes, 'purposes is required')
18
26
  assert(keys, 'keys is required')
19
27
  assert(coinInfo, 'coinInfo is required')
28
+
20
29
  return ({ privateKey }) => {
21
- const publicKey = wifToPublicKey({ coinInfo, privateKeyWIF: privateKey })
22
- return purposes.map((purpose) =>
30
+ if (!isValidPrivateKey(privateKey)) {
31
+ return { invalid: true }
32
+ }
33
+ const { publicKey, compressed } = wifToPublicKey({ coinInfo, privateKeyWIF: privateKey })
34
+ const addresses = purposes.map((purpose) =>
23
35
  keys.encodePublic(purpose === 49 ? secp256k1.publicKeyConvert(publicKey, true) : publicKey, {
24
36
  purpose,
25
37
  })
26
38
  )
39
+ return { addresses, compressed }
27
40
  }
28
41
  }
29
42
 
@@ -44,6 +57,7 @@ export const moveFundsFactory = ({
44
57
  signTx,
45
58
  address,
46
59
  getAddressesFromPrivateKey,
60
+ shouldExcludeVoutUtxo = () => false,
47
61
  }) => {
48
62
  assert(asset, 'asset is required')
49
63
  assert(insightClient, 'insightClient is required')
@@ -51,6 +65,7 @@ export const moveFundsFactory = ({
51
65
  assert(address, 'address is required')
52
66
  assert(signTx, 'signTx is required')
53
67
  assert(getAddressesFromPrivateKey, 'getAddressesFromPrivateKey is required')
68
+ assert(typeof shouldExcludeVoutUtxo === 'function', 'shouldExcludeVoutUtxo must be a function')
54
69
 
55
70
  async function prepareSendFundsTx({
56
71
  assetName,
@@ -73,21 +88,31 @@ export const moveFundsFactory = ({
73
88
  // WIF format private key
74
89
  const privateKey = input
75
90
 
76
- if (!isValidPrivateKey(privateKey)) {
91
+ const { addresses, compressed, invalid } = getAddressesFromPrivateKey({
92
+ privateKey,
93
+ formatProps,
94
+ MoveFundsError,
95
+ })
96
+
97
+ if (invalid) {
77
98
  throw new MoveFundsError('private-key-invalid', formatProps)
78
99
  }
79
100
 
80
- const { compressed } = wif.decode(privateKey)
81
- const addresses = getAddressesFromPrivateKey({ privateKey })
82
-
83
- const receiveAddresses = await assetClientInterface.getReceiveAddresses({
84
- walletAccount,
85
- assetName,
86
- multiAddressMode: true,
87
- })
101
+ const receiveAddresses = (
102
+ await assetClientInterface.getReceiveAddresses({
103
+ walletAccount,
104
+ assetName,
105
+ multiAddressMode: true,
106
+ })
107
+ ).map(
108
+ (receiveAddress) =>
109
+ address.toLegacyAddress?.(receiveAddress.toString()) || receiveAddress.toString()
110
+ )
88
111
 
89
112
  const findFromAddress = async () => {
90
- for (const currentAddress of addresses) {
113
+ for (const originalCurrentAddress of addresses) {
114
+ const currentAddress =
115
+ address.toLegacyAddress?.(originalCurrentAddress) || originalCurrentAddress
91
116
  const selfSend = receiveAddresses.some(
92
117
  (receiveAddress) => String(receiveAddress) === String(currentAddress)
93
118
  )
@@ -95,7 +120,8 @@ export const moveFundsFactory = ({
95
120
  throw new MoveFundsError('private-key-own-key', formatProps)
96
121
  }
97
122
 
98
- const utxos = await getUtxos({ asset, address: currentAddress })
123
+ const collectedUtxos = await getUtxos({ asset, address: currentAddress })
124
+ const utxos = collectedUtxos.filter((utxo) => !shouldExcludeVoutUtxo({ output: utxo }))
99
125
 
100
126
  if (!utxos.value.isZero) {
101
127
  return { fromAddress: currentAddress, utxos }
@@ -121,7 +147,9 @@ export const moveFundsFactory = ({
121
147
  const unsignedTx = {
122
148
  txData: {
123
149
  inputs: createInputs(assetName, utxos.toArray()),
124
- outputs: [createOutput(assetName, toAddress, amount)],
150
+ outputs: [
151
+ createOutput(assetName, address.toLegacyAddress?.(toAddress) || toAddress, amount),
152
+ ],
125
153
  },
126
154
  txMeta: {
127
155
  addressPathsMap: utxos.getAddressPathsMap(),
@@ -188,15 +216,6 @@ export const moveFundsFactory = ({
188
216
  return { fee, sizeKB }
189
217
  }
190
218
 
191
- function isValidPrivateKey(privateKey) {
192
- try {
193
- wif.decode(privateKey)
194
- return true
195
- } catch (err) {
196
- return false
197
- }
198
- }
199
-
200
219
  return {
201
220
  prepareSendFundsTx,
202
221
  sendFunds,