opnet 1.8.1 → 1.8.3

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +25 -15
  3. package/browser/_version.d.ts +1 -1
  4. package/browser/contracts/interfaces/IProviderForCallResult.d.ts +2 -0
  5. package/browser/index.js +174 -63
  6. package/browser/opnet.d.ts +1 -0
  7. package/browser/providers/AbstractRpcProvider.d.ts +2 -0
  8. package/browser/providers/interfaces/JSONRpcMethods.d.ts +1 -0
  9. package/browser/providers/websocket/types/WebSocketOpcodes.d.ts +2 -0
  10. package/browser/transactions/interfaces/BroadcastedTransactionPackage.d.ts +48 -0
  11. package/browser/utxos/UTXOsManager.d.ts +1 -0
  12. package/build/_version.d.ts +1 -1
  13. package/build/_version.js +1 -1
  14. package/build/contracts/CallResult.js +54 -19
  15. package/build/contracts/interfaces/IProviderForCallResult.d.ts +2 -0
  16. package/build/opnet.d.ts +1 -0
  17. package/build/opnet.js +1 -0
  18. package/build/providers/AbstractRpcProvider.d.ts +2 -0
  19. package/build/providers/AbstractRpcProvider.js +15 -2
  20. package/build/providers/WebsocketRpcProvider.js +5 -0
  21. package/build/providers/interfaces/JSONRpcMethods.d.ts +1 -0
  22. package/build/providers/interfaces/JSONRpcMethods.js +1 -0
  23. package/build/providers/websocket/MethodMapping.js +6 -0
  24. package/build/providers/websocket/types/WebSocketOpcodes.d.ts +2 -0
  25. package/build/providers/websocket/types/WebSocketOpcodes.js +2 -0
  26. package/build/transactions/interfaces/BroadcastedTransactionPackage.d.ts +48 -0
  27. package/build/transactions/interfaces/BroadcastedTransactionPackage.js +1 -0
  28. package/build/tsconfig.build.tsbuildinfo +1 -1
  29. package/build/utxos/UTXOsManager.d.ts +1 -0
  30. package/build/utxos/UTXOsManager.js +37 -28
  31. package/docs/api-reference/provider-api.md +16 -0
  32. package/docs/api-reference/types-interfaces.md +91 -0
  33. package/docs/api-reference/utxo-manager-api.md +4 -2
  34. package/docs/svg/tx-broadcast-flow.svg +201 -0
  35. package/docs/transactions/broadcasting.md +124 -9
  36. package/package.json +2 -3
  37. package/src/_version.ts +1 -1
  38. package/src/contracts/CallResult.ts +82 -32
  39. package/src/contracts/Contract.ts +11 -4
  40. package/src/contracts/interfaces/IProviderForCallResult.ts +5 -0
  41. package/src/opnet.ts +1 -0
  42. package/src/providers/AbstractRpcProvider.ts +52 -5
  43. package/src/providers/WebsocketRpcProvider.ts +7 -0
  44. package/src/providers/interfaces/JSONRpcMethods.ts +1 -0
  45. package/src/providers/websocket/MethodMapping.ts +6 -0
  46. package/src/providers/websocket/types/WebSocketOpcodes.ts +2 -0
  47. package/src/transactions/interfaces/BroadcastedTransactionPackage.ts +72 -0
  48. package/src/utxos/UTXOsManager.ts +82 -46
package/CHANGELOG.md CHANGED
@@ -1,5 +1,60 @@
1
1
  # Changelog
2
2
 
3
+ ## [v1.8.2] - 2026-03-07
4
+
5
+ - No changes
6
+
7
+
8
+ ## [v1.8.1] - 2026-03-07
9
+
10
+ ### Breaking Changes
11
+
12
+ - breaking: upgraded deps, refactor buffer -> uint8array for consistency, upgraded eslint v10. ([#134](https://github.com/btc-vision/opnet/pull/134)) by @BlobMaster41
13
+
14
+ ### Features
15
+
16
+ - Rename targetHash to checksumRoot in epoch interfaces ([#120](https://github.com/btc-vision/opnet/pull/120)) by @BlobMaster41
17
+ - Upgrade/deps add http threader ([#121](https://github.com/btc-vision/opnet/pull/121)) by @BlobMaster41
18
+ - Fix/react native ([#126](https://github.com/btc-vision/opnet/pull/126)) by @BlobMaster41
19
+ - Add constant/payable validation to CallResult ([#131](https://github.com/btc-vision/opnet/pull/131)) by @BlobMaster41
20
+ - breaking: upgraded deps, refactor buffer -> uint8array for consistency, upgraded eslint v10. ([#134](https://github.com/btc-vision/opnet/pull/134)) by @BlobMaster41
21
+ - Normalize hex strings; strip 0x prefix safely ([#135](https://github.com/btc-vision/opnet/pull/135)) by @BlobMaster41
22
+ - feat: add mempool API and WebSocket support ([#136](https://github.com/btc-vision/opnet/pull/136)) by @BlobMaster41
23
+ - Rework/mempool ([#137](https://github.com/btc-vision/opnet/pull/137)) by @BlobMaster41
24
+
25
+ ### Bug Fixes
26
+
27
+ - Upgrade/deps add http threader ([#121](https://github.com/btc-vision/opnet/pull/121)) by @BlobMaster41
28
+ - Fix/react native ([#126](https://github.com/btc-vision/opnet/pull/126)) by @BlobMaster41
29
+ - Normalize hex strings; strip 0x prefix safely ([#135](https://github.com/btc-vision/opnet/pull/135)) by @BlobMaster41
30
+
31
+ ### Documentation
32
+
33
+ - Upgrade/deps add http threader ([#121](https://github.com/btc-vision/opnet/pull/121)) by @BlobMaster41
34
+ - Add constant/payable validation to CallResult ([#131](https://github.com/btc-vision/opnet/pull/131)) by @BlobMaster41
35
+ - docs: add ABI flags and update contract APIs ([#132](https://github.com/btc-vision/opnet/pull/132)) by @BlobMaster41
36
+ - breaking: upgraded deps, refactor buffer -> uint8array for consistency, upgraded eslint v10. ([#134](https://github.com/btc-vision/opnet/pull/134)) by @BlobMaster41
37
+ - feat: add mempool API and WebSocket support ([#136](https://github.com/btc-vision/opnet/pull/136)) by @BlobMaster41
38
+
39
+ ### Other Changes
40
+
41
+ - Refactor ABI interfaces and events for OPNet and stablecoins ([#110](https://github.com/btc-vision/opnet/pull/110)) by @BlobMaster41
42
+ - Update docs for mnemonic-based wallet usage and add tables of contents ([#114](https://github.com/btc-vision/opnet/pull/114)) by @BlobMaster41
43
+ - Bump version to 1.8.0 ([#115](https://github.com/btc-vision/opnet/pull/115)) by @BlobMaster41
44
+ - Add security policy, templates, and extended ABI support ([#118](https://github.com/btc-vision/opnet/pull/118)) by @BlobMaster41
45
+ - update motochef factory and template motochef abi/interface ([#117](https://github.com/btc-vision/opnet/pull/117)) by @icedevera
46
+ - Bump version to 1.8.1-alpha.0 ([#119](https://github.com/btc-vision/opnet/pull/119)) by @BlobMaster41
47
+ - ⬆️(deps-dev): Bump vite-plugin-node-polyfills from 0.24.0 to 0.25.0 in the dev-deps group ([#116](https://github.com/btc-vision/opnet/pull/116)) by @dependabot[bot]
48
+ - Bump btc-vision deps and relax signer type ([#124](https://github.com/btc-vision/opnet/pull/124)) by @BlobMaster41
49
+ - Tuple/implmentation ([#127](https://github.com/btc-vision/opnet/pull/127)) by @BlobMaster41
50
+ - Bump version and disable threaded parsing ([#128](https://github.com/btc-vision/opnet/pull/128)) by @BlobMaster41
51
+ - Added constant to ABI ([#133](https://github.com/btc-vision/opnet/pull/133)) by @BlobMaster41
52
+ - Bump version and relax getPublicKeyInfo return ([#141](https://github.com/btc-vision/opnet/pull/141)) by @BlobMaster41
53
+ - ⬆️(deps): Bump bignumber.js from 9.3.1 to 10.0.2 ([#140](https://github.com/btc-vision/opnet/pull/140)) by @dependabot[bot]
54
+
55
+
56
+
57
+
3
58
  ## [v1.8.1-rc.17] - 2026-02-27
4
59
 
5
60
  - No changes
package/README.md CHANGED
@@ -7,7 +7,8 @@
7
7
 
8
8
  [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
9
9
 
10
- The official client library for building Bitcoin-based applications on OPNet. Full TypeScript support with type-safe contract interactions.
10
+ The official client library for building Bitcoin-based applications on OPNet.
11
+ Full TypeScript support with type-safe contract interactions.
11
12
 
12
13
  ## Security Audit
13
14
 
@@ -26,7 +27,8 @@ The official client library for building Bitcoin-based applications on OPNet. Fu
26
27
  </a>
27
28
  </p>
28
29
 
29
- This library has been professionally audited by [Verichains](https://verichains.io).
30
+ This library has been professionally audited
31
+ by [Verichains](https://verichains.io).
30
32
 
31
33
  See [SECURITY.md](./SECURITY.md) for details.
32
34
 
@@ -41,18 +43,22 @@ npm install opnet @btc-vision/transaction @btc-vision/bitcoin
41
43
  Check out the full documentation in [`/docs`](./docs)!
42
44
 
43
45
  - [Getting Started](./docs/getting-started/quick-start.md)
44
- - [Providers](./docs/providers/json-rpc-provider.md) - JSON-RPC & WebSocket connections
45
- - [Smart Contracts](./docs/contracts/overview.md) - Contract interactions & transactions
46
+ - [Providers](./docs/providers/json-rpc-provider.md) - JSON-RPC & WebSocket
47
+ connections
48
+ - [Smart Contracts](./docs/contracts/overview.md) - Contract interactions &
49
+ transactions
46
50
  - [UTXO Management](./docs/bitcoin/utxos.md) - Bitcoin UTXO handling
47
51
  - [Offline Signing](./docs/contracts/offline-signing.md) - Cold wallet support
48
- - [ABI Reference](./docs/abi-reference/abi-overview.md) - OP20, OP721, MotoSwap ABIs
52
+ - [ABI Reference](./docs/abi-reference/abi-overview.md) - OP20, OP721, MotoSwap
53
+ ABIs
49
54
  - [API Reference](./docs/api-reference/provider-api.md) - Full API documentation
50
55
 
51
56
  ## RPC Endpoints
52
57
 
53
- | Network | URL |
54
- |---------|-----|
58
+ | Network | URL |
59
+ |---------|-----------------------------|
55
60
  | Mainnet | `https://mainnet.opnet.org` |
61
+ | Testnet | `https://testnet.opnet.org` |
56
62
  | Regtest | `https://regtest.opnet.org` |
57
63
 
58
64
  ## Quick Start
@@ -63,16 +69,17 @@ import { AddressTypes, Mnemonic, MLDSASecurityLevel } from '@btc-vision/transact
63
69
  import { networks } from '@btc-vision/bitcoin';
64
70
 
65
71
  // Connect to OPNet
66
- const provider = new JSONRpcProvider('https://regtest.opnet.org', networks.regtest);
72
+ const provider = new JSONRpcProvider('https://testnet.opnet.org', networks.
73
+ opnetTestnet);
67
74
 
68
75
  // Create wallet from mnemonic
69
76
  const mnemonic = new Mnemonic(
70
77
  'your twenty four word seed phrase goes here ...',
71
78
  '',
72
- networks.regtest,
79
+ networks.opnetTestnet,
73
80
  MLDSASecurityLevel.LEVEL2,
74
81
  );
75
- const wallet = mnemonic.deriveUnisat(AddressTypes.P2TR, 0);
82
+ const wallet = mnemonic.deriveOPWallet(AddressTypes.P2TR, 0);
76
83
  const myAddress = wallet.address;
77
84
 
78
85
  // Interact with a token contract
@@ -80,7 +87,7 @@ const token = getContract<IOP20Contract>(
80
87
  'op1...', // contract address
81
88
  OP_20_ABI,
82
89
  provider,
83
- networks.regtest,
90
+ networks.opnetTestnet,
84
91
  myAddress
85
92
  );
86
93
 
@@ -105,7 +112,7 @@ const tx = await simulation.sendTransaction({
105
112
  refundTo: wallet.p2tr,
106
113
  maximumAllowedSatToSpend: 50000n,
107
114
  feeRate: 10,
108
- network: networks.regtest,
115
+ network: networks.opnetTestnet,
109
116
  });
110
117
 
111
118
  console.log('TX ID:', tx.transactionId);
@@ -133,12 +140,15 @@ npm run build
133
140
  4. Run tests: `npm test`
134
141
  5. Submit a pull request
135
142
 
136
- See the [pull request template](./.github/PULL_REQUEST_TEMPLATE.md) for requirements.
143
+ See the [pull request template](./.github/PULL_REQUEST_TEMPLATE.md) for
144
+ requirements.
137
145
 
138
146
  ## Reporting Issues
139
147
 
140
- - **Bugs**: Use the [bug report template](https://github.com/btc-vision/opnet/issues/new?template=bug_report.yml)
141
- - **Security**: See [SECURITY.md](./SECURITY.md) - do not open public issues for vulnerabilities
148
+ - **Bugs**: Use
149
+ the [bug report template](https://github.com/btc-vision/opnet/issues/new?template=bug_report.yml)
150
+ - **Security**: See [SECURITY.md](./SECURITY.md) - do not open public issues for
151
+ vulnerabilities
142
152
 
143
153
  ## License
144
154
 
@@ -1 +1 @@
1
- export declare const version = "1.8.1";
1
+ export declare const version = "1.8.3";
@@ -2,6 +2,7 @@ import { Network } from '../../../node_modules/@btc-vision/bitcoin/build/index.j
2
2
  import { Address, ChallengeSolution, IP2WSHAddress } from '../../../node_modules/@btc-vision/transaction/build/index.js';
3
3
  import { UTXO, UTXOs } from '../../bitcoin/UTXOs.js';
4
4
  import { BroadcastedTransaction } from '../../transactions/interfaces/BroadcastedTransaction.js';
5
+ import { BroadcastedTransactionPackage } from '../../transactions/interfaces/BroadcastedTransactionPackage.js';
5
6
  import { RequestUTXOsParamsWithAmount } from '../../utxos/interfaces/IUTXOsManager.js';
6
7
  export interface IUTXOManagerForCallResult {
7
8
  getUTXOsForAmount(params: RequestUTXOsParamsWithAmount): Promise<UTXO[]>;
@@ -13,5 +14,6 @@ export interface IProviderForCallResult {
13
14
  readonly utxoManager: IUTXOManagerForCallResult;
14
15
  getChallenge(): Promise<ChallengeSolution>;
15
16
  sendRawTransaction(tx: string, psbt: boolean): Promise<BroadcastedTransaction>;
17
+ sendRawTransactionPackage(txs: string[], isPackage?: boolean): Promise<BroadcastedTransactionPackage>;
16
18
  getCSV1ForAddress(address: Address): IP2WSHAddress;
17
19
  }
package/browser/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { d as decompile, f as fromHex, A as Address, b as fromBase64, N as NetEvent, B as BinaryWriter, c as BinaryReader, e as AddressTypes, h as AddressVerificator, t as toHex, C as ChallengeSolution, r as regtest, o as opnetTestnet, i as testnet, j as bitcoin, T as TransactionFactory, k as BufferHelper, l as AddressMap, m as toBase64, p as pLimit, n as process$1, L as Logger, q as Long, s as abiTypeToSelectorString, u as ABICoder, v as isAbiTuple, w as isAbiStruct, x as ABIDataTypes, y as BigNumber, z as fromBech32, P as P2MR_MS, D as P2TR_MS } from './vendors.js';
2
2
  import { p as protobuf } from './protobuf.js';
3
3
 
4
- const version = "1.8.1";
4
+ const version = "1.8.3";
5
5
 
6
6
  var OPNetTransactionTypes = /* @__PURE__ */ ((OPNetTransactionTypes2) => {
7
7
  OPNetTransactionTypes2["Generic"] = "Generic";
@@ -953,6 +953,19 @@ class TransactionHelper {
953
953
  }
954
954
 
955
955
  const factory = new TransactionFactory();
956
+ function extractPackageFailures(packageResult) {
957
+ const failures = [];
958
+ const results = packageResult.txResults;
959
+ for (const [submittedTxid, result] of Object.entries(results)) {
960
+ if (result.error) {
961
+ failures.push(`tx ${submittedTxid} failed: ${result.error}`);
962
+ }
963
+ }
964
+ if (failures.length === 0 && packageResult.packageMsg !== "success") {
965
+ failures.push(`package rejected: ${packageResult.packageMsg}`);
966
+ }
967
+ return failures;
968
+ }
956
969
  class CallResult {
957
970
  result;
958
971
  accessList;
@@ -1052,6 +1065,13 @@ class CallResult {
1052
1065
  )
1053
1066
  );
1054
1067
  },
1068
+ sendRawTransactionPackage: () => {
1069
+ return Promise.reject(
1070
+ new Error(
1071
+ "Cannot broadcast from offline CallResult. Export signed transaction and broadcast online."
1072
+ )
1073
+ );
1074
+ },
1055
1075
  getCSV1ForAddress: () => {
1056
1076
  if (!data.csvAddress) {
1057
1077
  throw new Error("CSV address not available in offline data");
@@ -1215,43 +1235,69 @@ class CallResult {
1215
1235
  }
1216
1236
  /**
1217
1237
  * Broadcasts a pre-signed interaction transaction.
1238
+ * Uses sendRawTransactionPackage for atomic broadcast when a funding tx is present,
1239
+ * falls back to sendRawTransaction for P2WDA (interaction-only) transactions.
1218
1240
  * @param {SignedInteractionTransactionReceipt} signedTx - The signed transaction data.
1219
1241
  * @returns {Promise<InteractionTransactionReceipt>} The transaction receipt with broadcast results.
1220
1242
  */
1221
1243
  async sendPresignedTransaction(signedTx) {
1222
- if (!signedTx.utxoTracking.isP2WDA) {
1223
- if (!signedTx.fundingTransactionRaw) {
1224
- throw new Error("Funding transaction not created");
1225
- }
1226
- const tx1 = await this.#provider.sendRawTransaction(
1227
- signedTx.fundingTransactionRaw,
1244
+ if (signedTx.utxoTracking.isP2WDA || !signedTx.fundingTransactionRaw) {
1245
+ const tx = await this.#provider.sendRawTransaction(
1246
+ signedTx.interactionTransactionRaw,
1228
1247
  false
1229
1248
  );
1230
- if (!tx1 || tx1.error) {
1231
- throw new Error(`Error sending transaction: ${tx1?.error || "Unknown error"}`);
1249
+ if (!tx || tx.error) {
1250
+ throw new Error(`Error sending transaction: ${tx?.error || "Unknown error"}`);
1251
+ }
1252
+ if (!tx.result) {
1253
+ throw new Error("No transaction ID returned");
1232
1254
  }
1233
- if (!tx1.success) {
1234
- throw new Error(`Error sending transaction: ${tx1.result || "Unknown error"}`);
1255
+ if (!tx.success) {
1256
+ throw new Error(`Error sending transaction: ${tx.result || "Unknown error"}`);
1235
1257
  }
1258
+ this.#processUTXOTracking(signedTx);
1259
+ return {
1260
+ interactionAddress: signedTx.interactionAddress,
1261
+ transactionId: tx.result,
1262
+ peerAcknowledgements: tx.peers || 0,
1263
+ newUTXOs: signedTx.nextUTXOs,
1264
+ estimatedFees: signedTx.estimatedFees,
1265
+ challengeSolution: signedTx.challengeSolution,
1266
+ rawTransaction: signedTx.interactionTransactionRaw,
1267
+ fundingUTXOs: signedTx.fundingUTXOs,
1268
+ fundingInputUtxos: signedTx.fundingInputUtxos,
1269
+ compiledTargetScript: signedTx.compiledTargetScript
1270
+ };
1236
1271
  }
1237
- const tx2 = await this.#provider.sendRawTransaction(
1238
- signedTx.interactionTransactionRaw,
1239
- false
1272
+ const result = await this.#provider.sendRawTransactionPackage(
1273
+ [signedTx.fundingTransactionRaw, signedTx.interactionTransactionRaw],
1274
+ true
1240
1275
  );
1241
- if (!tx2 || tx2.error) {
1242
- throw new Error(`Error sending transaction: ${tx2?.error || "Unknown error"}`);
1276
+ if (!result.success) {
1277
+ throw new Error(
1278
+ `Error sending transaction package: ${result.error || "Unknown error"}`
1279
+ );
1243
1280
  }
1244
- if (!tx2.result) {
1245
- throw new Error("No transaction ID returned");
1281
+ if (result.packageResult) {
1282
+ const failures = extractPackageFailures(result.packageResult);
1283
+ if (failures.length > 0) {
1284
+ throw new Error(`Transaction package failed:
1285
+ ${failures.join("\n")}`);
1286
+ }
1246
1287
  }
1247
- if (!tx2.success) {
1248
- throw new Error(`Error sending transaction: ${tx2.result || "Unknown error"}`);
1288
+ const interactionSeqResult = result.sequentialResults?.[1];
1289
+ if (interactionSeqResult && !interactionSeqResult.success) {
1290
+ throw new Error(
1291
+ `Interaction transaction failed: ${interactionSeqResult.error || "Unknown error"}`
1292
+ );
1249
1293
  }
1294
+ const interactionTxId = interactionSeqResult?.txid || signedTx.interactionTransactionRaw;
1295
+ const peers = interactionSeqResult?.peers || 0;
1250
1296
  this.#processUTXOTracking(signedTx);
1251
1297
  return {
1252
1298
  interactionAddress: signedTx.interactionAddress,
1253
- transactionId: tx2.result,
1254
- peerAcknowledgements: tx2.peers || 0,
1299
+ transactionId: interactionTxId,
1300
+ peerAcknowledgements: peers,
1255
1301
  newUTXOs: signedTx.nextUTXOs,
1256
1302
  estimatedFees: signedTx.estimatedFees,
1257
1303
  challengeSolution: signedTx.challengeSolution,
@@ -1949,6 +1995,7 @@ var JSONRpcMethods = /* @__PURE__ */ ((JSONRpcMethods2) => {
1949
1995
  JSONRpcMethods2["GAS"] = "btc_gas";
1950
1996
  JSONRpcMethods2["GET_TRANSACTION_BY_HASH"] = "btc_getTransactionByHash";
1951
1997
  JSONRpcMethods2["BROADCAST_TRANSACTION"] = "btc_sendRawTransaction";
1998
+ JSONRpcMethods2["BROADCAST_TRANSACTION_PACKAGE"] = "btc_sendRawTransactionPackage";
1952
1999
  JSONRpcMethods2["TRANSACTION_PREIMAGE"] = "btc_preimage";
1953
2000
  JSONRpcMethods2["PUBLIC_KEY_INFO"] = "btc_publicKeyInfo";
1954
2001
  JSONRpcMethods2["GET_UTXOS"] = "btc_getUTXOs";
@@ -1977,7 +2024,7 @@ class UTXOsManager {
1977
2024
  this.provider = provider;
1978
2025
  }
1979
2026
  /**
1980
- * Holds all address-specific data so we dont mix up UTXOs between addresses/wallets.
2027
+ * Holds all address-specific data so we don't mix up UTXOs between addresses/wallets.
1981
2028
  */
1982
2029
  dataByAddress = {};
1983
2030
  /**
@@ -2112,11 +2159,14 @@ class UTXOsManager {
2112
2159
  * Fetch UTXOs for a specific amount needed, from a single address,
2113
2160
  * merging from pending and confirmed UTXOs.
2114
2161
  *
2162
+ * Prioritizes normal UTXOs first, only falling back to CSV UTXOs
2163
+ * if the normal ones cannot cover the requested amount.
2164
+ *
2115
2165
  * @param {object} options
2116
2166
  * @param {string} options.address The address to fetch UTXOs for
2117
2167
  * @param {bigint} options.amount The needed amount
2118
2168
  * @param {boolean} [options.optimize=true] Optimize the UTXOs
2119
- * @param {boolean} [options.csvAddress] Use CSV UTXOs in priority
2169
+ * @param {boolean} [options.csvAddress] Use CSV UTXOs as fallback
2120
2170
  * @param {boolean} [options.mergePendingUTXOs=true] Merge pending
2121
2171
  * @param {boolean} [options.filterSpentUTXOs=true] Filter out spent
2122
2172
  * @param {boolean} [options.throwErrors=false] Throw error if insufficient
@@ -2135,52 +2185,47 @@ class UTXOsManager {
2135
2185
  maxUTXOs = 5e3,
2136
2186
  throwIfUTXOsLimitReached = false
2137
2187
  }) {
2138
- const utxosPromises = [];
2139
- if (csvAddress) {
2140
- utxosPromises.push(
2141
- this.getUTXOs({
2142
- address: csvAddress,
2143
- optimize: true,
2144
- mergePendingUTXOs: false,
2145
- filterSpentUTXOs: true,
2146
- olderThan: 1n,
2147
- isCSV: true
2148
- })
2149
- );
2150
- }
2151
- utxosPromises.push(
2152
- this.getUTXOs({
2153
- address,
2154
- optimize,
2155
- mergePendingUTXOs,
2156
- filterSpentUTXOs,
2157
- olderThan
2158
- })
2159
- );
2160
- const combinedUTXOs = (await Promise.all(utxosPromises)).flat();
2161
- const utxoUntilAmount = [];
2188
+ const selected = [];
2162
2189
  let currentValue = 0n;
2163
- for (const utxo of combinedUTXOs) {
2164
- if (maxUTXOs && utxoUntilAmount.length >= maxUTXOs) {
2165
- if (throwIfUTXOsLimitReached) {
2166
- throw new Error(
2167
- `Woah. You must consolidate your UTXOs (${combinedUTXOs.length})! This transaction is too large.`
2168
- );
2169
- }
2170
- break;
2171
- }
2172
- utxoUntilAmount.push(utxo);
2173
- currentValue += utxo.value;
2174
- if (currentValue >= amount) {
2175
- break;
2176
- }
2190
+ const normalUTXOs = await this.getUTXOs({
2191
+ address,
2192
+ optimize,
2193
+ mergePendingUTXOs,
2194
+ filterSpentUTXOs,
2195
+ olderThan
2196
+ });
2197
+ currentValue = this.selectUTXOsGreedily(
2198
+ normalUTXOs,
2199
+ selected,
2200
+ currentValue,
2201
+ amount,
2202
+ maxUTXOs,
2203
+ throwIfUTXOsLimitReached
2204
+ );
2205
+ if (currentValue < amount && csvAddress) {
2206
+ const csvUTXOs = await this.getUTXOs({
2207
+ address: csvAddress,
2208
+ optimize: true,
2209
+ mergePendingUTXOs: false,
2210
+ filterSpentUTXOs: true,
2211
+ olderThan: 1n,
2212
+ isCSV: true
2213
+ });
2214
+ currentValue = this.selectUTXOsGreedily(
2215
+ csvUTXOs,
2216
+ selected,
2217
+ currentValue,
2218
+ amount,
2219
+ maxUTXOs,
2220
+ throwIfUTXOsLimitReached
2221
+ );
2177
2222
  }
2178
2223
  if (currentValue < amount && throwErrors) {
2179
2224
  throw new Error(
2180
2225
  `Insufficient UTXOs to cover amount. Available: ${currentValue}, Needed: ${amount}`
2181
2226
  );
2182
2227
  }
2183
- return utxoUntilAmount;
2228
+ return selected;
2184
2229
  }
2185
2230
  /**
2186
2231
  * Fetch UTXOs for multiple addresses in a single batch request.
@@ -2254,6 +2299,33 @@ class UTXOsManager {
2254
2299
  }
2255
2300
  return result;
2256
2301
  }
2302
+ /**
2303
+ * Sort UTXOs by value descending and greedily append to `selected` until
2304
+ * `currentValue >= amount` or the pool is exhausted. Mutates `candidates`
2305
+ * (sort in-place) and `selected` (pushes chosen UTXOs). Returns the
2306
+ * updated cumulative value.
2307
+ */
2308
+ selectUTXOsGreedily(candidates, selected, currentValue, amount, maxUTXOs, throwIfLimitReached) {
2309
+ candidates.sort((a, b) => {
2310
+ if (b.value > a.value) return 1;
2311
+ if (b.value < a.value) return -1;
2312
+ return 0;
2313
+ });
2314
+ for (const utxo of candidates) {
2315
+ if (currentValue >= amount) break;
2316
+ if (maxUTXOs && selected.length >= maxUTXOs) {
2317
+ if (throwIfLimitReached) {
2318
+ throw new Error(
2319
+ `Woah. You must consolidate your UTXOs (${candidates.length + selected.length})! This transaction is too large.`
2320
+ );
2321
+ }
2322
+ break;
2323
+ }
2324
+ selected.push(utxo);
2325
+ currentValue += utxo.value;
2326
+ }
2327
+ return currentValue;
2328
+ }
2257
2329
  /**
2258
2330
  * Fetch UTXOs for multiple addresses in a single batch RPC call.
2259
2331
  * @private
@@ -2914,6 +2986,32 @@ class AbstractRpcProvider {
2914
2986
  return rawTx.result;
2915
2987
  });
2916
2988
  }
2989
+ /**
2990
+ * Broadcast a package of raw transactions atomically.
2991
+ * @description Submits an ordered array of raw transactions via Bitcoin Core's submitpackage
2992
+ * RPC for atomic acceptance, or falls back to validated sequential broadcast.
2993
+ * @param {string[]} txs The raw transactions to send as hex strings (max 25)
2994
+ * @param {boolean} [isPackage=true] Whether to use atomic package submission (submitpackage)
2995
+ * or validated sequential broadcast (testmempoolaccept + sendrawtransaction)
2996
+ * @returns {Promise<BroadcastedTransactionPackage>} The result of the package broadcast
2997
+ * @throws {Error} If something went wrong while broadcasting the package
2998
+ */
2999
+ async sendRawTransactionPackage(txs, isPackage = true) {
3000
+ if (!txs.length) {
3001
+ throw new Error("sendRawTransactionPackage: txs array must not be empty");
3002
+ }
3003
+ for (let i = 0; i < txs.length; i++) {
3004
+ if (!/^[0-9A-Fa-f]+$/.test(txs[i])) {
3005
+ throw new Error(`sendRawTransactionPackage: txs[${i}] is not a valid hex string`);
3006
+ }
3007
+ }
3008
+ const payload = this.buildJsonRpcPayload(
3009
+ JSONRpcMethods.BROADCAST_TRANSACTION_PACKAGE,
3010
+ [txs, isPackage]
3011
+ );
3012
+ const result = await this.callPayloadSingle(payload);
3013
+ return result.result;
3014
+ }
2917
3015
  /**
2918
3016
  * Get block witnesses.
2919
3017
  * @description This method is used to get the witnesses of a block. This proves that the actions executed inside a block are valid and confirmed by the network. If the minimum number of witnesses are not met, the block is considered as potentially invalid.
@@ -3965,6 +4063,7 @@ var WebSocketRequestOpcode = /* @__PURE__ */ ((WebSocketRequestOpcode2) => {
3965
4063
  WebSocketRequestOpcode2[WebSocketRequestOpcode2["GET_TRANSACTION_BY_HASH"] = 32] = "GET_TRANSACTION_BY_HASH";
3966
4064
  WebSocketRequestOpcode2[WebSocketRequestOpcode2["GET_TRANSACTION_RECEIPT"] = 33] = "GET_TRANSACTION_RECEIPT";
3967
4065
  WebSocketRequestOpcode2[WebSocketRequestOpcode2["BROADCAST_TRANSACTION"] = 34] = "BROADCAST_TRANSACTION";
4066
+ WebSocketRequestOpcode2[WebSocketRequestOpcode2["BROADCAST_TRANSACTION_PACKAGE"] = 39] = "BROADCAST_TRANSACTION_PACKAGE";
3968
4067
  WebSocketRequestOpcode2[WebSocketRequestOpcode2["GET_PREIMAGE"] = 35] = "GET_PREIMAGE";
3969
4068
  WebSocketRequestOpcode2[WebSocketRequestOpcode2["GET_MEMPOOL_INFO"] = 36] = "GET_MEMPOOL_INFO";
3970
4069
  WebSocketRequestOpcode2[WebSocketRequestOpcode2["GET_PENDING_TRANSACTION"] = 37] = "GET_PENDING_TRANSACTION";
@@ -3999,6 +4098,7 @@ var WebSocketResponseOpcode = /* @__PURE__ */ ((WebSocketResponseOpcode2) => {
3999
4098
  WebSocketResponseOpcode2[WebSocketResponseOpcode2["TRANSACTION"] = 160] = "TRANSACTION";
4000
4099
  WebSocketResponseOpcode2[WebSocketResponseOpcode2["TRANSACTION_RECEIPT"] = 161] = "TRANSACTION_RECEIPT";
4001
4100
  WebSocketResponseOpcode2[WebSocketResponseOpcode2["BROADCAST_RESULT"] = 162] = "BROADCAST_RESULT";
4101
+ WebSocketResponseOpcode2[WebSocketResponseOpcode2["BROADCAST_PACKAGE_RESULT"] = 167] = "BROADCAST_PACKAGE_RESULT";
4002
4102
  WebSocketResponseOpcode2[WebSocketResponseOpcode2["PREIMAGE"] = 163] = "PREIMAGE";
4003
4103
  WebSocketResponseOpcode2[WebSocketResponseOpcode2["MEMPOOL_INFO"] = 164] = "MEMPOOL_INFO";
4004
4104
  WebSocketResponseOpcode2[WebSocketResponseOpcode2["PENDING_TRANSACTION"] = 165] = "PENDING_TRANSACTION";
@@ -4077,6 +4177,12 @@ const METHOD_MAPPINGS = {
4077
4177
  requestType: "BroadcastTransactionRequest",
4078
4178
  responseType: "BroadcastTransactionResponse"
4079
4179
  },
4180
+ [JSONRpcMethods.BROADCAST_TRANSACTION_PACKAGE]: {
4181
+ requestOpcode: WebSocketRequestOpcode.BROADCAST_TRANSACTION_PACKAGE,
4182
+ responseOpcode: WebSocketResponseOpcode.BROADCAST_PACKAGE_RESULT,
4183
+ requestType: "BroadcastTransactionPackageRequest",
4184
+ responseType: "BroadcastTransactionPackageResponse"
4185
+ },
4080
4186
  [JSONRpcMethods.TRANSACTION_PREIMAGE]: {
4081
4187
  requestOpcode: WebSocketRequestOpcode.GET_PREIMAGE,
4082
4188
  responseOpcode: WebSocketResponseOpcode.PREIMAGE,
@@ -4724,6 +4830,11 @@ class WebSocketRpcProvider extends AbstractRpcProvider {
4724
4830
  2: params[0],
4725
4831
  3: params[1] ?? false
4726
4832
  };
4833
+ case JSONRpcMethods.BROADCAST_TRANSACTION_PACKAGE:
4834
+ return {
4835
+ 2: params[0],
4836
+ 3: params[1] ?? true
4837
+ };
4727
4838
  case JSONRpcMethods.TRANSACTION_PREIMAGE:
4728
4839
  return {};
4729
4840
  case JSONRpcMethods.GET_BALANCE:
@@ -70,6 +70,7 @@ export * from './storage/interfaces/IStorageValue.js';
70
70
  export * from './storage/StoredValue.js';
71
71
  export * from './contracts/interfaces/IRawContract.js';
72
72
  export * from './transactions/interfaces/BroadcastedTransaction.js';
73
+ export * from './transactions/interfaces/BroadcastedTransactionPackage.js';
73
74
  export * from './transactions/interfaces/ITransaction.js';
74
75
  export * from './transactions/interfaces/ITransactionReceipt.js';
75
76
  export * from './transactions/metadata/TransactionReceipt.js';
@@ -18,6 +18,7 @@ import { OPNetTransactionTypes } from '../interfaces/opnet/OPNetTransactionTypes
18
18
  import { MempoolTransactionData } from '../mempool/MempoolTransactionData.js';
19
19
  import { StoredValue } from '../storage/StoredValue.js';
20
20
  import { BroadcastedTransaction } from '../transactions/interfaces/BroadcastedTransaction.js';
21
+ import { BroadcastedTransactionPackage } from '../transactions/interfaces/BroadcastedTransactionPackage.js';
21
22
  import { TransactionReceipt } from '../transactions/metadata/TransactionReceipt.js';
22
23
  import { TransactionBase } from '../transactions/Transaction.js';
23
24
  import { UTXOsManager } from '../utxos/UTXOsManager.js';
@@ -59,6 +60,7 @@ export declare abstract class AbstractRpcProvider {
59
60
  gasParameters(): Promise<BlockGasParameters>;
60
61
  sendRawTransaction(tx: string, psbt: boolean): Promise<BroadcastedTransaction>;
61
62
  sendRawTransactions(txs: string[]): Promise<BroadcastedTransaction[]>;
63
+ sendRawTransactionPackage(txs: string[], isPackage?: boolean): Promise<BroadcastedTransactionPackage>;
62
64
  getBlockWitness(height?: BigNumberish, trusted?: boolean, limit?: number, page?: number): Promise<BlockWitnesses>;
63
65
  getReorg(fromBlock?: BigNumberish, toBlock?: BigNumberish): Promise<ReorgInformation[]>;
64
66
  abstract _send(payload: JsonRpcPayload | JsonRpcPayload[]): Promise<JsonRpcCallResult>;
@@ -8,6 +8,7 @@ export declare enum JSONRpcMethods {
8
8
  GAS = "btc_gas",
9
9
  GET_TRANSACTION_BY_HASH = "btc_getTransactionByHash",
10
10
  BROADCAST_TRANSACTION = "btc_sendRawTransaction",
11
+ BROADCAST_TRANSACTION_PACKAGE = "btc_sendRawTransactionPackage",
11
12
  TRANSACTION_PREIMAGE = "btc_preimage",
12
13
  PUBLIC_KEY_INFO = "btc_publicKeyInfo",
13
14
  GET_UTXOS = "btc_getUTXOs",
@@ -10,6 +10,7 @@ export declare enum WebSocketRequestOpcode {
10
10
  GET_TRANSACTION_BY_HASH = 32,
11
11
  GET_TRANSACTION_RECEIPT = 33,
12
12
  BROADCAST_TRANSACTION = 34,
13
+ BROADCAST_TRANSACTION_PACKAGE = 39,
13
14
  GET_PREIMAGE = 35,
14
15
  GET_MEMPOOL_INFO = 36,
15
16
  GET_PENDING_TRANSACTION = 37,
@@ -43,6 +44,7 @@ export declare enum WebSocketResponseOpcode {
43
44
  TRANSACTION = 160,
44
45
  TRANSACTION_RECEIPT = 161,
45
46
  BROADCAST_RESULT = 162,
47
+ BROADCAST_PACKAGE_RESULT = 167,
46
48
  PREIMAGE = 163,
47
49
  MEMPOOL_INFO = 164,
48
50
  PENDING_TRANSACTION = 165,
@@ -0,0 +1,48 @@
1
+ export interface SequentialBroadcastTxResult {
2
+ readonly txid: string;
3
+ readonly success: boolean;
4
+ readonly error?: string;
5
+ readonly peers?: number;
6
+ }
7
+ export interface BroadcastedTransactionPackage {
8
+ readonly success: boolean;
9
+ readonly error?: string;
10
+ readonly testResults?: readonly TestMempoolAcceptResult[];
11
+ readonly packageResult?: PackageResult;
12
+ readonly sequentialResults?: readonly SequentialBroadcastTxResult[];
13
+ readonly fellBackToSequential?: boolean;
14
+ }
15
+ export interface TestMempoolAcceptResult {
16
+ readonly txid: string;
17
+ readonly wtxid: string;
18
+ readonly allowed?: boolean;
19
+ readonly vsize?: number;
20
+ readonly packageError?: string;
21
+ readonly rejectReason?: string;
22
+ readonly rejectDetails?: string;
23
+ readonly fees?: TestMempoolAcceptFees;
24
+ }
25
+ export interface TestMempoolAcceptFees {
26
+ readonly base: number;
27
+ readonly effectiveFeerate: number;
28
+ readonly effectiveIncludes: readonly string[];
29
+ }
30
+ export interface PackageTxResult {
31
+ readonly txid: string;
32
+ readonly otherWtxid?: string;
33
+ readonly vsize?: number;
34
+ readonly fees?: PackageTxFees;
35
+ readonly error?: string;
36
+ }
37
+ export interface PackageTxFees {
38
+ readonly base: number;
39
+ readonly effectiveFeerate?: number;
40
+ readonly effectiveIncludes?: readonly string[];
41
+ }
42
+ export interface PackageResult {
43
+ readonly packageMsg: string;
44
+ readonly txResults: {
45
+ readonly [wtxid: string]: PackageTxResult;
46
+ };
47
+ readonly replacedTransactions?: readonly string[];
48
+ }
@@ -11,6 +11,7 @@ export declare class UTXOsManager {
11
11
  getUTXOs({ address, isCSV, optimize, mergePendingUTXOs, filterSpentUTXOs, olderThan, }: RequestUTXOsParams): Promise<UTXOs>;
12
12
  getUTXOsForAmount({ address, amount, csvAddress, optimize, mergePendingUTXOs, filterSpentUTXOs, throwErrors, olderThan, maxUTXOs, throwIfUTXOsLimitReached, }: RequestUTXOsParamsWithAmount): Promise<UTXOs>;
13
13
  getMultipleUTXOs({ requests, mergePendingUTXOs, filterSpentUTXOs, }: RequestMultipleUTXOsParams): Promise<Record<string, UTXOs>>;
14
+ private selectUTXOsGreedily;
14
15
  private fetchMultipleUTXOs;
15
16
  private getAddressData;
16
17
  private maybeFetchUTXOs;
@@ -1 +1 @@
1
- export declare const version = "1.8.1";
1
+ export declare const version = "1.8.3";
package/build/_version.js CHANGED
@@ -1 +1 @@
1
- export const version = '1.8.1';
1
+ export const version = '1.8.3';