@exodus/bitcoin-api 4.8.0 → 4.8.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 CHANGED
@@ -3,6 +3,26 @@
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
+ ## [4.8.2](https://github.com/ExodusMovement/assets/compare/@exodus/bitcoin-api@4.8.1...@exodus/bitcoin-api@4.8.2) (2025-12-04)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+
12
+ * fix: utxo psbtify fixes (#7029)
13
+
14
+
15
+
16
+ ## [4.8.1](https://github.com/ExodusMovement/assets/compare/@exodus/bitcoin-api@4.8.0...@exodus/bitcoin-api@4.8.1) (2025-12-03)
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+
22
+ * fix: add redeemScript to input via hardware wallet (#7039)
23
+
24
+
25
+
6
26
  ## [4.8.0](https://github.com/ExodusMovement/assets/compare/@exodus/bitcoin-api@4.7.0...@exodus/bitcoin-api@4.8.0) (2025-11-26)
7
27
 
8
28
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/bitcoin-api",
3
- "version": "4.8.0",
3
+ "version": "4.8.2",
4
4
  "description": "Bitcoin transaction and fee monitors, RPC with the blockchain node, other networking code.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -60,5 +60,5 @@
60
60
  "type": "git",
61
61
  "url": "git+https://github.com/ExodusMovement/assets.git"
62
62
  },
63
- "gitHead": "ce3d3ce783034bad54303d6e3d065f6c7324c32c"
63
+ "gitHead": "5440ba73907657281aa3c062168f4fda1f3b6581"
64
64
  }
@@ -3,6 +3,7 @@ import { Address, UtxoCollection } from '@exodus/models'
3
3
  import BipPath from 'bip32-path'
4
4
  import assert from 'minimalistic-assert'
5
5
 
6
+ import { parseCurrency, serializeCurrency } from './fee/fee-utils.js'
6
7
  import { readPsbtGlobalField, readPsbtOutputField, SubType } from './psbt-proprietary-types.js'
7
8
  import { getAddressType, getPurposeXPubs, validatePurpose } from './psbt-utils.js'
8
9
  import { createInputs, createOutput } from './tx-create/tx-create-utils.js'
@@ -278,7 +279,7 @@ function processReplacementTransaction(replaceTx, asset) {
278
279
 
279
280
  updatedTx.data.sent = updatedTx?.data?.sent.map((to) => ({
280
281
  ...to,
281
- amount: asset.currency.baseUnit(to.amount),
282
+ amount: serializeCurrency(to.amount, asset.currency),
282
283
  }))
283
284
 
284
285
  return updatedTx
@@ -295,7 +296,10 @@ function calculateAmounts({ primaryOutputs, changeOutputData, processedReplaceTx
295
296
  : asset.currency.ZERO
296
297
 
297
298
  const totalAmount = processedReplaceTx
298
- ? processedReplaceTx.data.sent.reduce((total, { amount }) => total.add(amount), totalSendAmount)
299
+ ? processedReplaceTx.data.sent.reduce(
300
+ (total, { amount }) => total.add(parseCurrency(amount, asset.currency)),
301
+ totalSendAmount
302
+ )
299
303
  : totalSendAmount
300
304
 
301
305
  return { sendAmounts, totalSendAmount, changeAmount, totalAmount }
@@ -334,6 +338,26 @@ function extractRawTransactions(parsedInputs) {
334
338
  return [...rawTxsMap].map(([txId, rawData]) => ({ txId, rawData }))
335
339
  }
336
340
 
341
+ function orderSelectedUtxos(parsedInputs, selectedUtxos) {
342
+ const selectedUtxoKey = (txId, vout) => `${txId}:${vout}`
343
+ const selectedUtxoMap = new Map(
344
+ selectedUtxos.toArray().map((utxo) => [selectedUtxoKey(utxo.txId, utxo.vout), utxo])
345
+ )
346
+
347
+ const orderedSelectedUtxos = []
348
+ for (const parsedInput of parsedInputs) {
349
+ const key = selectedUtxoKey(parsedInput.txId, parsedInput.vout)
350
+ const utxo = selectedUtxoMap.get(key)
351
+ if (utxo) {
352
+ orderedSelectedUtxos.push(utxo)
353
+ } else {
354
+ throw new Error(`orderSelectedUtxos: missing selected UTXO for ${key}`)
355
+ }
356
+ }
357
+
358
+ return orderedSelectedUtxos
359
+ }
360
+
337
361
  export async function parsePsbt({
338
362
  psbtBuffer,
339
363
  asset,
@@ -605,7 +629,11 @@ export async function extractTransactionContext({
605
629
  unconfirmedTxAncestor,
606
630
  })
607
631
 
608
- const inputs = createInputs(assetName, selectedUtxos.toArray(), globalMetadata.rbfEnabled)
632
+ const inputs = createInputs(
633
+ assetName,
634
+ orderSelectedUtxos(parsedInputs, selectedUtxos),
635
+ globalMetadata.rbfEnabled
636
+ )
609
637
  const outputs = parsedOutputs.map((output) =>
610
638
  createOutput(assetName, output.address.address, asset.currency.baseUnit(output.amount))
611
639
  )
@@ -280,7 +280,8 @@ async function createUnsignedTx({
280
280
  Transaction,
281
281
  }) {
282
282
  const nonWitnessTxs = await getNonWitnessTxs(asset, selectedUtxos, insightClient)
283
-
283
+ const sendOutputIndexes =
284
+ sendOutputIndex === undefined || sendOutputIndex === null ? [] : [sendOutputIndex]
284
285
  const result = {
285
286
  txData: {
286
287
  inputs,
@@ -291,8 +292,7 @@ async function createUnsignedTx({
291
292
  addressPathsMap,
292
293
  blockHeight,
293
294
  rawTxs: nonWitnessTxs,
294
- sendOutputIndexes:
295
- sendOutputIndex === undefined || sendOutputIndex === null ? [] : [sendOutputIndex],
295
+ sendOutputIndexes,
296
296
  changeOutputIndex,
297
297
  outputAddressPurposesMap,
298
298
  rbfEnabled,
@@ -317,7 +317,7 @@ async function createUnsignedTx({
317
317
  metadata: {
318
318
  rbfEnabled,
319
319
  txType,
320
- sendOutputIndexes: [sendOutputIndex],
320
+ sendOutputIndexes,
321
321
  changeOutputIndex,
322
322
  bumpTxId,
323
323
  blockHeight,
@@ -110,14 +110,19 @@ export function applySignatures(psbt, signatures, inputsToSign) {
110
110
  tapKeySig: signature.signature,
111
111
  })
112
112
  } else {
113
- psbt.data.updateInput(inputIndex, {
113
+ const updateData = {
114
114
  partialSig: [
115
115
  {
116
116
  pubkey: signature.publicKey,
117
117
  signature: signature.signature,
118
118
  },
119
119
  ],
120
- })
120
+ }
121
+ if (signature.redeemScript) {
122
+ updateData.redeemScript = signature.redeemScript
123
+ }
124
+
125
+ psbt.data.updateInput(inputIndex, updateData)
121
126
  }
122
127
  } else {
123
128
  throw new Error(
@@ -3,7 +3,7 @@
3
3
  // bitcoinjs default). If an asset is missing, the library fallback (5000 sat/vB)
4
4
  // will apply instead.
5
5
  const MAXIMUM_FEE_RATES = {
6
- dogecoin: 12_000,
6
+ dogecoin: 200_000,
7
7
  qtumignition: 25_000,
8
8
  ravencoin: 1_000_000,
9
9
  }