cashscript 0.13.0-next.6 → 0.13.0-next.7

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.
@@ -6,7 +6,19 @@ import { debugLibauthTemplate, getLibauthTemplate, getBitauthUri } from './libau
6
6
  import { getWcContractInfo } from './walletconnect-utils.js';
7
7
  import semver from 'semver';
8
8
  const DEFAULT_SEQUENCE = 0xfffffffe;
9
+ /**
10
+ * Fluent builder for constructing, debugging, and broadcasting CashScript transactions.
11
+ *
12
+ * Inputs are added via `addInput` / `addInputs` with an `Unlocker` produced by a `Contract` or
13
+ * `SignatureTemplate`, outputs are added via `addOutput` / `addOutputs`, and the resulting
14
+ * transaction can be built (`build`), debugged (`debug`), or broadcast (`send`).
15
+ */
9
16
  export class TransactionBuilder {
17
+ /**
18
+ * Create a new TransactionBuilder.
19
+ *
20
+ * @param options - Builder options, including the network provider and optional fee/burn limits.
21
+ */
10
22
  constructor(options) {
11
23
  this.inputs = [];
12
24
  this.outputs = [];
@@ -17,6 +29,16 @@ export class TransactionBuilder {
17
29
  ...options,
18
30
  };
19
31
  }
32
+ /**
33
+ * Add a single UTXO as an input to the transaction.
34
+ *
35
+ * @param utxo - The UTXO to spend.
36
+ * @param unlocker - The unlocker to generate the unlocking bytecode for this input. Typically
37
+ * obtained from `contract.unlock.<functionName>(...args)` or `signatureTemplate.unlockP2PKH()`.
38
+ * @param options - Optional per-input options such as a custom sequence number.
39
+ * @returns This builder for chaining.
40
+ * @throws If the UTXO is invalid.
41
+ */
20
42
  addInput(utxo, unlocker, options) {
21
43
  return this.addInputs([utxo], unlocker, options);
22
44
  }
@@ -33,19 +55,50 @@ export class TransactionBuilder {
33
55
  this.inputs = this.inputs.concat(utxos.map(((utxo) => ({ ...utxo, unlocker, options }))));
34
56
  return this;
35
57
  }
58
+ /**
59
+ * Add a single output to the transaction.
60
+ *
61
+ * @param output - The output to add. Its address, amount and optional token are validated
62
+ * against the provider's network.
63
+ * @returns This builder for chaining.
64
+ * @throws If the output is invalid.
65
+ */
36
66
  addOutput(output) {
37
67
  return this.addOutputs([output]);
38
68
  }
69
+ /**
70
+ * Add multiple outputs to the transaction.
71
+ *
72
+ * @param outputs - The outputs to add. Each output is validated against the provider's network.
73
+ * @returns This builder for chaining.
74
+ * @throws If any output is invalid.
75
+ */
39
76
  addOutputs(outputs) {
40
- outputs.forEach(validateOutput);
77
+ outputs.forEach((output) => validateOutput(output, this.provider.network));
41
78
  this.outputs = this.outputs.concat(outputs);
42
79
  return this;
43
80
  }
44
81
  // TODO: allow uint8array for chunks
82
+ /**
83
+ * Append an `OP_RETURN` output containing the provided data chunks. Hex strings prefixed with
84
+ * `0x` are decoded as bytes; other strings are encoded as UTF-8.
85
+ *
86
+ * @param chunks - The data chunks to include after the `OP_RETURN` opcode.
87
+ * @returns This builder for chaining.
88
+ */
45
89
  addOpReturnOutput(chunks) {
46
90
  this.outputs.push(createOpReturnOutput(chunks));
47
91
  return this;
48
92
  }
93
+ /**
94
+ * Add a BCH change output for the remaining value after fees, if it exceeds the dust limit. The
95
+ * fee is computed from the transaction size at the configured fee rate; dust-sized change is
96
+ * simply absorbed into the fee.
97
+ *
98
+ * @param changeOutputOptions - The destination address and the fee rate (in sats/byte) to use.
99
+ * @returns This builder for chaining.
100
+ * @throws If the available surplus is insufficient to cover the fee for the configured rate.
101
+ */
49
102
  addBchChangeOutputIfNeeded(changeOutputOptions) {
50
103
  const totalBchInputAmount = this.inputs.reduce((total, input) => total + input.satoshis, 0n);
51
104
  const totalBchOutputAmount = this.outputs.reduce((total, output) => total + output.amount, 0n);
@@ -71,10 +124,21 @@ export class TransactionBuilder {
71
124
  this.outputs.push(changeOutput);
72
125
  return this;
73
126
  }
127
+ /**
128
+ * Build the transaction (skipping fee and burn checks) and return its encoded byte length.
129
+ *
130
+ * @returns The size of the transaction in bytes.
131
+ */
74
132
  getTransactionSize() {
75
133
  const transaction = this.buildLibauthTransaction(true);
76
134
  return BigInt(encodeTransaction(transaction).byteLength);
77
135
  }
136
+ /**
137
+ * Set the `nLockTime` of the transaction.
138
+ *
139
+ * @param locktime - The absolute locktime to use (block height or UNIX timestamp).
140
+ * @returns This builder for chaining.
141
+ */
78
142
  setLocktime(locktime) {
79
143
  this.locktime = locktime;
80
144
  return this;
@@ -144,10 +208,26 @@ export class TransactionBuilder {
144
208
  }
145
209
  return transaction;
146
210
  }
211
+ /**
212
+ * Build the transaction, applying fee and implicit-burn checks, and return the hex-encoded
213
+ * transaction bytes.
214
+ *
215
+ * @returns The signed transaction as a hex string.
216
+ * @throws If the transaction fee exceeds the configured maximum, or if fungible tokens are
217
+ * implicitly burned without `allowImplicitFungibleTokenBurn` enabled.
218
+ */
147
219
  build() {
148
220
  const transaction = this.buildLibauthTransaction();
149
221
  return binToHex(encodeTransaction(transaction));
150
222
  }
223
+ /**
224
+ * Locally evaluate the transaction against the Bitcoin Cash VM using debug information from the
225
+ * contract artifacts. Throws a descriptive error if any input fails evaluation.
226
+ *
227
+ * @returns The full debug execution trace for every scenario in the generated libauth template.
228
+ * @throws If the transaction contains inputs with custom (non-standard) unlockers, or if the
229
+ * evaluation fails (e.g. a failing `require` statement).
230
+ */
151
231
  debug() {
152
232
  if (this.inputs.some((input) => !isStandardUnlockableUtxo(input))) {
153
233
  throw new Error('Cannot debug a transaction with custom unlocker');
@@ -161,6 +241,15 @@ export class TransactionBuilder {
161
241
  }
162
242
  return debugLibauthTemplate(this.getLibauthTemplate(), this);
163
243
  }
244
+ /**
245
+ * Compute VM resource usage (ops, op cost budget, sigchecks, hash iterations) for each input
246
+ * by running the transaction through `debug`.
247
+ *
248
+ * @param verbose - When `true`, also prints a formatted table of the results via `console.table`.
249
+ * @returns One entry per input with its VM resource usage metrics.
250
+ * @throws If the transaction contains inputs with custom (non-standard) unlockers, or if the
251
+ * evaluation fails.
252
+ */
164
253
  getVmResourceUsage(verbose = false) {
165
254
  // Note that only StandardUnlockableUtxo inputs are supported for debugging, so any transaction with custom unlockers
166
255
  // cannot be debugged (and therefore cannot return VM resource usage)
@@ -191,10 +280,27 @@ export class TransactionBuilder {
191
280
  }
192
281
  return vmResourceUsage;
193
282
  }
283
+ /**
284
+ * Build a Bitauth IDE URI that loads the transaction (and all private keys required to sign it)
285
+ * in the online Bitauth IDE debugger.
286
+ *
287
+ * WARNING: The URI embeds every private key used in the transaction. Do not share this URI if
288
+ * the transaction is signed with real private keys.
289
+ *
290
+ * @returns A Bitauth IDE URL for debugging this transaction.
291
+ * @throws If the transaction cannot be built (fee exceeds limit or fungible tokens burned).
292
+ */
194
293
  getBitauthUri() {
195
294
  console.warn('WARNING: it is unsafe to use this Bitauth URI when using real private keys as they are included in the transaction template');
196
295
  return getBitauthUri(this.getLibauthTemplate());
197
296
  }
297
+ /**
298
+ * Build the transaction and return the corresponding libauth `WalletTemplate`. Useful for
299
+ * exporting the transaction to external libauth-compatible tooling.
300
+ *
301
+ * @returns A libauth `WalletTemplate` describing this transaction.
302
+ * @throws If the transaction cannot be built (fee exceeds limit or fungible tokens burned).
303
+ */
198
304
  getLibauthTemplate() {
199
305
  const libauthTransaction = this.buildLibauthTransaction();
200
306
  return getLibauthTemplate(this, libauthTransaction);
@@ -212,7 +318,7 @@ export class TransactionBuilder {
212
318
  }
213
319
  catch (e) {
214
320
  const reason = e.error ?? e.message;
215
- throw new FailedTransactionError(reason, this.getBitauthUri());
321
+ throw new FailedTransactionError(reason, getBitauthUri(this.getLibauthTemplate()));
216
322
  }
217
323
  }
218
324
  async getTxDetails(txid, raw) {
@@ -232,6 +338,16 @@ export class TransactionBuilder {
232
338
  // Should not happen
233
339
  throw new Error('Could not retrieve transaction details for over 10 minutes');
234
340
  }
341
+ /**
342
+ * Build the transaction and format it as a BCH WalletConnect transaction object suitable for
343
+ * signing and broadcasting via a BCH WalletConnect-compatible Bitcoin Cash wallet.
344
+ *
345
+ * See the [BCH WalletConnect spec](https://github.com/mainnet-pat/wc2-bch-bcr) for the object format.
346
+ *
347
+ * @param options - Optional WalletConnect options such as `broadcast` and `userPrompt`.
348
+ * @returns A WalletConnect transaction object ready to be sent to a WalletConnect wallet.
349
+ * @throws If the transaction cannot be built (fee exceeds limit or fungible tokens burned).
350
+ */
235
351
  generateWcTransactionObject(options) {
236
352
  const encodedTransaction = this.build();
237
353
  const transaction = decodeTransactionUnsafe(hexToBin(encodedTransaction));
package/dist/index.d.ts CHANGED
@@ -6,7 +6,8 @@ export type { Artifact, AbiFunction, AbiInput } from '@cashscript/utils';
6
6
  export * as utils from '@cashscript/utils';
7
7
  export * from './interfaces.js';
8
8
  export * from './Errors.js';
9
- export { type NetworkProvider, BitcoinRpcNetworkProvider, ElectrumNetworkProvider, FullStackNetworkProvider, MockNetworkProvider, } from './network/index.js';
9
+ export * from './network/errors.js';
10
+ export { type NetworkProvider, ElectrumNetworkProvider, MockNetworkProvider, } from './network/index.js';
10
11
  export { randomUtxo, randomToken, randomNFT } from './utils.js';
11
12
  export * from './walletconnect-utils.js';
12
13
  export { gatherBchUtxos, gatherFungibleTokenUtxos, type GatherUtxosResult } from './transaction-utils.js';
package/dist/index.js CHANGED
@@ -5,7 +5,8 @@ export { encodeFunctionArgument, } from './Argument.js';
5
5
  export * as utils from '@cashscript/utils';
6
6
  export * from './interfaces.js';
7
7
  export * from './Errors.js';
8
- export { BitcoinRpcNetworkProvider, ElectrumNetworkProvider, FullStackNetworkProvider, MockNetworkProvider, } from './network/index.js';
8
+ export * from './network/errors.js';
9
+ export { ElectrumNetworkProvider, MockNetworkProvider, } from './network/index.js';
9
10
  export { randomUtxo, randomToken, randomNFT } from './utils.js';
10
11
  export * from './walletconnect-utils.js';
11
12
  export { gatherBchUtxos, gatherFungibleTokenUtxos } from './transaction-utils.js';
@@ -11,11 +11,23 @@ interface CustomElectrumOptions extends OptionsBase {
11
11
  electrum: ElectrumClient<ElectrumClientEvents>;
12
12
  }
13
13
  type Options = OptionsBase | CustomHostNameOptions | CustomElectrumOptions;
14
+ /**
15
+ * A `NetworkProvider` implementation backed by an Electrum Cash server. By default it manages
16
+ * its own connection lifecycle, connecting on demand and disconnecting when idle; for long-lived
17
+ * clients, pass `manualConnectionManagement: true` and call `connect` / `disconnect` explicitly.
18
+ */
14
19
  export default class ElectrumNetworkProvider implements NetworkProvider {
15
20
  network: Network;
16
21
  private electrum;
17
22
  private concurrentRequests;
18
23
  private manualConnectionManagement;
24
+ /**
25
+ * Create a new ElectrumNetworkProvider.
26
+ *
27
+ * @param network - The BCH network to connect to. Defaults to `Network.MAINNET`.
28
+ * @param options - Optional hostname, pre-configured `ElectrumClient`, and/or
29
+ * `manualConnectionManagement` flag.
30
+ */
19
31
  constructor(network?: Network, options?: Options);
20
32
  private instantiateElectrumClient;
21
33
  private getServerForNetwork;
@@ -24,8 +36,29 @@ export default class ElectrumNetworkProvider implements NetworkProvider {
24
36
  getBlockHeight(): Promise<number>;
25
37
  getRawTransaction(txid: string): Promise<string>;
26
38
  sendRawTransaction(txHex: string): Promise<string>;
39
+ /**
40
+ * Manually open the underlying Electrum connection. Only allowed when the provider was created
41
+ * with `manualConnectionManagement: true`.
42
+ *
43
+ * @throws If manual connection management is disabled.
44
+ */
27
45
  connect(): Promise<void>;
46
+ /**
47
+ * Manually close the underlying Electrum connection. Only allowed when the provider was created
48
+ * with `manualConnectionManagement: true`.
49
+ *
50
+ * @throws If manual connection management is disabled.
51
+ * @returns Whether the connection was disconnected successfully.
52
+ */
28
53
  disconnect(): Promise<boolean>;
54
+ /**
55
+ * Perform an arbitrary Electrum JSON-RPC request against the underlying server. Automatically
56
+ * manages the connection lifecycle unless `manualConnectionManagement` was set.
57
+ *
58
+ * @param name - The Electrum method name (e.g. `blockchain.transaction.get`).
59
+ * @param parameters - Parameters passed to the method.
60
+ * @returns The raw Electrum server response.
61
+ */
29
62
  performRequest(name: string, ...parameters: (string | number | boolean)[]): Promise<RequestResponse>;
30
63
  private shouldConnect;
31
64
  private shouldDisconnect;
@@ -3,7 +3,20 @@ import { sha256 } from '@cashscript/utils';
3
3
  import { ElectrumClient, } from '@electrum-cash/network';
4
4
  import { Network } from '../interfaces.js';
5
5
  import { addressToLockScript } from '../utils.js';
6
+ import { NetworkProviderMissingInputsError, NetworkProviderMempoolConflictError, NetworkProviderTransactionAlreadySubmittedError, NetworkProviderAbsoluteTimelockError, NetworkProviderRelativeTimelockError, } from './errors.js';
7
+ /**
8
+ * A `NetworkProvider` implementation backed by an Electrum Cash server. By default it manages
9
+ * its own connection lifecycle, connecting on demand and disconnecting when idle; for long-lived
10
+ * clients, pass `manualConnectionManagement: true` and call `connect` / `disconnect` explicitly.
11
+ */
6
12
  export default class ElectrumNetworkProvider {
13
+ /**
14
+ * Create a new ElectrumNetworkProvider.
15
+ *
16
+ * @param network - The BCH network to connect to. Defaults to `Network.MAINNET`.
17
+ * @param options - Optional hostname, pre-configured `ElectrumClient`, and/or
18
+ * `manualConnectionManagement` flag.
19
+ */
7
20
  constructor(network = Network.MAINNET, options = {}) {
8
21
  this.network = network;
9
22
  this.concurrentRequests = 0;
@@ -62,20 +75,47 @@ export default class ElectrumNetworkProvider {
62
75
  return await this.performRequest('blockchain.transaction.get', txid);
63
76
  }
64
77
  async sendRawTransaction(txHex) {
65
- return await this.performRequest('blockchain.transaction.broadcast', txHex);
78
+ try {
79
+ return await this.performRequest('blockchain.transaction.broadcast', txHex);
80
+ }
81
+ catch (e) {
82
+ const errorMessage = e.message ?? String(e);
83
+ throw classifyNetworkProviderError(errorMessage);
84
+ }
66
85
  }
86
+ /**
87
+ * Manually open the underlying Electrum connection. Only allowed when the provider was created
88
+ * with `manualConnectionManagement: true`.
89
+ *
90
+ * @throws If manual connection management is disabled.
91
+ */
67
92
  async connect() {
68
93
  if (!this.manualConnectionManagement) {
69
94
  throw new Error('Manual connection management is disabled');
70
95
  }
71
96
  return this.electrum.connect();
72
97
  }
98
+ /**
99
+ * Manually close the underlying Electrum connection. Only allowed when the provider was created
100
+ * with `manualConnectionManagement: true`.
101
+ *
102
+ * @throws If manual connection management is disabled.
103
+ * @returns Whether the connection was disconnected successfully.
104
+ */
73
105
  async disconnect() {
74
106
  if (!this.manualConnectionManagement) {
75
107
  throw new Error('Manual connection management is disabled');
76
108
  }
77
109
  return this.electrum.disconnect();
78
110
  }
111
+ /**
112
+ * Perform an arbitrary Electrum JSON-RPC request against the underlying server. Automatically
113
+ * manages the connection lifecycle unless `manualConnectionManagement` was set.
114
+ *
115
+ * @param name - The Electrum method name (e.g. `blockchain.transaction.get`).
116
+ * @param parameters - Parameters passed to the method.
117
+ * @returns The raw Electrum server response.
118
+ */
79
119
  async performRequest(name, ...parameters) {
80
120
  // Only connect the electrum client when no concurrent requests are running
81
121
  if (this.shouldConnect()) {
@@ -113,6 +153,43 @@ export default class ElectrumNetworkProvider {
113
153
  return true;
114
154
  }
115
155
  }
156
+ const MISSING_INPUTS_PATTERNS = [
157
+ 'Missing inputs',
158
+ 'bad-txns-inputs-missingorspent',
159
+ 'bad-txns-inputs-spent',
160
+ ];
161
+ const MEMPOOL_CONFLICT_PATTERNS = [
162
+ 'txn-mempool-conflict',
163
+ ];
164
+ const ALREADY_SUBMITTED_PATTERNS = [
165
+ 'transaction already in block chain',
166
+ 'txn-already-known',
167
+ 'txn-already-in-mempool',
168
+ ];
169
+ const ABSOLUTE_TIMELOCK_PATTERNS = [
170
+ 'bad-txns-nonfinal',
171
+ ];
172
+ const RELATIVE_TIMELOCK_PATTERNS = [
173
+ 'non-BIP68-final',
174
+ ];
175
+ function classifyNetworkProviderError(errorMessage) {
176
+ if (MISSING_INPUTS_PATTERNS.some((pattern) => errorMessage.includes(pattern))) {
177
+ return new NetworkProviderMissingInputsError(errorMessage);
178
+ }
179
+ if (MEMPOOL_CONFLICT_PATTERNS.some((pattern) => errorMessage.includes(pattern))) {
180
+ return new NetworkProviderMempoolConflictError(errorMessage);
181
+ }
182
+ if (ALREADY_SUBMITTED_PATTERNS.some((pattern) => errorMessage.includes(pattern))) {
183
+ return new NetworkProviderTransactionAlreadySubmittedError(errorMessage);
184
+ }
185
+ if (ABSOLUTE_TIMELOCK_PATTERNS.some((pattern) => errorMessage.includes(pattern))) {
186
+ return new NetworkProviderAbsoluteTimelockError(errorMessage);
187
+ }
188
+ if (RELATIVE_TIMELOCK_PATTERNS.some((pattern) => errorMessage.includes(pattern))) {
189
+ return new NetworkProviderRelativeTimelockError(errorMessage);
190
+ }
191
+ return new Error(errorMessage);
192
+ }
116
193
  function lockingBytecodeToElectrumScriptHash(lockingBytecode) {
117
194
  const scriptHash = sha256(lockingBytecode);
118
195
  scriptHash.reverse();
@@ -1,9 +1,23 @@
1
1
  import { Utxo, Network, VmTarget } from '../interfaces.js';
2
2
  import NetworkProvider from './NetworkProvider.js';
3
+ /**
4
+ * Options accepted by the `MockNetworkProvider` constructor.
5
+ */
3
6
  export interface MockNetworkProviderOptions {
7
+ /**
8
+ * When `true` (default), broadcasting a transaction via `sendRawTransaction` updates the
9
+ * in-memory UTXO set: input UTXOs are removed and output UTXOs are added. Set to `false` to
10
+ * keep the UTXO set static.
11
+ */
4
12
  updateUtxoSet?: boolean;
13
+ /** The BCH VM target used for local debugging. Defaults to the current stable VM. */
5
14
  vmTarget?: VmTarget;
6
15
  }
16
+ /**
17
+ * An in-memory `NetworkProvider` useful for tests and examples. It does not connect to any
18
+ * external server; instead UTXOs are manually added via `addUtxo` and transactions are tracked
19
+ * in memory.
20
+ */
7
21
  export default class MockNetworkProvider implements NetworkProvider {
8
22
  private utxoSet;
9
23
  private transactionMap;
@@ -11,13 +25,34 @@ export default class MockNetworkProvider implements NetworkProvider {
11
25
  network: Network;
12
26
  options: MockNetworkProviderOptions;
13
27
  vmTarget: VmTarget;
28
+ /**
29
+ * Create a new MockNetworkProvider.
30
+ *
31
+ * @param options - Optional settings controlling UTXO-set updating and the VM target used by
32
+ * `TransactionBuilder.debug`.
33
+ */
14
34
  constructor(options?: Partial<MockNetworkProviderOptions>);
15
35
  getUtxos(address: string): Promise<Utxo[]>;
16
36
  getUtxosForLockingBytecode(lockingBytecode: Uint8Array | string): Promise<Utxo[]>;
37
+ /**
38
+ * Override the current block height returned by `getBlockHeight`.
39
+ *
40
+ * @param newBlockHeight - The block height to report for subsequent queries.
41
+ */
17
42
  setBlockHeight(newBlockHeight: number): void;
18
43
  getBlockHeight(): Promise<number>;
19
44
  getRawTransaction(txid: string): Promise<string>;
20
45
  sendRawTransaction(txHex: string): Promise<string>;
46
+ /**
47
+ * Add a UTXO to the in-memory set so that it becomes spendable by the specified address or
48
+ * locking bytecode.
49
+ *
50
+ * @param addressOrLockingBytecode - Either a CashAddress or a hex-encoded locking bytecode.
51
+ * @param utxo - The UTXO to make spendable.
52
+ */
21
53
  addUtxo(addressOrLockingBytecode: string, utxo: Utxo): void;
54
+ /**
55
+ * Clear the in-memory UTXO set and transaction history. Block height is preserved.
56
+ */
22
57
  reset(): void;
23
58
  }
@@ -3,7 +3,18 @@ import { sha256 } from '@cashscript/utils';
3
3
  import { Network } from '../interfaces.js';
4
4
  import { addressToLockScript, libauthTokenDetailsToCashScriptTokenDetails } from '../utils.js';
5
5
  import { DEFAULT_VM_TARGET } from '../libauth-template/utils.js';
6
+ /**
7
+ * An in-memory `NetworkProvider` useful for tests and examples. It does not connect to any
8
+ * external server; instead UTXOs are manually added via `addUtxo` and transactions are tracked
9
+ * in memory.
10
+ */
6
11
  export default class MockNetworkProvider {
12
+ /**
13
+ * Create a new MockNetworkProvider.
14
+ *
15
+ * @param options - Optional settings controlling UTXO-set updating and the VM target used by
16
+ * `TransactionBuilder.debug`.
17
+ */
7
18
  constructor(options) {
8
19
  // we use lockingBytecode hex as the key for utxoMap to make cash addresses and token addresses interchangeable
9
20
  this.utxoSet = [];
@@ -21,6 +32,11 @@ export default class MockNetworkProvider {
21
32
  const lockingBytecodeHex = typeof lockingBytecode === 'string' ? lockingBytecode : binToHex(lockingBytecode);
22
33
  return this.utxoSet.filter(([key]) => key === lockingBytecodeHex).map(([, utxo]) => utxo);
23
34
  }
35
+ /**
36
+ * Override the current block height returned by `getBlockHeight`.
37
+ *
38
+ * @param newBlockHeight - The block height to report for subsequent queries.
39
+ */
24
40
  setBlockHeight(newBlockHeight) {
25
41
  this.blockHeight = newBlockHeight;
26
42
  }
@@ -62,11 +78,21 @@ export default class MockNetworkProvider {
62
78
  // Note: the user can technically add the same UTXO multiple times (txid + vout), to the same or different addresses
63
79
  // but we don't check for this in the sendRawTransaction method. We might want to prevent duplicates from being added
64
80
  // in the first place.
81
+ /**
82
+ * Add a UTXO to the in-memory set so that it becomes spendable by the specified address or
83
+ * locking bytecode.
84
+ *
85
+ * @param addressOrLockingBytecode - Either a CashAddress or a hex-encoded locking bytecode.
86
+ * @param utxo - The UTXO to make spendable.
87
+ */
65
88
  addUtxo(addressOrLockingBytecode, utxo) {
66
89
  const lockingBytecode = isHex(addressOrLockingBytecode) ?
67
90
  addressOrLockingBytecode : binToHex(addressToLockScript(addressOrLockingBytecode));
68
91
  this.utxoSet.push([lockingBytecode, utxo]);
69
92
  }
93
+ /**
94
+ * Clear the in-memory UTXO set and transaction history. Block height is preserved.
95
+ */
70
96
  reset() {
71
97
  this.utxoSet = [];
72
98
  this.transactionMap = {};
@@ -0,0 +1,19 @@
1
+ export declare class NetworkProviderError extends Error {
2
+ originalError: string;
3
+ constructor(message: string, originalError: string);
4
+ }
5
+ export declare class NetworkProviderMissingInputsError extends NetworkProviderError {
6
+ constructor(originalError: string);
7
+ }
8
+ export declare class NetworkProviderMempoolConflictError extends NetworkProviderError {
9
+ constructor(originalError: string);
10
+ }
11
+ export declare class NetworkProviderTransactionAlreadySubmittedError extends NetworkProviderError {
12
+ constructor(originalError: string);
13
+ }
14
+ export declare class NetworkProviderAbsoluteTimelockError extends NetworkProviderError {
15
+ constructor(originalError: string);
16
+ }
17
+ export declare class NetworkProviderRelativeTimelockError extends NetworkProviderError {
18
+ constructor(originalError: string);
19
+ }
@@ -0,0 +1,38 @@
1
+ // Base class for errors returned by a network provider when broadcasting a transaction.
2
+ export class NetworkProviderError extends Error {
3
+ constructor(message, originalError) {
4
+ super(message);
5
+ this.originalError = originalError;
6
+ }
7
+ }
8
+ // Thrown when one or more inputs reference UTXOs that are missing or already spent.
9
+ export class NetworkProviderMissingInputsError extends NetworkProviderError {
10
+ constructor(originalError) {
11
+ super(`Transaction inputs are missing or already spent: ${originalError}`, originalError);
12
+ }
13
+ }
14
+ // Thrown when an input is already being spent by another transaction in the mempool (double-spend).
15
+ export class NetworkProviderMempoolConflictError extends NetworkProviderError {
16
+ constructor(originalError) {
17
+ super(`Transaction conflicts with an unconfirmed transaction in the mempool: ${originalError}`, originalError);
18
+ }
19
+ }
20
+ // Thrown when the same transaction has already been submitted (already in mempool or confirmed).
21
+ export class NetworkProviderTransactionAlreadySubmittedError extends NetworkProviderError {
22
+ constructor(originalError) {
23
+ super(`Transaction has already been submitted: ${originalError}`, originalError);
24
+ }
25
+ }
26
+ // Thrown when the transaction's nLockTime has not been satisfied (transaction is not yet final).
27
+ export class NetworkProviderAbsoluteTimelockError extends NetworkProviderError {
28
+ constructor(originalError) {
29
+ super(`Transaction is not yet final (nLockTime not satisfied): ${originalError}`, originalError);
30
+ }
31
+ }
32
+ // Thrown when a BIP68 relative timelock (sequence lock) on an input has not been satisfied.
33
+ export class NetworkProviderRelativeTimelockError extends NetworkProviderError {
34
+ constructor(originalError) {
35
+ super(`BIP68 sequence lock not satisfied: ${originalError}`, originalError);
36
+ }
37
+ }
38
+ //# sourceMappingURL=errors.js.map
@@ -1,5 +1,3 @@
1
1
  export type { default as NetworkProvider } from './NetworkProvider.js';
2
- export { default as BitcoinRpcNetworkProvider } from './BitcoinRpcNetworkProvider.js';
3
2
  export { default as ElectrumNetworkProvider } from './ElectrumNetworkProvider.js';
4
- export { default as FullStackNetworkProvider } from './FullStackNetworkProvider.js';
5
3
  export { default as MockNetworkProvider } from './MockNetworkProvider.js';
@@ -1,5 +1,3 @@
1
- export { default as BitcoinRpcNetworkProvider } from './BitcoinRpcNetworkProvider.js';
2
1
  export { default as ElectrumNetworkProvider } from './ElectrumNetworkProvider.js';
3
- export { default as FullStackNetworkProvider } from './FullStackNetworkProvider.js';
4
2
  export { default as MockNetworkProvider } from './MockNetworkProvider.js';
5
3
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,30 @@
1
1
  import { Utxo } from './interfaces.js';
2
+ /**
3
+ * Result of `gatherBchUtxos` and `gatherFungibleTokenUtxos`: the selected UTXOs and the total
4
+ * amount they cover (satoshis for BCH, token amount for fungible tokens).
5
+ */
2
6
  export interface GatherUtxosResult {
3
7
  utxos: Utxo[];
4
8
  totalAmount: bigint;
5
9
  }
10
+ /**
11
+ * Select non-token UTXOs from the provided list, largest-first, until the requested amount of
12
+ * satoshis is covered.
13
+ *
14
+ * @param utxos - UTXOs to choose from. Token UTXOs are ignored.
15
+ * @param amount - The minimum total satoshis that the selected UTXOs must cover.
16
+ * @returns The selected UTXOs and their cumulative satoshi amount.
17
+ * @throws If the available non-token UTXOs do not cover the requested amount.
18
+ */
6
19
  export declare function gatherBchUtxos(utxos: Utxo[], amount: bigint): GatherUtxosResult;
20
+ /**
21
+ * Select fungible token UTXOs (for a specific token category) from the provided list,
22
+ * largest-first, until the requested token amount is covered. NFT UTXOs are ignored.
23
+ *
24
+ * @param utxos - UTXOs to choose from.
25
+ * @param tokenCategory - The hex-encoded token category to filter on.
26
+ * @param amount - The minimum total token amount that the selected UTXOs must cover.
27
+ * @returns The selected UTXOs and their cumulative token amount.
28
+ * @throws If the available fungible token UTXOs do not cover the requested amount.
29
+ */
7
30
  export declare function gatherFungibleTokenUtxos(utxos: Utxo[], tokenCategory: string, amount: bigint): GatherUtxosResult;
@@ -1,4 +1,13 @@
1
1
  import { isFungibleTokenUtxo, isNonTokenUtxo } from './utils.js';
2
+ /**
3
+ * Select non-token UTXOs from the provided list, largest-first, until the requested amount of
4
+ * satoshis is covered.
5
+ *
6
+ * @param utxos - UTXOs to choose from. Token UTXOs are ignored.
7
+ * @param amount - The minimum total satoshis that the selected UTXOs must cover.
8
+ * @returns The selected UTXOs and their cumulative satoshi amount.
9
+ * @throws If the available non-token UTXOs do not cover the requested amount.
10
+ */
2
11
  export function gatherBchUtxos(utxos, amount) {
3
12
  const sortedBchUtxos = utxos
4
13
  .filter(isNonTokenUtxo)
@@ -16,6 +25,16 @@ export function gatherBchUtxos(utxos, amount) {
16
25
  }
17
26
  return { utxos: targetUtxos, totalAmount: total };
18
27
  }
28
+ /**
29
+ * Select fungible token UTXOs (for a specific token category) from the provided list,
30
+ * largest-first, until the requested token amount is covered. NFT UTXOs are ignored.
31
+ *
32
+ * @param utxos - UTXOs to choose from.
33
+ * @param tokenCategory - The hex-encoded token category to filter on.
34
+ * @param amount - The minimum total token amount that the selected UTXOs must cover.
35
+ * @returns The selected UTXOs and their cumulative token amount.
36
+ * @throws If the available fungible token UTXOs do not cover the requested amount.
37
+ */
19
38
  export function gatherFungibleTokenUtxos(utxos, tokenCategory, amount) {
20
39
  const sortedTokenUtxos = utxos
21
40
  .filter((utxo) => isFungibleTokenUtxo(utxo) && utxo.token.category === tokenCategory)