opnet 1.4.0 → 1.4.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.
@@ -3,5 +3,4 @@ export interface BroadcastedTransaction {
3
3
  readonly result?: string;
4
4
  readonly error?: string;
5
5
  readonly peers?: number;
6
- readonly id: string;
7
6
  }
@@ -3,17 +3,14 @@ import { AbstractRpcProvider } from '../providers/AbstractRpcProvider.js';
3
3
  import { RequestUTXOsParams, RequestUTXOsParamsWithAmount } from './interfaces/IUTXOsManager.js';
4
4
  export declare class UTXOsManager {
5
5
  private readonly provider;
6
- private spentUTXOs;
7
- private pendingUTXOs;
8
- private pendingUtxoDepth;
9
- private lastCleanup;
10
- private lastFetchTimestamp;
11
- private lastFetchedData;
6
+ private dataByAddress;
12
7
  constructor(provider: AbstractRpcProvider);
13
- spentUTXO(spent: UTXOs, newUTXOs: UTXOs): void;
14
- clean(): void;
8
+ spentUTXO(address: string, spent: UTXOs, newUTXOs: UTXOs): void;
9
+ getPendingUTXOs(address: string): UTXOs;
10
+ clean(address?: string): void;
15
11
  getUTXOs({ address, optimize, mergePendingUTXOs, filterSpentUTXOs, }: RequestUTXOsParams): Promise<UTXOs>;
16
12
  getUTXOsForAmount({ address, amount, optimize, mergePendingUTXOs, filterSpentUTXOs, throwErrors, }: RequestUTXOsParamsWithAmount): Promise<UTXOs>;
13
+ private getAddressData;
17
14
  private maybeFetchUTXOs;
18
15
  private fetchUTXOs;
19
16
  private syncPendingDepthWithFetched;
@@ -1 +1 @@
1
- export declare const version = "1.4.0";
1
+ export declare const version = "1.4.2";
package/build/_version.js CHANGED
@@ -1 +1 @@
1
- export const version = '1.4.0';
1
+ export const version = '1.4.2';
@@ -137,7 +137,7 @@ export class CallResult {
137
137
  if (!tx2.result) {
138
138
  throw new Error('No transaction ID returned');
139
139
  }
140
- this.#provider.utxoManager.spentUTXO(UTXOs, transaction.nextUTXOs);
140
+ this.#provider.utxoManager.spentUTXO(interactionParams.refundTo, UTXOs, transaction.nextUTXOs);
141
141
  return {
142
142
  transactionId: tx2.result,
143
143
  peerAcknowledgements: tx2.peers || 0,
@@ -278,14 +278,7 @@ export class AbstractRpcProvider {
278
278
  }
279
279
  const payload = this.buildJsonRpcPayload(JSONRpcMethods.BROADCAST_TRANSACTION, [tx, psbt]);
280
280
  const rawTx = await this.callPayloadSingle(payload);
281
- const result = rawTx.result;
282
- if (result && result.id) {
283
- return {
284
- ...result,
285
- id: result.id,
286
- };
287
- }
288
- return result;
281
+ return rawTx.result;
289
282
  }
290
283
  async sendRawTransactions(txs) {
291
284
  const payloads = txs.map((tx) => {
@@ -296,14 +289,7 @@ export class AbstractRpcProvider {
296
289
  throw new Error(`Error sending transactions: ${rawTxs.error}`);
297
290
  }
298
291
  return rawTxs.map((rawTx) => {
299
- const result = rawTx.result;
300
- if (result && result.id) {
301
- return {
302
- ...result,
303
- id: result.id,
304
- };
305
- }
306
- return result;
292
+ return rawTx.result;
307
293
  });
308
294
  }
309
295
  async getBlockWitness(height = -1, trusted, limit, page) {
@@ -3,5 +3,4 @@ export interface BroadcastedTransaction {
3
3
  readonly result?: string;
4
4
  readonly error?: string;
5
5
  readonly peers?: number;
6
- readonly id: string;
7
6
  }
@@ -3,17 +3,14 @@ import { AbstractRpcProvider } from '../providers/AbstractRpcProvider.js';
3
3
  import { RequestUTXOsParams, RequestUTXOsParamsWithAmount } from './interfaces/IUTXOsManager.js';
4
4
  export declare class UTXOsManager {
5
5
  private readonly provider;
6
- private spentUTXOs;
7
- private pendingUTXOs;
8
- private pendingUtxoDepth;
9
- private lastCleanup;
10
- private lastFetchTimestamp;
11
- private lastFetchedData;
6
+ private dataByAddress;
12
7
  constructor(provider: AbstractRpcProvider);
13
- spentUTXO(spent: UTXOs, newUTXOs: UTXOs): void;
14
- clean(): void;
8
+ spentUTXO(address: string, spent: UTXOs, newUTXOs: UTXOs): void;
9
+ getPendingUTXOs(address: string): UTXOs;
10
+ clean(address?: string): void;
15
11
  getUTXOs({ address, optimize, mergePendingUTXOs, filterSpentUTXOs, }: RequestUTXOsParams): Promise<UTXOs>;
16
12
  getUTXOsForAmount({ address, amount, optimize, mergePendingUTXOs, filterSpentUTXOs, throwErrors, }: RequestUTXOsParamsWithAmount): Promise<UTXOs>;
13
+ private getAddressData;
17
14
  private maybeFetchUTXOs;
18
15
  private fetchUTXOs;
19
16
  private syncPendingDepthWithFetched;
@@ -5,30 +5,26 @@ const FETCH_COOLDOWN = 10000;
5
5
  const MEMPOOL_CHAIN_LIMIT = 25;
6
6
  export class UTXOsManager {
7
7
  provider;
8
- spentUTXOs = [];
9
- pendingUTXOs = [];
10
- pendingUtxoDepth = {};
11
- lastCleanup = Date.now();
12
- lastFetchTimestamp = 0;
13
- lastFetchedData = null;
8
+ dataByAddress = {};
14
9
  constructor(provider) {
15
10
  this.provider = provider;
16
11
  }
17
- spentUTXO(spent, newUTXOs) {
12
+ spentUTXO(address, spent, newUTXOs) {
13
+ const addressData = this.getAddressData(address);
18
14
  const utxoKey = (u) => `${u.transactionId}:${u.outputIndex}`;
19
- this.pendingUTXOs = this.pendingUTXOs.filter((utxo) => {
15
+ addressData.pendingUTXOs = addressData.pendingUTXOs.filter((utxo) => {
20
16
  return !spent.some((spentUtxo) => spentUtxo.transactionId === utxo.transactionId &&
21
17
  spentUtxo.outputIndex === utxo.outputIndex);
22
18
  });
23
19
  for (const spentUtxo of spent) {
24
20
  const key = utxoKey(spentUtxo);
25
- delete this.pendingUtxoDepth[key];
21
+ delete addressData.pendingUtxoDepth[key];
26
22
  }
27
- this.spentUTXOs.push(...spent);
23
+ addressData.spentUTXOs.push(...spent);
28
24
  let maxParentDepth = 0;
29
25
  for (const spentUtxo of spent) {
30
26
  const key = utxoKey(spentUtxo);
31
- const parentDepth = this.pendingUtxoDepth[key] ?? 0;
27
+ const parentDepth = addressData.pendingUtxoDepth[key] ?? 0;
32
28
  if (parentDepth > maxParentDepth) {
33
29
  maxParentDepth = parentDepth;
34
30
  }
@@ -38,23 +34,34 @@ export class UTXOsManager {
38
34
  throw new Error(`too-long-mempool-chain, too many descendants for tx ... [limit: ${MEMPOOL_CHAIN_LIMIT}]`);
39
35
  }
40
36
  for (const nu of newUTXOs) {
41
- this.pendingUTXOs.push(nu);
42
- this.pendingUtxoDepth[utxoKey(nu)] = newDepth;
37
+ addressData.pendingUTXOs.push(nu);
38
+ addressData.pendingUtxoDepth[utxoKey(nu)] = newDepth;
43
39
  }
44
40
  }
45
- clean() {
46
- this.spentUTXOs = [];
47
- this.pendingUTXOs = [];
48
- this.pendingUtxoDepth = {};
49
- this.lastCleanup = Date.now();
50
- this.lastFetchTimestamp = 0;
51
- this.lastFetchedData = null;
41
+ getPendingUTXOs(address) {
42
+ const addressData = this.getAddressData(address);
43
+ return addressData.pendingUTXOs;
44
+ }
45
+ clean(address) {
46
+ if (address) {
47
+ const addressData = this.getAddressData(address);
48
+ addressData.spentUTXOs = [];
49
+ addressData.pendingUTXOs = [];
50
+ addressData.pendingUtxoDepth = {};
51
+ addressData.lastCleanup = Date.now();
52
+ addressData.lastFetchTimestamp = 0;
53
+ addressData.lastFetchedData = null;
54
+ }
55
+ else {
56
+ this.dataByAddress = {};
57
+ }
52
58
  }
53
59
  async getUTXOs({ address, optimize = true, mergePendingUTXOs = true, filterSpentUTXOs = true, }) {
60
+ const addressData = this.getAddressData(address);
54
61
  const fetchedData = await this.maybeFetchUTXOs(address, optimize);
55
62
  const utxoKey = (utxo) => `${utxo.transactionId}:${utxo.outputIndex}`;
56
- const pendingUTXOKeys = new Set(this.pendingUTXOs.map(utxoKey));
57
- const spentUTXOKeys = new Set(this.spentUTXOs.map(utxoKey));
63
+ const pendingUTXOKeys = new Set(addressData.pendingUTXOs.map(utxoKey));
64
+ const spentUTXOKeys = new Set(addressData.spentUTXOs.map(utxoKey));
58
65
  const fetchedSpentKeys = new Set(fetchedData.spentTransactions.map(utxoKey));
59
66
  const combinedUTXOs = [];
60
67
  const combinedKeysSet = new Set();
@@ -66,7 +73,7 @@ export class UTXOsManager {
66
73
  }
67
74
  }
68
75
  if (mergePendingUTXOs) {
69
- for (const utxo of this.pendingUTXOs) {
76
+ for (const utxo of addressData.pendingUTXOs) {
70
77
  const key = utxoKey(utxo);
71
78
  if (!combinedKeysSet.has(key)) {
72
79
  combinedUTXOs.push(utxo);
@@ -108,23 +115,36 @@ export class UTXOsManager {
108
115
  }
109
116
  return utxoUntilAmount;
110
117
  }
118
+ getAddressData(address) {
119
+ if (!this.dataByAddress[address]) {
120
+ this.dataByAddress[address] = {
121
+ spentUTXOs: [],
122
+ pendingUTXOs: [],
123
+ pendingUtxoDepth: {},
124
+ lastCleanup: Date.now(),
125
+ lastFetchTimestamp: 0,
126
+ lastFetchedData: null,
127
+ };
128
+ }
129
+ return this.dataByAddress[address];
130
+ }
111
131
  async maybeFetchUTXOs(address, optimize) {
132
+ const addressData = this.getAddressData(address);
112
133
  const now = Date.now();
113
- const age = now - this.lastFetchTimestamp;
114
- if (now - this.lastCleanup > AUTO_PURGE_AFTER) {
115
- this.clean();
134
+ const age = now - addressData.lastFetchTimestamp;
135
+ if (now - addressData.lastCleanup > AUTO_PURGE_AFTER) {
136
+ this.clean(address);
116
137
  }
117
- if (this.lastFetchedData && age < FETCH_COOLDOWN) {
118
- return this.lastFetchedData;
138
+ if (addressData.lastFetchedData && age < FETCH_COOLDOWN) {
139
+ return addressData.lastFetchedData;
119
140
  }
120
- this.lastFetchedData = await this.fetchUTXOs(address, optimize);
121
- this.lastFetchTimestamp = now;
122
- this.syncPendingDepthWithFetched();
123
- return this.lastFetchedData;
141
+ addressData.lastFetchedData = await this.fetchUTXOs(address, optimize);
142
+ addressData.lastFetchTimestamp = now;
143
+ this.syncPendingDepthWithFetched(address);
144
+ return addressData.lastFetchedData;
124
145
  }
125
146
  async fetchUTXOs(address, optimize = false) {
126
- const addressStr = address.toString();
127
- const payload = this.provider.buildJsonRpcPayload(JSONRpcMethods.GET_UTXOS, [addressStr, optimize]);
147
+ const payload = this.provider.buildJsonRpcPayload(JSONRpcMethods.GET_UTXOS, [address, optimize]);
128
148
  const rawUTXOs = await this.provider.callPayloadSingle(payload);
129
149
  if ('error' in rawUTXOs) {
130
150
  throw new Error(`Error fetching block: ${rawUTXOs.error}`);
@@ -140,16 +160,17 @@ export class UTXOsManager {
140
160
  spentTransactions: result.spentTransactions.map((utxo) => new UTXO(utxo)),
141
161
  };
142
162
  }
143
- syncPendingDepthWithFetched() {
144
- if (!this.lastFetchedData) {
163
+ syncPendingDepthWithFetched(address) {
164
+ const addressData = this.getAddressData(address);
165
+ const fetched = addressData.lastFetchedData;
166
+ if (!fetched)
145
167
  return;
146
- }
147
- const confirmedKeys = new Set(this.lastFetchedData.confirmed.map((u) => `${u.transactionId}:${u.outputIndex}`));
148
- const spentKeys = new Set(this.lastFetchedData.spentTransactions.map((u) => `${u.transactionId}:${u.outputIndex}`));
149
- this.pendingUTXOs = this.pendingUTXOs.filter((u) => {
168
+ const confirmedKeys = new Set(fetched.confirmed.map((u) => `${u.transactionId}:${u.outputIndex}`));
169
+ const spentKeys = new Set(fetched.spentTransactions.map((u) => `${u.transactionId}:${u.outputIndex}`));
170
+ addressData.pendingUTXOs = addressData.pendingUTXOs.filter((u) => {
150
171
  const key = `${u.transactionId}:${u.outputIndex}`;
151
172
  if (confirmedKeys.has(key) || spentKeys.has(key)) {
152
- delete this.pendingUtxoDepth[key];
173
+ delete addressData.pendingUtxoDepth[key];
153
174
  return false;
154
175
  }
155
176
  return true;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "opnet",
3
3
  "type": "module",
4
- "version": "1.4.0",
4
+ "version": "1.4.2",
5
5
  "author": "OP_NET",
6
6
  "description": "The perfect library for building Bitcoin-based applications.",
7
7
  "engines": {
@@ -103,7 +103,7 @@
103
103
  "@bitcoinerlab/secp256k1": "^1.2.0",
104
104
  "@btc-vision/bitcoin": "^6.3.6",
105
105
  "@btc-vision/bitcoin-rpc": "^1.0.1",
106
- "@btc-vision/transaction": "^1.3.8",
106
+ "@btc-vision/transaction": "^1.4.0",
107
107
  "@noble/hashes": "^1.7.1",
108
108
  "bignumber.js": "^9.1.2",
109
109
  "buffer": "^6.0.3",
package/src/_version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '1.4.0';
1
+ export const version = '1.4.2';
@@ -250,7 +250,11 @@ export class CallResult<
250
250
  throw new Error('No transaction ID returned');
251
251
  }
252
252
 
253
- this.#provider.utxoManager.spentUTXO(UTXOs, transaction.nextUTXOs);
253
+ this.#provider.utxoManager.spentUTXO(
254
+ interactionParams.refundTo,
255
+ UTXOs,
256
+ transaction.nextUTXOs,
257
+ );
254
258
 
255
259
  return {
256
260
  transactionId: tx2.result,
@@ -586,15 +586,7 @@ export abstract class AbstractRpcProvider {
586
586
  );
587
587
 
588
588
  const rawTx: JsonRpcResult = await this.callPayloadSingle(payload);
589
- const result: BroadcastedTransaction = rawTx.result as BroadcastedTransaction;
590
- if (result && result.id) {
591
- return {
592
- ...result,
593
- id: result.id,
594
- };
595
- }
596
-
597
- return result;
589
+ return rawTx.result as BroadcastedTransaction;
598
590
  }
599
591
 
600
592
  /**
@@ -615,15 +607,7 @@ export abstract class AbstractRpcProvider {
615
607
  }
616
608
 
617
609
  return rawTxs.map((rawTx) => {
618
- const result: BroadcastedTransaction = rawTx.result as BroadcastedTransaction;
619
- if (result && result.id) {
620
- return {
621
- ...result,
622
- id: result.id,
623
- };
624
- }
625
-
626
- return result;
610
+ return rawTx.result as BroadcastedTransaction;
627
611
  });
628
612
  }
629
613
 
@@ -16,9 +16,4 @@ export interface BroadcastedTransaction {
16
16
  * The number of peers that the transaction was broadcasted to.
17
17
  */
18
18
  readonly peers?: number;
19
-
20
- /**
21
- * The identifier of the transaction.
22
- */
23
- readonly id: string;
24
19
  }