@exodus/bitcoin-api 2.3.3 → 2.3.5
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/package.json +4 -2
- package/src/tx-send/index.js +50 -5
- package/src/tx-sign/default-create-tx.js +21 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/bitcoin-api",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.5",
|
|
4
4
|
"description": "Exodus bitcoin-api",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@exodus/asset-lib": "^3.7.2",
|
|
22
|
+
"@exodus/basic-utils": "^2.0.1",
|
|
22
23
|
"@exodus/bip44-constants": "^195.0.0",
|
|
23
24
|
"@exodus/bitcoinjs-lib": "6.0.2-beta.5",
|
|
24
25
|
"@exodus/models": "^8.10.4",
|
|
@@ -35,10 +36,11 @@
|
|
|
35
36
|
"url-join": "4.0.0"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
39
|
+
"@exodus/asset-lib": "^3.7.1",
|
|
38
40
|
"@exodus/bcash-meta": "^1.0.0",
|
|
39
41
|
"@exodus/bip-schnorr": "0.6.6-fork-1",
|
|
40
42
|
"@exodus/bitcoin-meta": "^1.0.1",
|
|
41
43
|
"@noble/secp256k1": "~1.5.3"
|
|
42
44
|
},
|
|
43
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "3dd9a1846d6f34252c12e966e1ee1f851cca4173"
|
|
44
46
|
}
|
package/src/tx-send/index.js
CHANGED
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
import { findUnconfirmedSentRbfTxs } from '../tx-utils'
|
|
17
17
|
import { getUsableUtxos, getUtxos } from '../utxos-utils'
|
|
18
18
|
|
|
19
|
+
import * as defaultBitcoinjsLib from '@exodus/bitcoinjs-lib'
|
|
20
|
+
|
|
19
21
|
const ASSETS_SUPPORTED_BIP_174 = [
|
|
20
22
|
'bitcoin',
|
|
21
23
|
'bitcoinregtest',
|
|
@@ -79,12 +81,55 @@ export async function getNonWitnessTxs(asset, utxos, insightClient) {
|
|
|
79
81
|
return rawTxs
|
|
80
82
|
}
|
|
81
83
|
|
|
84
|
+
export const getSizeAndChangeScriptFactory = ({ bitcoinJsLib = defaultBitcoinjsLib } = {}) => ({
|
|
85
|
+
assetName,
|
|
86
|
+
tx,
|
|
87
|
+
rawTx,
|
|
88
|
+
changeUtxoIndex,
|
|
89
|
+
txId,
|
|
90
|
+
}) => {
|
|
91
|
+
assert(assetName, 'assetName is required')
|
|
92
|
+
assert(rawTx, 'rawTx is required')
|
|
93
|
+
assert(typeof changeUtxoIndex === 'number', 'changeUtxoIndex must be a number')
|
|
94
|
+
|
|
95
|
+
const getSize = (tx) => {
|
|
96
|
+
if (typeof tx.size === 'number') return tx.size
|
|
97
|
+
if (typeof tx.virtualSize === 'function') {
|
|
98
|
+
return tx.virtualSize()
|
|
99
|
+
}
|
|
100
|
+
if (typeof tx.virtualSize === 'number') {
|
|
101
|
+
return tx.virtualSize
|
|
102
|
+
}
|
|
103
|
+
return undefined
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (tx) {
|
|
107
|
+
return {
|
|
108
|
+
script: tx.outs?.[changeUtxoIndex]?.script.toString('hex'),
|
|
109
|
+
size: getSize(tx),
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Trezor doesn't return tx!! we need to reparse it!
|
|
113
|
+
const parsedTx = bitcoinJsLib.Transaction.fromBuffer(Buffer.from(rawTx, 'hex'))
|
|
114
|
+
try {
|
|
115
|
+
return {
|
|
116
|
+
script: parsedTx.outs?.[changeUtxoIndex]?.script.toString('hex'),
|
|
117
|
+
size: getSize(parsedTx),
|
|
118
|
+
}
|
|
119
|
+
} catch (e) {
|
|
120
|
+
console.warn(
|
|
121
|
+
`tx-send warning: ${assetName} cannot extract script and size from tx ${txId}. ${e}`
|
|
122
|
+
)
|
|
123
|
+
return {}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
82
127
|
// not ported from Exodus; but this demos signing / broadcasting
|
|
83
128
|
// NOTE: this will be ripped out in the coming weeks
|
|
84
129
|
|
|
85
130
|
export const createAndBroadcastTXFactory = ({
|
|
86
131
|
getFeeEstimator,
|
|
87
|
-
|
|
132
|
+
getSizeAndChangeScript = getSizeAndChangeScriptFactory(), // for decred customizations
|
|
88
133
|
allowUnconfirmedRbfEnabledUtxos,
|
|
89
134
|
}) => async ({ asset, walletAccount, address, amount, options }, { assetClientInterface }) => {
|
|
90
135
|
const {
|
|
@@ -308,6 +353,8 @@ export const createAndBroadcastTXFactory = ({
|
|
|
308
353
|
}
|
|
309
354
|
}
|
|
310
355
|
|
|
356
|
+
const { script, size } = getSizeAndChangeScript({ assetName, tx, rawTx, changeUtxoIndex, txId })
|
|
357
|
+
|
|
311
358
|
let remainingUtxos = usableUtxos.difference(selectedUtxos)
|
|
312
359
|
if (changeUtxoIndex !== -1) {
|
|
313
360
|
const address = Address.create(ourAddress.address, ourAddress.meta)
|
|
@@ -315,7 +362,7 @@ export const createAndBroadcastTXFactory = ({
|
|
|
315
362
|
txId,
|
|
316
363
|
address,
|
|
317
364
|
vout: changeUtxoIndex,
|
|
318
|
-
script
|
|
365
|
+
script,
|
|
319
366
|
value: change,
|
|
320
367
|
confirmations: 0,
|
|
321
368
|
rbfEnabled,
|
|
@@ -364,9 +411,7 @@ export const createAndBroadcastTXFactory = ({
|
|
|
364
411
|
data: {
|
|
365
412
|
sent: selfSend ? [] : receivers,
|
|
366
413
|
rbfEnabled,
|
|
367
|
-
feePerKB:
|
|
368
|
-
? fee.div(tx.virtualSize / 1000).toBaseNumber()
|
|
369
|
-
: undefined,
|
|
414
|
+
feePerKB: size ? fee.div(size / 1000).toBaseNumber() : undefined,
|
|
370
415
|
changeAddress: changeOutput ? ourAddress : undefined,
|
|
371
416
|
blockHeight,
|
|
372
417
|
blocksSeen: 0,
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import assert from 'minimalistic-assert'
|
|
2
2
|
import lodash from 'lodash'
|
|
3
3
|
import ECPairFactory from 'ecpair'
|
|
4
|
-
import { Psbt, Transaction } from '@exodus/bitcoinjs-lib'
|
|
4
|
+
import { payments, Psbt, Transaction } from '@exodus/bitcoinjs-lib'
|
|
5
|
+
import { getOwnProperty } from '@exodus/basic-utils'
|
|
6
|
+
|
|
7
|
+
import secp256k1 from 'secp256k1'
|
|
5
8
|
|
|
6
9
|
import { toAsyncSigner, tweakSigner } from './taproot'
|
|
7
10
|
|
|
@@ -45,10 +48,11 @@ export const signTxFactory = ({ assetName, resolvePurpose, keys, coinInfo, netwo
|
|
|
45
48
|
ECPair = ECPair || ECPairFactory(ecc)
|
|
46
49
|
|
|
47
50
|
const getKeyAndPurpose = lodash.memoize((address) => {
|
|
48
|
-
// TODO: Consider using privateKeysAddressMap for other assets
|
|
49
51
|
const purpose = resolvePurpose(address)
|
|
50
52
|
if (privateKeysAddressMap) {
|
|
51
|
-
const
|
|
53
|
+
const privateKey = getOwnProperty(privateKeysAddressMap, address, 'string')
|
|
54
|
+
assert(privateKey, `there is no private key for address ${address}`)
|
|
55
|
+
const key = ECPair.fromWIF(privateKey, networkInfo)
|
|
52
56
|
return { key, purpose }
|
|
53
57
|
}
|
|
54
58
|
const path = addressPathsMap[address]
|
|
@@ -96,6 +100,20 @@ export const signTxFactory = ({ assetName, resolvePurpose, keys, coinInfo, netwo
|
|
|
96
100
|
for (let index = 0; index < inputs.length; index++) {
|
|
97
101
|
const { address } = inputs[index]
|
|
98
102
|
const { key, purpose } = getKeyAndPurpose(address)
|
|
103
|
+
|
|
104
|
+
if (purpose === 49) {
|
|
105
|
+
// If spending from a P2SH address, we assume the address is P2SH wrapping
|
|
106
|
+
// P2WPKH. Exodus doesn't use P2SH addresses so we should only ever be
|
|
107
|
+
// signing a P2SH input if we are importing a private key
|
|
108
|
+
// BIP143: As a default policy, only compressed public keys are accepted in P2WPKH and P2WSH
|
|
109
|
+
const publicKey = secp256k1.publicKeyCreate(key.privateKey, true)
|
|
110
|
+
const p2wpkh = payments.p2wpkh({ pubkey: publicKey })
|
|
111
|
+
const p2sh = payments.p2sh({ redeem: p2wpkh })
|
|
112
|
+
psbt.updateInput(index, {
|
|
113
|
+
redeemScript: p2sh.redeem.output,
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
|
|
99
117
|
if (ecc.signSchnorrAsync) {
|
|
100
118
|
// desktop / BE / mobile with bip-schnorr signing
|
|
101
119
|
const isTaprootAddress = purpose === 86
|