@exodus/bitcoin-api 2.29.0 → 2.29.2
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.
- package/CHANGELOG.md +15 -0
- package/package.json +3 -3
- package/src/fee/fee-estimator.js +50 -41
- package/src/fee/index.js +8 -1
- package/src/tx-log/bitcoin-monitor-scanner.js +1 -0
- package/src/tx-send/dogecoin.js +1 -0
- package/src/tx-send/index.js +1 -0
- package/src/tx-sign/create-get-key-and-purpose.js +18 -11
- package/src/tx-sign/create-sign-with-wallet.js +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [2.29.2](https://github.com/ExodusMovement/assets/compare/@exodus/bitcoin-api@2.29.1...@exodus/bitcoin-api@2.29.2) (2024-11-19)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
* fix: bitcoin use utxo.derivationPath path to resolve purpose (#4541)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## [2.29.1](https://github.com/ExodusMovement/assets/compare/@exodus/bitcoin-api@2.29.0...@exodus/bitcoin-api@2.29.1) (2024-11-13)
|
|
17
|
+
|
|
18
|
+
**Note:** Update exports in fee module of package @exodus/bitcoin-api
|
|
19
|
+
|
|
20
|
+
|
|
6
21
|
## [2.29.0](https://github.com/ExodusMovement/assets/compare/@exodus/bitcoin-api@2.28.0...@exodus/bitcoin-api@2.29.0) (2024-11-10)
|
|
7
22
|
|
|
8
23
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/bitcoin-api",
|
|
3
|
-
"version": "2.29.
|
|
3
|
+
"version": "2.29.2",
|
|
4
4
|
"description": "Exodus bitcoin-api",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@exodus/bitcoin-lib": "^2.4.2",
|
|
29
29
|
"@exodus/bitcoinjs": "^1.1.0",
|
|
30
30
|
"@exodus/crypto": "^1.0.0-rc.13",
|
|
31
|
-
"@exodus/currency": "^
|
|
31
|
+
"@exodus/currency": "^6.0.1",
|
|
32
32
|
"@exodus/key-identifier": "^1.3.0",
|
|
33
33
|
"@exodus/models": "^12.0.1",
|
|
34
34
|
"@exodus/simple-retry": "^0.0.6",
|
|
@@ -56,5 +56,5 @@
|
|
|
56
56
|
"type": "git",
|
|
57
57
|
"url": "git+https://github.com/ExodusMovement/assets.git"
|
|
58
58
|
},
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "ebe9c86c8ecb6e6810613402e27ee62e8c308753"
|
|
60
60
|
}
|
package/src/fee/fee-estimator.js
CHANGED
|
@@ -79,49 +79,17 @@ export const getSizeFactory = ({ defaultOutputType, addressApi }) => {
|
|
|
79
79
|
4 + // n_locktime
|
|
80
80
|
varuint.encodingLength(inputs.length) + // inputs_len
|
|
81
81
|
// input[]
|
|
82
|
-
inputs.reduce(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const scriptType = scriptClassifier.classifyScriptHex({ assetName, script })
|
|
87
|
-
|
|
88
|
-
const supportedTypes = supportedInputTypes[assetName] || supportedInputTypes.default
|
|
89
|
-
assert(
|
|
90
|
-
supportedTypes.includes(scriptType),
|
|
91
|
-
`Only ${supportedTypes.join(', ')} inputs supported right now`
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
const scriptSigLengths = compressed
|
|
95
|
-
? scriptSigCompressedLengths
|
|
96
|
-
: scriptSigUncompressedLengths
|
|
97
|
-
const scriptSigLength = scriptSigLengths[scriptType]
|
|
98
|
-
return t + 32 + 4 + varuint.encodingLength(scriptSigLength) + scriptSigLength + 4
|
|
99
|
-
}, 0) +
|
|
82
|
+
inputs.reduce(
|
|
83
|
+
(t, script) => t + getInputSize({ script, scriptClassifier, assetName, compressed }),
|
|
84
|
+
0
|
|
85
|
+
) +
|
|
100
86
|
varuint.encodingLength(outputs.length) + // outputs_len
|
|
101
87
|
// output[]
|
|
102
|
-
outputs.reduce(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
let scriptType = scriptClassify.types[output]
|
|
108
|
-
const supportedTypes = supportedOutputTypes[assetName] || supportedOutputTypes.default
|
|
109
|
-
|
|
110
|
-
if (!supportedTypes.includes(scriptType)) {
|
|
111
|
-
scriptType = scriptClassifier.classifyAddress({
|
|
112
|
-
assetName,
|
|
113
|
-
address: output,
|
|
114
|
-
})
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
assert(
|
|
118
|
-
supportedTypes.includes(scriptType),
|
|
119
|
-
`Only ${supportedTypes.join(', ')} outputs supported right now`
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
const scriptPubKeyLength = scriptPubKeyLengths[scriptType]
|
|
123
|
-
return t + 8 + varuint.encodingLength(scriptPubKeyLength) + scriptPubKeyLength
|
|
124
|
-
}, 0)
|
|
88
|
+
outputs.reduce(
|
|
89
|
+
(t, output) =>
|
|
90
|
+
t + getOutputSize({ output, scriptClassifier, assetName, defaultOutputType }),
|
|
91
|
+
0
|
|
92
|
+
)
|
|
125
93
|
|
|
126
94
|
const witnessSize =
|
|
127
95
|
1 + // marker
|
|
@@ -169,4 +137,45 @@ const getFeeEstimatorFactory = ({ defaultOutputType, addressApi }) => {
|
|
|
169
137
|
return createDefaultFeeEstimator(getSize)
|
|
170
138
|
}
|
|
171
139
|
|
|
140
|
+
export const getInputSize = ({ script, scriptClassifier, assetName, compressed }) => {
|
|
141
|
+
if (script === null) script = '76a914000000000000000000000000000000000000000088ac' // P2PKH
|
|
142
|
+
assert(isHex(script), 'script must be hex string')
|
|
143
|
+
|
|
144
|
+
const scriptType = scriptClassifier.classifyScriptHex({ assetName, script })
|
|
145
|
+
|
|
146
|
+
const supportedTypes = supportedInputTypes[assetName] || supportedInputTypes.default
|
|
147
|
+
assert(
|
|
148
|
+
supportedTypes.includes(scriptType),
|
|
149
|
+
`Only ${supportedTypes.join(', ')} inputs supported right now`
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
const scriptSigLengths = compressed ? scriptSigCompressedLengths : scriptSigUncompressedLengths
|
|
153
|
+
const scriptSigLength = scriptSigLengths[scriptType]
|
|
154
|
+
return 32 + 4 + varuint.encodingLength(scriptSigLength) + scriptSigLength + 4
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export const getOutputSize = ({ output, scriptClassifier, assetName, defaultOutputType }) => {
|
|
158
|
+
// if (output === null) output = get(asset, 'address.versions.bech32') ? 'P2WSH' : 'P2PKH'
|
|
159
|
+
|
|
160
|
+
if (output === null) output = defaultOutputType
|
|
161
|
+
|
|
162
|
+
let scriptType = scriptClassify.types[output]
|
|
163
|
+
const supportedTypes = supportedOutputTypes[assetName] || supportedOutputTypes.default
|
|
164
|
+
|
|
165
|
+
if (!supportedTypes.includes(scriptType)) {
|
|
166
|
+
scriptType = scriptClassifier.classifyAddress({
|
|
167
|
+
assetName,
|
|
168
|
+
address: output,
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
assert(
|
|
173
|
+
supportedTypes.includes(scriptType),
|
|
174
|
+
`Only ${supportedTypes.join(', ')} outputs supported right now`
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
const scriptPubKeyLength = scriptPubKeyLengths[scriptType]
|
|
178
|
+
return 8 + varuint.encodingLength(scriptPubKeyLength) + scriptPubKeyLength
|
|
179
|
+
}
|
|
180
|
+
|
|
172
181
|
export default getFeeEstimatorFactory
|
package/src/fee/index.js
CHANGED
|
@@ -1,2 +1,9 @@
|
|
|
1
1
|
export * from './get-fee-resolver.js'
|
|
2
|
-
export {
|
|
2
|
+
export {
|
|
3
|
+
default as getFeeEstimatorFactory,
|
|
4
|
+
getInputSize,
|
|
5
|
+
getOutputSize,
|
|
6
|
+
getSizeFactory,
|
|
7
|
+
} from './fee-estimator.js'
|
|
8
|
+
export { default as createDefaultFeeEstimator } from './fee-utils.js'
|
|
9
|
+
export { scriptClassifierFactory } from './script-classifier.js'
|
|
@@ -545,6 +545,7 @@ export class BitcoinMonitorScanner {
|
|
|
545
545
|
script: vout.scriptPubKey.hex,
|
|
546
546
|
value: val,
|
|
547
547
|
rbfEnabled: txItem.rbf,
|
|
548
|
+
derivationPath: address.meta.keyIdentifier?.derivationPath,
|
|
548
549
|
...(txItem.vin.length === 0 ? { isCoinbase: true } : undefined),
|
|
549
550
|
}
|
|
550
551
|
|
package/src/tx-send/dogecoin.js
CHANGED
package/src/tx-send/index.js
CHANGED
|
@@ -14,20 +14,27 @@ export const createGetKeyWithMetadata = ({
|
|
|
14
14
|
coinInfo,
|
|
15
15
|
getKeyIdentifier,
|
|
16
16
|
}) =>
|
|
17
|
-
memoize(
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
memoize(
|
|
18
|
+
({ address, derivationPath }) => {
|
|
19
|
+
const purpose = derivationPath
|
|
20
|
+
? parseInt(derivationPath.split('/')[1].replace(/'/g, ''))
|
|
21
|
+
: resolvePurpose(address)
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
23
|
+
assert(typeof purpose === 'number' && purpose, 'purpose must be a number')
|
|
24
|
+
const networkInfo = coinInfo.toBitcoinJS()
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
if (signer) {
|
|
27
|
+
return getPublicKeyFromSigner(signer, addressPathsMap, purpose, address, getKeyIdentifier)
|
|
28
|
+
}
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
if (privateKeysAddressMap) {
|
|
31
|
+
return getPrivateKeyFromMap(privateKeysAddressMap, networkInfo, purpose, address)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return getPrivateKeyFromHDKeys(hdkeys, addressPathsMap, networkInfo, purpose, address)
|
|
35
|
+
},
|
|
36
|
+
({ address, derivationPath }) => address + '_' + derivationPath
|
|
37
|
+
)
|
|
31
38
|
|
|
32
39
|
function getPrivateKeyFromMap(privateKeysAddressMap, networkInfo, purpose, address) {
|
|
33
40
|
const privateWif = getOwnProperty(privateKeysAddressMap, address, 'string')
|
|
@@ -34,14 +34,17 @@ export function createSignWithWallet({
|
|
|
34
34
|
if (!inputInfo) continue
|
|
35
35
|
|
|
36
36
|
const input = psbt.data.inputs[index]
|
|
37
|
-
const { address, sigHash } = inputInfo
|
|
37
|
+
const { address, sigHash, derivationPath } = inputInfo
|
|
38
38
|
// The sighash value from the PSBT input itself will be used.
|
|
39
39
|
// This list just represents possible sighash values the inputs can have.
|
|
40
40
|
const allowedSigHashTypes =
|
|
41
41
|
sigHash === undefined
|
|
42
42
|
? undefined // `SIGHASH_DEFAULT` is a default safe sig hash, always allow it.
|
|
43
43
|
: [sigHash, Transaction.SIGHASH_ALL]
|
|
44
|
-
const { keyId, privateKey, publicKey, purpose } = await getKeyWithMetadata(
|
|
44
|
+
const { keyId, privateKey, publicKey, purpose } = await getKeyWithMetadata({
|
|
45
|
+
address,
|
|
46
|
+
derivationPath,
|
|
47
|
+
})
|
|
45
48
|
|
|
46
49
|
const isTaprootInput = bip371.isTaprootInput(input)
|
|
47
50
|
const isTapLeafScriptSpend = input.tapLeafScript && input.tapLeafScript.length > 0
|