@exodus/bitcoin-api 2.9.0 → 2.9.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/bitcoin-api",
3
- "version": "2.9.0",
3
+ "version": "2.9.1",
4
4
  "description": "Exodus bitcoin-api",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -42,5 +42,5 @@
42
42
  "@scure/btc-signer": "^1.1.0",
43
43
  "jest-when": "^3.5.1"
44
44
  },
45
- "gitHead": "ed03529f7a8bb4b39bfd173387f9cdd5d7207925"
45
+ "gitHead": "1f96673b2977e792373f9f3c4eb98c778817b2b6"
46
46
  }
@@ -15,6 +15,7 @@ export function createAccountState({ asset, ordinalsEnabled = false, brc20Enable
15
15
  defaults.ordinalsUtxos = empty
16
16
  defaults.knownBalanceUtxoIds = []
17
17
  defaults.mustAvoidUtxoIds = []
18
+ defaults.additionalInscriptions = []
18
19
  }
19
20
 
20
21
  if (brc20Enabled) {
@@ -603,6 +603,7 @@ export class BitcoinMonitorScanner {
603
603
  ordinalAddress,
604
604
  knownBalanceUtxoIds: latestAccountState.knownBalanceUtxoIds,
605
605
  mustAvoidUtxoIds: latestAccountState.mustAvoidUtxoIds,
606
+ additionalInscriptions: latestAccountState.additionalInscriptions,
606
607
  })
607
608
  : {}
608
609
 
@@ -674,6 +675,7 @@ export class BitcoinMonitorScanner {
674
675
  ordinalAddress: ordinalAddress,
675
676
  knownBalanceUtxoIds: latestAccountState.knownBalanceUtxoIds,
676
677
  mustAvoidUtxoIds: latestAccountState.mustAvoidUtxoIds,
678
+ additionalInscriptions: latestAccountState.additionalInscriptions,
677
679
  })
678
680
 
679
681
  return {
@@ -168,13 +168,10 @@ export class Monitor extends BaseMonitor {
168
168
  }
169
169
 
170
170
  if (txsToUpdate.length) {
171
- const accountState = await aci.getAccountState({ assetName, walletAccount })
172
171
  await this.updateTxLog({ assetName, walletAccount, logItems: txsToUpdate })
173
- if (['bitcoin', 'bitcoinregtest', 'bitcointestnet'].includes(assetName)) {
172
+ if (utxos && ['bitcoin', 'bitcoinregtest', 'bitcointestnet'].includes(assetName)) {
174
173
  const unconfirmedTxAncestor = await resolveUnconfirmedAncestorData({
175
- asset: this.asset,
176
- accountState,
177
- walletAccount,
174
+ utxos,
178
175
  insightClient: this.#insightClient,
179
176
  })
180
177
  newData.mem = { unconfirmedTxAncestor }
@@ -269,12 +266,9 @@ export class Monitor extends BaseMonitor {
269
266
  }
270
267
 
271
268
  // Move to after tick
272
- if (['bitcoin', 'bitcoinregtest', 'bitcointestnet'].includes(assetName)) {
273
- const accountState = await aci.getAccountState({ assetName, walletAccount })
269
+ if (utxos && ['bitcoin', 'bitcoinregtest', 'bitcointestnet'].includes(assetName)) {
274
270
  const unconfirmedTxAncestor = await resolveUnconfirmedAncestorData({
275
- asset: this.asset,
276
- accountState,
277
- walletAccount,
271
+ utxos,
278
272
  insightClient: this.#insightClient,
279
273
  })
280
274
  newData.mem = { unconfirmedTxAncestor }
package/src/tx-utils.js CHANGED
@@ -11,13 +11,7 @@ export const findUnconfirmedSentRbfTxs = (txSet) =>
11
11
  tx.data.inputs
12
12
  )
13
13
 
14
- export const findLargeUnconfirmedTxs = ({
15
- assetName,
16
- txSet,
17
- feeRate,
18
- maxFee,
19
- unconfirmedTxAncestor,
20
- }) =>
14
+ export const findLargeUnconfirmedTxs = ({ txSet, feeRate, maxFee, unconfirmedTxAncestor }) =>
21
15
  !txSet
22
16
  ? new Set()
23
17
  : new Set(
@@ -25,7 +19,6 @@ export const findLargeUnconfirmedTxs = ({
25
19
  .filter((tx) => {
26
20
  if (!tx.pending) return false
27
21
  const extraFee = resolveExtraFeeOfTx({
28
- assetName,
29
22
  feeRate,
30
23
  txId: tx.txId,
31
24
  unconfirmedTxAncestor,
@@ -1,28 +1,18 @@
1
- import { getUtxos } from './utxos-utils'
1
+ import assert from 'minimalistic-assert'
2
2
 
3
- export async function resolveUnconfirmedAncestorData({
4
- asset,
5
- walletAccount,
6
- accountState,
7
- insightClient,
8
- }) {
9
- const dataMap = getUnconfirmedTxAncestorMap({ accountState })
10
- Object.entries(dataMap).forEach(([txId, stored]) => {
11
- if (stored.walletAccount === walletAccount && stored.assetName === asset.name)
12
- delete dataMap[txId]
3
+ export async function resolveUnconfirmedAncestorData({ utxos, insightClient }) {
4
+ assert(utxos, 'utxos is required')
5
+ assert(insightClient, 'insightClient is required')
6
+ const dataMap = Object.create(null)
7
+ const unconfirmedUtxos = utxos.toArray().filter((data) => {
8
+ return !data.confirmations || data.confirmations <= 0
13
9
  })
14
-
15
- const utxos = getUtxos({ accountState, asset })
16
- .toArray()
17
- .filter((data) => {
18
- return !data.confirmations || data.confirmations <= 0
19
- })
20
- const txIds = new Set(utxos.map(({ txId }) => txId))
10
+ const txIds = new Set(unconfirmedUtxos.map(({ txId }) => txId))
21
11
  for (const txId of txIds) {
22
12
  try {
23
13
  const { size, fees } = await insightClient.fetchUnconfirmedAncestorData(txId)
24
14
  if (size !== 0) {
25
- dataMap[txId] = { assetName: asset.name, walletAccount, size, fees }
15
+ dataMap[txId] = { size, fees }
26
16
  }
27
17
  } catch (e) {
28
18
  console.warn(e)
@@ -32,19 +22,11 @@ export async function resolveUnconfirmedAncestorData({
32
22
  }
33
23
 
34
24
  export function getUnconfirmedTxAncestorMap({ accountState }) {
35
- return accountState?.mem?.unconfirmedTxAncestor || {}
36
- }
37
-
38
- function getUnconfirmedAncestorData({ txId, assetName, unconfirmedTxAncestor = {} }) {
39
- const stored = unconfirmedTxAncestor[txId]
40
- if (stored?.assetName === assetName) {
41
- return { size: stored.size, fees: stored.fees }
42
- }
43
- return undefined
25
+ return accountState?.mem?.unconfirmedTxAncestor || Object.create(null)
44
26
  }
45
27
 
46
- export function resolveExtraFeeOfTx({ assetName, feeRate, txId, unconfirmedTxAncestor }) {
47
- const data = getUnconfirmedAncestorData({ assetName, txId, unconfirmedTxAncestor })
28
+ export function resolveExtraFeeOfTx({ feeRate, txId, unconfirmedTxAncestor }) {
29
+ const data = unconfirmedTxAncestor?.[txId]
48
30
  if (!data) return 0
49
31
  const { fees, size } = data
50
32
  // Get the difference in fee rate between ancestors and current estimate
@@ -122,17 +122,54 @@ function isOrdinalUtxo({
122
122
  return hasOrdinals
123
123
  }
124
124
 
125
+ export function mergeAdditionalInscriptions({ allUtxos, additionalInscriptions }) {
126
+ return UtxoCollection.fromArray(
127
+ allUtxos.toArray().map((utxo) => {
128
+ const inscriptions = additionalInscriptions
129
+ .filter((additionalInscription) => {
130
+ const forUtxo =
131
+ additionalInscription.vout === utxo.vout && additionalInscription.txId === utxo.txId
132
+ if (forUtxo) {
133
+ // avoid duplicated
134
+ return !utxo.inscriptions?.find(
135
+ (existingInscription) =>
136
+ existingInscription.inscriptionId === additionalInscription.inscriptionId
137
+ )
138
+ }
139
+ return forUtxo
140
+ })
141
+ .map((additionalInscription) => ({
142
+ inscriptionId: additionalInscription.inscriptionId,
143
+ offset: additionalInscription.offset || 0,
144
+ }))
145
+ if (inscriptions.length) {
146
+ utxo.inscriptions = [...(utxo.inscriptions || []), ...inscriptions]
147
+ }
148
+ return utxo
149
+ }),
150
+ {
151
+ currency: allUtxos.currency,
152
+ }
153
+ )
154
+ }
155
+
125
156
  export function partitionUtxos({
126
157
  allUtxos,
127
158
  ordinalsEnabled,
128
159
  knownBalanceUtxoIds,
129
160
  ordinalAddress,
130
161
  mustAvoidUtxoIds,
162
+ additionalInscriptions,
131
163
  }) {
132
164
  assert(allUtxos, 'allUtxos is required')
133
165
  if (ordinalsEnabled) assert(ordinalAddress, 'ordinalAddress is required')
166
+
167
+ const expandedAllUtxos = ordinalsEnabled
168
+ ? mergeAdditionalInscriptions({ allUtxos, additionalInscriptions })
169
+ : allUtxos
170
+
134
171
  return {
135
- utxos: allUtxos.filter(
172
+ utxos: expandedAllUtxos.filter(
136
173
  (utxo) =>
137
174
  !isOrdinalUtxo({
138
175
  utxo,
@@ -142,7 +179,7 @@ export function partitionUtxos({
142
179
  mustAvoidUtxoIds,
143
180
  })
144
181
  ),
145
- ordinalsUtxos: allUtxos.filter((utxo) =>
182
+ ordinalsUtxos: expandedAllUtxos.filter((utxo) =>
146
183
  isOrdinalUtxo({
147
184
  utxo,
148
185
  ordinalsEnabled,
@@ -191,7 +228,6 @@ export function getUsableUtxos({ asset, utxos, feeData, txSet, unconfirmedTxAnce
191
228
  assert(typeof maxFee === 'number' && !Number.isNaN(maxFee), 'maxFee must be a number')
192
229
 
193
230
  const largeUnconfirmedTxs = findLargeUnconfirmedTxs({
194
- assetName: asset.name,
195
231
  txSet,
196
232
  feeRate,
197
233
  maxFee,