@leather.io/bitcoin 0.35.5 → 0.35.6

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/dist/index.js CHANGED
@@ -1,1727 +1,1411 @@
1
- // src/bip21/bip21.ts
2
1
  import { decode, encode } from "bip21";
3
- import { isError } from "@leather.io/utils";
4
- var bip21 = {
5
- decode: (uri, urnScheme) => {
6
- try {
7
- const { address: address2, options } = decode(uri, urnScheme);
8
- return {
9
- success: true,
10
- data: { address: address2, ...options }
11
- };
12
- } catch (error) {
13
- return {
14
- success: false,
15
- error: isError(error) ? error.message : "invalid input"
16
- };
17
- }
18
- },
19
- encode: (address2, options, urnScheme) => {
20
- try {
21
- return encode(address2, options, urnScheme);
22
- } catch {
23
- return null;
24
- }
25
- }
26
- };
27
-
28
- // src/bip322/bip322-utils.ts
2
+ import { assertUnreachable, createCounter, createMoney, defaultWalletKeyId, hexToNumber, isDefined, isEmptyString, isError, isString, isUndefined, satToBtc, subtractMoney, sumMoney, sumNumbers, toHexString, whenNetwork } from "@leather.io/utils";
29
3
  import ecc from "@bitcoinerlab/secp256k1";
30
4
  import { sha256 } from "@noble/hashes/sha256";
31
- import { hexToBytes as hexToBytes2, utf8ToBytes } from "@noble/hashes/utils";
32
- import * as bitcoin from "bitcoinjs-lib";
5
+ import { bytesToHex, hexToBytes, utf8ToBytes } from "@noble/hashes/utils";
6
+ import * as bitcoinJs from "bitcoinjs-lib";
33
7
  import { ECPairFactory } from "ecpair";
34
- import { encode as encode2 } from "varuint-bitcoin";
35
- import { isString } from "@leather.io/utils";
36
-
37
- // src/utils/bitcoin.utils.ts
38
- import { hexToBytes } from "@noble/hashes/utils";
39
- import { HDKey } from "@scure/bip32";
8
+ import { encode as encode$1 } from "varuint-bitcoin";
9
+ import { HARDENED_OFFSET, HDKey } from "@scure/bip32";
40
10
  import { mnemonicToSeedSync } from "@scure/bip39";
41
- import * as btc3 from "@scure/btc-signer";
42
- import {
43
- DerivationPathDepth as DerivationPathDepth3,
44
- extractAccountIndexFromPath,
45
- extractPurposeFromPath
46
- } from "@leather.io/crypto";
47
- import { defaultWalletKeyId, isDefined, whenNetwork } from "@leather.io/utils";
48
-
49
- // src/payments/p2tr-address-gen.ts
50
11
  import * as btc from "@scure/btc-signer";
51
- import { DerivationPathDepth } from "@leather.io/crypto";
12
+ import { DerivationPathDepth, appendAddressIndexToPath, decomposeDescriptor, deriveBip39SeedFromMnemonic, deriveKeychainFromXpub, deriveRootBip32Keychain, extractAccountIndexFromPath, extractAddressIndexFromPath, extractChangeIndexFromPath, extractPurposeFromPath, keyOriginToDerivationPath } from "@leather.io/crypto";
13
+ import validate$1, { AddressType, Network, getAddressInfo, validate } from "bitcoin-address-validation";
14
+ import { base58check, base64 } from "@scure/base";
15
+ import BigNumber from "bignumber.js";
16
+ import { BITCOIN_MINIMUM_SPEND_IN_SATS, BTC_P2WPKH_DUST_AMOUNT } from "@leather.io/constants";
17
+ import { z } from "zod";
18
+ import { ripemd160 } from "@noble/hashes/ripemd160";
19
+ import { RawPSBTV0, RawPSBTV2 } from "@scure/btc-signer/psbt";
52
20
 
53
- // src/utils/bitcoin.network.ts
54
- import * as bitcoinJs from "bitcoinjs-lib";
55
- var bitcoinMainnet = {
56
- bech32: "bc",
57
- pubKeyHash: 0,
58
- scriptHash: 5,
59
- wif: 128
21
+ //#region src/bip21/bip21.ts
22
+ const bip21 = {
23
+ decode: (uri, urnScheme) => {
24
+ try {
25
+ const { address, options } = decode(uri, urnScheme);
26
+ return {
27
+ success: true,
28
+ data: {
29
+ address,
30
+ ...options
31
+ }
32
+ };
33
+ } catch (error) {
34
+ return {
35
+ success: false,
36
+ error: isError(error) ? error.message : "invalid input"
37
+ };
38
+ }
39
+ },
40
+ encode: (address, options, urnScheme) => {
41
+ try {
42
+ return encode(address, options, urnScheme);
43
+ } catch {
44
+ return null;
45
+ }
46
+ }
60
47
  };
61
- var bitcoinTestnet = {
62
- bech32: "tb",
63
- pubKeyHash: 111,
64
- scriptHash: 196,
65
- wif: 239
48
+
49
+ //#endregion
50
+ //#region src/utils/bitcoin.network.ts
51
+ const bitcoinMainnet = {
52
+ bech32: "bc",
53
+ pubKeyHash: 0,
54
+ scriptHash: 5,
55
+ wif: 128
66
56
  };
67
- var bitcoinRegtest = {
68
- bech32: "bcrt",
69
- pubKeyHash: 111,
70
- scriptHash: 196,
71
- wif: 239
57
+ const bitcoinTestnet = {
58
+ bech32: "tb",
59
+ pubKeyHash: 111,
60
+ scriptHash: 196,
61
+ wif: 239
72
62
  };
73
- var btcSignerLibNetworks = {
74
- mainnet: bitcoinMainnet,
75
- testnet: bitcoinTestnet,
76
- regtest: bitcoinRegtest,
77
- // Signet originally was going to have its own prefix but authors decided to
78
- // copy testnet
79
- signet: bitcoinTestnet
63
+ const btcSignerLibNetworks = {
64
+ mainnet: bitcoinMainnet,
65
+ testnet: bitcoinTestnet,
66
+ regtest: {
67
+ bech32: "bcrt",
68
+ pubKeyHash: 111,
69
+ scriptHash: 196,
70
+ wif: 239
71
+ },
72
+ signet: bitcoinTestnet
80
73
  };
81
74
  function getBtcSignerLibNetworkConfigByMode(network) {
82
- return btcSignerLibNetworks[network];
75
+ return btcSignerLibNetworks[network];
83
76
  }
84
- var bitcoinJsLibNetworks = {
85
- mainnet: bitcoinJs.networks.bitcoin,
86
- testnet: bitcoinJs.networks.testnet,
87
- regtest: bitcoinJs.networks.regtest,
88
- signet: bitcoinJs.networks.testnet
77
+ const bitcoinJsLibNetworks = {
78
+ mainnet: bitcoinJs.networks.bitcoin,
79
+ testnet: bitcoinJs.networks.testnet,
80
+ regtest: bitcoinJs.networks.regtest,
81
+ signet: bitcoinJs.networks.testnet
89
82
  };
90
83
  function getBitcoinJsLibNetworkConfigByMode(network) {
91
- return bitcoinJsLibNetworks[network];
84
+ return bitcoinJsLibNetworks[network];
92
85
  }
93
86
 
94
- // src/payments/p2tr-address-gen.ts
87
+ //#endregion
88
+ //#region src/payments/p2tr-address-gen.ts
95
89
  function makeTaprootAccountDerivationPath(network, accountIndex) {
96
- return `m/86'/${getBitcoinCoinTypeIndexByNetwork(network)}'/${accountIndex}'`;
90
+ return `m/86'/${getBitcoinCoinTypeIndexByNetwork(network)}'/${accountIndex}'`;
97
91
  }
98
- var getTaprootAccountDerivationPath = makeTaprootAccountDerivationPath;
92
+ /** @deprecated Use makeTaprootAccountDerivationPath */
93
+ const getTaprootAccountDerivationPath = makeTaprootAccountDerivationPath;
99
94
  function makeTaprootAddressIndexDerivationPath(network, accountIndex, addressIndex) {
100
- return makeTaprootAccountDerivationPath(network, accountIndex) + `/0/${addressIndex}`;
95
+ return makeTaprootAccountDerivationPath(network, accountIndex) + `/0/${addressIndex}`;
101
96
  }
102
- var getTaprootAddressIndexDerivationPath = makeTaprootAddressIndexDerivationPath;
97
+ /** @deprecated Use makeTaprootAddressIndexDerivationPath */
98
+ const getTaprootAddressIndexDerivationPath = makeTaprootAddressIndexDerivationPath;
103
99
  function deriveTaprootAccount(keychain, network) {
104
- if (keychain.depth !== DerivationPathDepth.Root)
105
- throw new Error("Keychain passed is not an account");
106
- return (accountIndex) => ({
107
- type: "p2tr",
108
- network,
109
- accountIndex,
110
- derivationPath: makeTaprootAccountDerivationPath(network, accountIndex),
111
- keychain: keychain.derive(makeTaprootAccountDerivationPath(network, accountIndex))
112
- });
100
+ if (keychain.depth !== DerivationPathDepth.Root) throw new Error("Keychain passed is not an account");
101
+ return (accountIndex) => ({
102
+ type: "p2tr",
103
+ network,
104
+ accountIndex,
105
+ derivationPath: makeTaprootAccountDerivationPath(network, accountIndex),
106
+ keychain: keychain.derive(makeTaprootAccountDerivationPath(network, accountIndex))
107
+ });
113
108
  }
114
109
  function getTaprootPayment(publicKey, network) {
115
- return btc.p2tr(
116
- ecdsaPublicKeyToSchnorr(publicKey),
117
- void 0,
118
- getBtcSignerLibNetworkConfigByMode(network),
119
- true
120
- // allow unknown outputs
121
- );
110
+ return btc.p2tr(ecdsaPublicKeyToSchnorr(publicKey), void 0, getBtcSignerLibNetworkConfigByMode(network), true);
122
111
  }
123
112
  function getTaprootPaymentFromAddressIndex(keychain, network) {
124
- if (keychain.depth !== DerivationPathDepth.AddressIndex)
125
- throw new Error("Keychain passed is not an address index");
126
- if (!keychain.publicKey) throw new Error("Keychain has no public key");
127
- return getTaprootPayment(keychain.publicKey, network);
128
- }
129
- function deriveTaprootReceiveAddressIndexZero({
130
- keychain,
131
- network
132
- }) {
133
- const zeroAddressIndex = deriveAddressIndexZeroFromAccount(keychain);
134
- return {
135
- keychain: zeroAddressIndex,
136
- payment: getTaprootPaymentFromAddressIndex(zeroAddressIndex, network)
137
- };
113
+ if (keychain.depth !== DerivationPathDepth.AddressIndex) throw new Error("Keychain passed is not an address index");
114
+ if (!keychain.publicKey) throw new Error("Keychain has no public key");
115
+ return getTaprootPayment(keychain.publicKey, network);
116
+ }
117
+ function deriveTaprootReceiveAddressIndexZero({ keychain, network }) {
118
+ const zeroAddressIndex = deriveAddressIndexZeroFromAccount(keychain);
119
+ return {
120
+ keychain: zeroAddressIndex,
121
+ payment: getTaprootPaymentFromAddressIndex(zeroAddressIndex, network)
122
+ };
138
123
  }
139
124
 
140
- // src/payments/p2wpkh-address-gen.ts
141
- import * as btc2 from "@scure/btc-signer";
142
- import { DerivationPathDepth as DerivationPathDepth2 } from "@leather.io/crypto";
125
+ //#endregion
126
+ //#region src/payments/p2wpkh-address-gen.ts
143
127
  function makeNativeSegwitAccountDerivationPath(network, accountIndex) {
144
- return `m/84'/${getBitcoinCoinTypeIndexByNetwork(network)}'/${accountIndex}'`;
128
+ return `m/84'/${getBitcoinCoinTypeIndexByNetwork(network)}'/${accountIndex}'`;
145
129
  }
146
- var getNativeSegwitAccountDerivationPath = makeNativeSegwitAccountDerivationPath;
130
+ /** @deprecated Use makeNativeSegwitAccountDerivationPath */
131
+ const getNativeSegwitAccountDerivationPath = makeNativeSegwitAccountDerivationPath;
147
132
  function makeNativeSegwitAddressIndexDerivationPath(network, accountIndex, addressIndex) {
148
- return makeNativeSegwitAccountDerivationPath(network, accountIndex) + `/0/${addressIndex}`;
133
+ return makeNativeSegwitAccountDerivationPath(network, accountIndex) + `/0/${addressIndex}`;
149
134
  }
150
- var getNativeSegwitAddressIndexDerivationPath = makeNativeSegwitAddressIndexDerivationPath;
135
+ /** @deprecated Use makeNativeSegwitAddressIndexDerivationPath */
136
+ const getNativeSegwitAddressIndexDerivationPath = makeNativeSegwitAddressIndexDerivationPath;
151
137
  function deriveNativeSegwitAccountFromRootKeychain(keychain, network) {
152
- if (keychain.depth !== DerivationPathDepth2.Root) throw new Error("Keychain passed is not a root");
153
- return (accountIndex) => ({
154
- type: "p2wpkh",
155
- network,
156
- accountIndex,
157
- derivationPath: makeNativeSegwitAccountDerivationPath(network, accountIndex),
158
- keychain: keychain.derive(makeNativeSegwitAccountDerivationPath(network, accountIndex))
159
- });
138
+ if (keychain.depth !== DerivationPathDepth.Root) throw new Error("Keychain passed is not a root");
139
+ return (accountIndex) => ({
140
+ type: "p2wpkh",
141
+ network,
142
+ accountIndex,
143
+ derivationPath: makeNativeSegwitAccountDerivationPath(network, accountIndex),
144
+ keychain: keychain.derive(makeNativeSegwitAccountDerivationPath(network, accountIndex))
145
+ });
160
146
  }
161
147
  function getNativeSegwitPaymentFromAddressIndex(keychain, network) {
162
- if (keychain.depth !== DerivationPathDepth2.AddressIndex)
163
- throw new Error("Keychain passed is not an address index");
164
- if (!keychain.publicKey) throw new Error("Keychain does not have a public key");
165
- return btc2.p2wpkh(keychain.publicKey, getBtcSignerLibNetworkConfigByMode(network));
166
- }
167
- function deriveNativeSegwitReceiveAddressIndexZero({
168
- keychain,
169
- network
170
- }) {
171
- const zeroAddressIndex = deriveAddressIndexZeroFromAccount(keychain);
172
- return {
173
- keychain: zeroAddressIndex,
174
- payment: getNativeSegwitPaymentFromAddressIndex(zeroAddressIndex, network)
175
- };
148
+ if (keychain.depth !== DerivationPathDepth.AddressIndex) throw new Error("Keychain passed is not an address index");
149
+ if (!keychain.publicKey) throw new Error("Keychain does not have a public key");
150
+ return btc.p2wpkh(keychain.publicKey, getBtcSignerLibNetworkConfigByMode(network));
151
+ }
152
+ function deriveNativeSegwitReceiveAddressIndexZero({ keychain, network }) {
153
+ const zeroAddressIndex = deriveAddressIndexZeroFromAccount(keychain);
154
+ return {
155
+ keychain: zeroAddressIndex,
156
+ payment: getNativeSegwitPaymentFromAddressIndex(zeroAddressIndex, network)
157
+ };
176
158
  }
177
159
 
178
- // src/validation/address-validation.ts
179
- import { Network, validate } from "bitcoin-address-validation";
180
- import { isEmptyString, isUndefined } from "@leather.io/utils";
160
+ //#endregion
161
+ //#region src/validation/address-validation.ts
181
162
  function getBitcoinAddressNetworkType(network) {
182
- if (network === "signet") return Network.testnet;
183
- return network;
163
+ if (network === "signet") return Network.testnet;
164
+ return network;
184
165
  }
185
- function isValidBitcoinAddress(address2) {
186
- if (isUndefined(address2) || isEmptyString(address2)) {
187
- return false;
188
- }
189
- return validate(address2);
166
+ function isValidBitcoinAddress(address) {
167
+ if (isUndefined(address) || isEmptyString(address)) return false;
168
+ return validate(address);
190
169
  }
191
- function isValidBitcoinNetworkAddress(address2, network) {
192
- return validate(address2, getBitcoinAddressNetworkType(network));
170
+ function isValidBitcoinNetworkAddress(address, network) {
171
+ return validate(address, getBitcoinAddressNetworkType(network));
193
172
  }
194
173
 
195
- // src/validation/bitcoin-error.ts
174
+ //#endregion
175
+ //#region src/validation/bitcoin-error.ts
196
176
  var BitcoinError = class extends Error {
197
- message;
198
- constructor(message) {
199
- super(message);
200
- this.name = "BitcoinError";
201
- this.message = message;
202
- Object.setPrototypeOf(this, new.target.prototype);
203
- }
177
+ message;
178
+ constructor(message) {
179
+ super(message);
180
+ this.name = "BitcoinError";
181
+ this.message = message;
182
+ Object.setPrototypeOf(this, new.target.prototype);
183
+ }
204
184
  };
205
185
 
206
- // src/validation/bitcoin-address.ts
186
+ //#endregion
187
+ //#region src/validation/bitcoin-address.ts
207
188
  function isBitcoinAddress(value) {
208
- try {
209
- isValidBitcoinAddress(value);
210
- return true;
211
- } catch {
212
- return false;
213
- }
189
+ try {
190
+ isValidBitcoinAddress(value);
191
+ return true;
192
+ } catch {
193
+ return false;
194
+ }
214
195
  }
215
196
  function createBitcoinAddress(value) {
216
- if (!isBitcoinAddress(value)) {
217
- throw new BitcoinError("InvalidAddress");
218
- }
219
- return value;
197
+ if (!isBitcoinAddress(value)) throw new BitcoinError("InvalidAddress");
198
+ return value;
220
199
  }
221
200
 
222
- // src/utils/bitcoin.utils.ts
201
+ //#endregion
202
+ //#region src/utils/bitcoin.utils.ts
223
203
  function initBitcoinAccount(derivationPath, policy) {
224
- const xpub = extractExtendedPublicKeyFromPolicy(policy);
225
- const network = inferNetworkFromPath(derivationPath);
226
- return {
227
- keychain: HDKey.fromExtendedKey(xpub, getHdKeyVersionsFromNetwork(network)),
228
- network,
229
- derivationPath,
230
- type: inferPaymentTypeFromPath(derivationPath),
231
- accountIndex: extractAccountIndexFromPath(derivationPath)
232
- };
233
- }
234
- var bitcoinNetworkToCoreNetworkMap = {
235
- mainnet: "mainnet",
236
- testnet: "testnet",
237
- regtest: "testnet",
238
- signet: "testnet"
204
+ const xpub = extractExtendedPublicKeyFromPolicy(policy);
205
+ const network = inferNetworkFromPath(derivationPath);
206
+ return {
207
+ keychain: HDKey.fromExtendedKey(xpub, getHdKeyVersionsFromNetwork(network)),
208
+ network,
209
+ derivationPath,
210
+ type: inferPaymentTypeFromPath(derivationPath),
211
+ accountIndex: extractAccountIndexFromPath(derivationPath)
212
+ };
213
+ }
214
+ /**
215
+ * Represents a map of `BitcoinNetworkModes` to `NetworkModes`. While Bitcoin
216
+ * has a number of networks, its often only necessary to consider the higher
217
+ * level concept of mainnet and testnet
218
+ */
219
+ const bitcoinNetworkToCoreNetworkMap = {
220
+ mainnet: "mainnet",
221
+ testnet: "testnet",
222
+ regtest: "testnet",
223
+ signet: "testnet"
239
224
  };
240
225
  function bitcoinNetworkModeToCoreNetworkMode(mode) {
241
- return bitcoinNetworkToCoreNetworkMap[mode];
226
+ return bitcoinNetworkToCoreNetworkMap[mode];
242
227
  }
243
228
  function whenBitcoinNetwork(mode) {
244
- return (networkMap) => networkMap[mode];
245
- }
246
- var coinTypeMap = {
247
- mainnet: 0,
248
- testnet: 1
229
+ return (networkMap) => networkMap[mode];
230
+ }
231
+ /**
232
+ * Map representing the "Coin Type" section of a derivation path.
233
+ * Consider example below, Coin type is one, thus testnet
234
+ * @example
235
+ * `m/86'/1'/0'/0/0`
236
+ */
237
+ const coinTypeMap = {
238
+ mainnet: 0,
239
+ testnet: 1
249
240
  };
250
241
  function getBitcoinCoinTypeIndexByNetwork(network) {
251
- return coinTypeMap[bitcoinNetworkModeToCoreNetworkMode(network)];
242
+ return coinTypeMap[bitcoinNetworkModeToCoreNetworkMode(network)];
252
243
  }
253
244
  function deriveAddressIndexKeychainFromAccount(keychain) {
254
- if (keychain.depth !== DerivationPathDepth3.Account)
255
- throw new Error("Keychain passed is not an account");
256
- return (index) => keychain.deriveChild(0).deriveChild(index);
245
+ if (keychain.depth !== DerivationPathDepth.Account) throw new Error("Keychain passed is not an account");
246
+ return (index) => keychain.deriveChild(0).deriveChild(index);
257
247
  }
258
248
  function deriveAddressIndexZeroFromAccount(keychain) {
259
- return deriveAddressIndexKeychainFromAccount(keychain)(0);
249
+ return deriveAddressIndexKeychainFromAccount(keychain)(0);
260
250
  }
261
- var ecdsaPublicKeyLength = 33;
251
+ const ecdsaPublicKeyLength = 33;
262
252
  function ecdsaPublicKeyToSchnorr(pubKey) {
263
- if (pubKey.byteLength !== ecdsaPublicKeyLength) throw new Error("Invalid public key length");
264
- return pubKey.slice(1);
253
+ if (pubKey.byteLength !== ecdsaPublicKeyLength) throw new Error("Invalid public key length");
254
+ return pubKey.slice(1);
265
255
  }
266
256
  function toXOnly(pubKey) {
267
- return pubKey.length === 32 ? pubKey : pubKey.subarray(1, 33);
257
+ return pubKey.length === 32 ? pubKey : pubKey.subarray(1, 33);
268
258
  }
269
259
  function decodeBitcoinTx(tx) {
270
- return btc3.RawTx.decode(hexToBytes(tx));
271
- }
272
- function getAddressFromOutScript(script2, bitcoinNetwork) {
273
- const outputScript = btc3.OutScript.decode(script2);
274
- switch (outputScript.type) {
275
- case "pkh":
276
- case "sh":
277
- case "wpkh":
278
- case "wsh":
279
- return createBitcoinAddress(
280
- btc3.Address(bitcoinNetwork).encode({
281
- type: outputScript.type,
282
- hash: outputScript.hash
283
- })
284
- );
285
- case "tr":
286
- return createBitcoinAddress(
287
- btc3.Address(bitcoinNetwork).encode({
288
- type: outputScript.type,
289
- pubkey: outputScript.pubkey
290
- })
291
- );
292
- case "ms":
293
- return createBitcoinAddress(btc3.p2ms(outputScript.m, outputScript.pubkeys).address ?? "");
294
- case "pk":
295
- return createBitcoinAddress(btc3.p2pk(outputScript.pubkey, bitcoinNetwork).address ?? "");
296
- case "unknown":
297
- case "tr_ms":
298
- case "tr_ns":
299
- case "p2a":
300
- default:
301
- return null;
302
- }
303
- }
304
- var paymentTypeMap = {
305
- wpkh: "p2wpkh",
306
- wsh: "p2wpkh-p2sh",
307
- tr: "p2tr",
308
- pkh: "p2pkh",
309
- sh: "p2sh"
260
+ return btc.RawTx.decode(hexToBytes(tx));
261
+ }
262
+ function getAddressFromOutScript(script, bitcoinNetwork) {
263
+ const outputScript = btc.OutScript.decode(script);
264
+ switch (outputScript.type) {
265
+ case "pkh":
266
+ case "sh":
267
+ case "wpkh":
268
+ case "wsh": return createBitcoinAddress(btc.Address(bitcoinNetwork).encode({
269
+ type: outputScript.type,
270
+ hash: outputScript.hash
271
+ }));
272
+ case "tr": return createBitcoinAddress(btc.Address(bitcoinNetwork).encode({
273
+ type: outputScript.type,
274
+ pubkey: outputScript.pubkey
275
+ }));
276
+ case "ms": return createBitcoinAddress(btc.p2ms(outputScript.m, outputScript.pubkeys).address ?? "");
277
+ case "pk": return createBitcoinAddress(btc.p2pk(outputScript.pubkey, bitcoinNetwork).address ?? "");
278
+ case "unknown":
279
+ case "tr_ms":
280
+ case "tr_ns":
281
+ case "p2a":
282
+ default: return null;
283
+ }
284
+ }
285
+ const paymentTypeMap = {
286
+ wpkh: "p2wpkh",
287
+ wsh: "p2wpkh-p2sh",
288
+ tr: "p2tr",
289
+ pkh: "p2pkh",
290
+ sh: "p2sh"
310
291
  };
311
292
  function btcSignerLibPaymentTypeToPaymentTypeMap(payment) {
312
- return paymentTypeMap[payment];
293
+ return paymentTypeMap[payment];
313
294
  }
314
295
  function isBtcSignerLibPaymentType(payment) {
315
- return payment in paymentTypeMap;
296
+ return payment in paymentTypeMap;
316
297
  }
317
298
  function parseKnownPaymentType(payment) {
318
- return isBtcSignerLibPaymentType(payment) ? btcSignerLibPaymentTypeToPaymentTypeMap(payment) : payment;
299
+ return isBtcSignerLibPaymentType(payment) ? btcSignerLibPaymentTypeToPaymentTypeMap(payment) : payment;
319
300
  }
320
301
  function whenPaymentType(mode) {
321
- return (paymentMap) => paymentMap[parseKnownPaymentType(mode)];
302
+ return (paymentMap) => paymentMap[parseKnownPaymentType(mode)];
322
303
  }
323
304
  function whenSupportedPaymentType(mode) {
324
- return (paymentMap) => paymentMap[mode];
325
- }
305
+ return (paymentMap) => paymentMap[mode];
306
+ }
307
+ /**
308
+ * Infers the Bitcoin payment type from the derivation path.
309
+ * Below we see path has 86 in it, per convention, this refers to taproot payments
310
+ * @example
311
+ * `m/86'/1'/0'/0/0`
312
+ */
326
313
  function inferPaymentTypeFromPath(path) {
327
- const purpose = extractPurposeFromPath(path);
328
- switch (purpose) {
329
- case 84:
330
- return "p2wpkh";
331
- case 86:
332
- return "p2tr";
333
- case 44:
334
- return "p2pkh";
335
- default:
336
- throw new Error(`Unable to infer payment type from purpose=${purpose}`);
337
- }
314
+ const purpose = extractPurposeFromPath(path);
315
+ switch (purpose) {
316
+ case 84: return "p2wpkh";
317
+ case 86: return "p2tr";
318
+ case 44: return "p2pkh";
319
+ default: throw new Error(`Unable to infer payment type from purpose=${purpose}`);
320
+ }
338
321
  }
339
322
  function inferNetworkFromPath(path) {
340
- return path.split("/")[2].startsWith("0") ? "mainnet" : "testnet";
323
+ return path.split("/")[2].startsWith("0") ? "mainnet" : "testnet";
341
324
  }
342
325
  function extractExtendedPublicKeyFromPolicy(policy) {
343
- return policy.split("]")[1];
326
+ return policy.split("]")[1];
344
327
  }
345
328
  function createWalletIdDecoratedPath(policy, walletId) {
346
- return policy.split("]")[0].replace("[", "").replace("m", walletId);
329
+ return policy.split("]")[0].replace("[", "").replace("m", walletId);
347
330
  }
348
331
  function getHdKeyVersionsFromNetwork(network) {
349
- return whenNetwork(network)({
350
- mainnet: void 0,
351
- testnet: {
352
- private: 0,
353
- public: 70617039
354
- }
355
- });
332
+ return whenNetwork(network)({
333
+ mainnet: void 0,
334
+ testnet: {
335
+ private: 0,
336
+ public: 70617039
337
+ }
338
+ });
356
339
  }
357
340
  function getBitcoinInputAddress(input, bitcoinNetwork) {
358
- if (isDefined(input.witnessUtxo))
359
- return getAddressFromOutScript(input.witnessUtxo.script, bitcoinNetwork);
360
- if (isDefined(input.nonWitnessUtxo) && isDefined(input.index))
361
- return getAddressFromOutScript(
362
- input.nonWitnessUtxo.outputs[input.index]?.script,
363
- bitcoinNetwork
364
- );
365
- return null;
341
+ if (isDefined(input.witnessUtxo)) return getAddressFromOutScript(input.witnessUtxo.script, bitcoinNetwork);
342
+ if (isDefined(input.nonWitnessUtxo) && isDefined(input.index)) return getAddressFromOutScript(input.nonWitnessUtxo.outputs[input.index]?.script, bitcoinNetwork);
343
+ return null;
366
344
  }
367
345
  function getInputPaymentType(input, network) {
368
- const address2 = getBitcoinInputAddress(input, getBtcSignerLibNetworkConfigByMode(network));
369
- if (address2 === null) throw new Error("Input address cannot be empty");
370
- if (address2.startsWith("bc1p") || address2.startsWith("tb1p") || address2.startsWith("bcrt1p"))
371
- return "p2tr";
372
- if (address2.startsWith("bc1q") || address2.startsWith("tb1q") || address2.startsWith("bcrt1q"))
373
- return "p2wpkh";
374
- throw new Error("Unable to infer payment type from input address");
346
+ const address = getBitcoinInputAddress(input, getBtcSignerLibNetworkConfigByMode(network));
347
+ if (address === null) throw new Error("Input address cannot be empty");
348
+ if (address.startsWith("bc1p") || address.startsWith("tb1p") || address.startsWith("bcrt1p")) return "p2tr";
349
+ if (address.startsWith("bc1q") || address.startsWith("tb1q") || address.startsWith("bcrt1q")) return "p2wpkh";
350
+ throw new Error("Unable to infer payment type from input address");
375
351
  }
376
352
  function lookUpLedgerKeysByPath(getDerivationPath) {
377
- return (ledgerKeyMap, network) => (accountIndex) => {
378
- const path = getDerivationPath(network, accountIndex);
379
- const account = ledgerKeyMap[path.replace("m", defaultWalletKeyId)];
380
- if (!account) return;
381
- return initBitcoinAccount(path, account.policy);
382
- };
353
+ return (ledgerKeyMap, network) => (accountIndex) => {
354
+ const path = getDerivationPath(network, accountIndex);
355
+ const account = ledgerKeyMap[path.replace("m", defaultWalletKeyId)];
356
+ if (!account) return;
357
+ return initBitcoinAccount(path, account.policy);
358
+ };
383
359
  }
384
360
  function getTaprootAddress({ index, keychain, network }) {
385
- if (!keychain) throw new Error("Expected keychain to be provided");
386
- if (keychain.depth !== DerivationPathDepth3.Account)
387
- throw new Error("Expects keychain to be on the account index");
388
- const addressIndex = deriveAddressIndexKeychainFromAccount(keychain)(index);
389
- if (!addressIndex.publicKey) throw new Error("Expected publicKey to be defined");
390
- const payment = getTaprootPayment(addressIndex.publicKey, network);
391
- if (!payment.address) throw new Error("Expected address to be defined");
392
- return payment.address;
361
+ if (!keychain) throw new Error("Expected keychain to be provided");
362
+ if (keychain.depth !== DerivationPathDepth.Account) throw new Error("Expects keychain to be on the account index");
363
+ const addressIndex = deriveAddressIndexKeychainFromAccount(keychain)(index);
364
+ if (!addressIndex.publicKey) throw new Error("Expected publicKey to be defined");
365
+ const payment = getTaprootPayment(addressIndex.publicKey, network);
366
+ if (!payment.address) throw new Error("Expected address to be defined");
367
+ return payment.address;
393
368
  }
394
369
  function getNativeSegwitAddress({ index, keychain, network }) {
395
- if (!keychain) throw new Error("Expected keychain to be provided");
396
- if (keychain.depth !== DerivationPathDepth3.Account)
397
- throw new Error("Expects keychain to be on the account index");
398
- const addressIndex = deriveAddressIndexKeychainFromAccount(keychain)(index);
399
- if (!addressIndex.publicKey) throw new Error("Expected publicKey to be defined");
400
- const payment = getNativeSegwitPaymentFromAddressIndex(addressIndex, network);
401
- if (!payment.address) throw new Error("Expected address to be defined");
402
- return payment.address;
403
- }
370
+ if (!keychain) throw new Error("Expected keychain to be provided");
371
+ if (keychain.depth !== DerivationPathDepth.Account) throw new Error("Expects keychain to be on the account index");
372
+ const addressIndex = deriveAddressIndexKeychainFromAccount(keychain)(index);
373
+ if (!addressIndex.publicKey) throw new Error("Expected publicKey to be defined");
374
+ const payment = getNativeSegwitPaymentFromAddressIndex(addressIndex, network);
375
+ if (!payment.address) throw new Error("Expected address to be defined");
376
+ return payment.address;
377
+ }
378
+ /**
379
+ * @deprecated
380
+ * Use `deriveRootBip32Keychain` in `@leather.io/crypto` instead
381
+ */
404
382
  function mnemonicToRootNode(secretKey) {
405
- const seed = mnemonicToSeedSync(secretKey);
406
- return HDKey.fromMasterSeed(seed);
383
+ const seed = mnemonicToSeedSync(secretKey);
384
+ return HDKey.fromMasterSeed(seed);
407
385
  }
408
386
  function getPsbtTxInputs(psbtTx) {
409
- const inputsLength = psbtTx.inputsLength;
410
- const inputs = [];
411
- for (let i = 0; i < inputsLength; i++) inputs.push(psbtTx.getInput(i));
412
- return inputs;
387
+ const inputsLength = psbtTx.inputsLength;
388
+ const inputs = [];
389
+ for (let i = 0; i < inputsLength; i++) inputs.push(psbtTx.getInput(i));
390
+ return inputs;
413
391
  }
414
392
  function getPsbtTxOutputs(psbtTx) {
415
- const outputsLength = psbtTx.outputsLength;
416
- const outputs = [];
417
- for (let i = 0; i < outputsLength; i++) outputs.push(psbtTx.getOutput(i));
418
- return outputs;
419
- }
420
- function inferNetworkFromAddress(address2) {
421
- if (address2.startsWith("bc1")) return "mainnet";
422
- if (address2.startsWith("tb1")) return "testnet";
423
- if (address2.startsWith("bcrt1")) return "regtest";
424
- const firstChar = address2[0];
425
- if (firstChar === "1" || firstChar === "3") return "mainnet";
426
- if (firstChar === "m" || firstChar === "n") return "testnet";
427
- if (firstChar === "2") return "testnet";
428
- throw new Error("Invalid or unsupported Bitcoin address format");
429
- }
430
- function inferPaymentTypeFromAddress(address2) {
431
- if (address2.startsWith("bc1q") || address2.startsWith("tb1q") || address2.startsWith("bcrt1q"))
432
- return "p2wpkh";
433
- if (address2.startsWith("bc1p") || address2.startsWith("tb1p") || address2.startsWith("bcrt1p"))
434
- return "p2tr";
435
- throw new Error("Unable to infer payment type from address");
393
+ const outputsLength = psbtTx.outputsLength;
394
+ const outputs = [];
395
+ for (let i = 0; i < outputsLength; i++) outputs.push(psbtTx.getOutput(i));
396
+ return outputs;
397
+ }
398
+ function inferNetworkFromAddress(address) {
399
+ if (address.startsWith("bc1")) return "mainnet";
400
+ if (address.startsWith("tb1")) return "testnet";
401
+ if (address.startsWith("bcrt1")) return "regtest";
402
+ const firstChar = address[0];
403
+ if (firstChar === "1" || firstChar === "3") return "mainnet";
404
+ if (firstChar === "m" || firstChar === "n") return "testnet";
405
+ if (firstChar === "2") return "testnet";
406
+ throw new Error("Invalid or unsupported Bitcoin address format");
407
+ }
408
+ function inferPaymentTypeFromAddress(address) {
409
+ if (address.startsWith("bc1q") || address.startsWith("tb1q") || address.startsWith("bcrt1q")) return "p2wpkh";
410
+ if (address.startsWith("bc1p") || address.startsWith("tb1p") || address.startsWith("bcrt1p")) return "p2tr";
411
+ throw new Error("Unable to infer payment type from address");
436
412
  }
437
413
  function getBitcoinInputValue(input) {
438
- if (isDefined(input.witnessUtxo)) return Number(input.witnessUtxo.amount);
439
- if (isDefined(input.nonWitnessUtxo) && isDefined(input.index))
440
- return Number(input.nonWitnessUtxo.outputs[input.index]?.amount);
441
- return 0;
414
+ if (isDefined(input.witnessUtxo)) return Number(input.witnessUtxo.amount);
415
+ if (isDefined(input.nonWitnessUtxo) && isDefined(input.index)) return Number(input.nonWitnessUtxo.outputs[input.index]?.amount);
416
+ return 0;
442
417
  }
443
418
 
444
- // src/bip322/bip322-utils.ts
445
- var bip322MessageTag = "BIP0322-signed-message";
446
- var ECPair = ECPairFactory(ecc);
447
- bitcoin.initEccLib(ecc);
419
+ //#endregion
420
+ //#region src/bip322/bip322-utils.ts
421
+ const bip322MessageTag = "BIP0322-signed-message";
422
+ const ECPair = ECPairFactory(ecc);
423
+ bitcoinJs.initEccLib(ecc);
448
424
  function ecPairFromPrivateKey(key) {
449
- return ECPair.fromPrivateKey(Buffer.from(key));
425
+ return ECPair.fromPrivateKey(Buffer.from(key));
450
426
  }
451
- var messageTagHash = Uint8Array.from([
452
- ...sha256(utf8ToBytes(bip322MessageTag)),
453
- ...sha256(utf8ToBytes(bip322MessageTag))
454
- ]);
427
+ const messageTagHash = Uint8Array.from([...sha256(utf8ToBytes(bip322MessageTag)), ...sha256(utf8ToBytes(bip322MessageTag))]);
455
428
  function hashBip322Message(message) {
456
- return sha256(
457
- Uint8Array.from([...messageTagHash, ...isString(message) ? utf8ToBytes(message) : message])
458
- );
459
- }
460
- var bip322TransactionToSignValues = {
461
- prevoutHash: hexToBytes2("0000000000000000000000000000000000000000000000000000000000000000"),
462
- prevoutIndex: 4294967295,
463
- sequence: 0
429
+ return sha256(Uint8Array.from([...messageTagHash, ...isString(message) ? utf8ToBytes(message) : message]));
430
+ }
431
+ const bip322TransactionToSignValues = {
432
+ prevoutHash: hexToBytes("0000000000000000000000000000000000000000000000000000000000000000"),
433
+ prevoutIndex: 4294967295,
434
+ sequence: 0
464
435
  };
465
436
  function encodeVarString(b) {
466
- return Buffer.concat([encode2(b.byteLength), b]);
437
+ return Buffer.concat([encode$1(b.byteLength), b]);
467
438
  }
468
- var supportedMessageSigningPaymentTypes = ["p2wpkh", "p2tr"];
439
+ const supportedMessageSigningPaymentTypes = ["p2wpkh", "p2tr"];
469
440
  function isSupportedMessageSigningPaymentType(paymentType) {
470
- return supportedMessageSigningPaymentTypes.includes(paymentType);
441
+ return supportedMessageSigningPaymentTypes.includes(paymentType);
471
442
  }
443
+ /**
444
+ * Encode witness data for a BIP322 message
445
+ * TODO: Refactor to remove `Buffer` use
446
+ */
472
447
  function encodeMessageWitnessData(witnessArray) {
473
- const len = encode2(witnessArray.length);
474
- return Buffer.concat([len, ...witnessArray.map((witness) => encodeVarString(witness))]);
448
+ const len = encode$1(witnessArray.length);
449
+ return Buffer.concat([len, ...witnessArray.map((witness) => encodeVarString(witness))]);
475
450
  }
476
451
  function tapTweakHash(pubKey, h) {
477
- return bitcoin.crypto.taggedHash("TapTweak", Buffer.concat(h ? [pubKey, h] : [pubKey]));
452
+ return bitcoinJs.crypto.taggedHash("TapTweak", Buffer.concat(h ? [pubKey, h] : [pubKey]));
478
453
  }
479
454
  function tweakSigner(signer, opts = {}) {
480
- let privateKey = signer.privateKey;
481
- if (!privateKey) {
482
- throw new Error("Private key is required for tweaking signer!");
483
- }
484
- if (signer.publicKey[0] === 3) {
485
- privateKey = ecc.privateNegate(privateKey);
486
- }
487
- const tweakedPrivateKey = ecc.privateAdd(
488
- privateKey,
489
- tapTweakHash(toXOnly(signer.publicKey), opts.tweakHash)
490
- );
491
- if (!tweakedPrivateKey) {
492
- throw new Error("Invalid tweaked private key!");
493
- }
494
- return ECPair.fromPrivateKey(Buffer.from(tweakedPrivateKey), {
495
- network: opts.network
496
- });
455
+ let privateKey = signer.privateKey;
456
+ if (!privateKey) throw new Error("Private key is required for tweaking signer!");
457
+ if (signer.publicKey[0] === 3) privateKey = ecc.privateNegate(privateKey);
458
+ const tweakedPrivateKey = ecc.privateAdd(privateKey, tapTweakHash(toXOnly(signer.publicKey), opts.tweakHash));
459
+ if (!tweakedPrivateKey) throw new Error("Invalid tweaked private key!");
460
+ return ECPair.fromPrivateKey(Buffer.from(tweakedPrivateKey), { network: opts.network });
497
461
  }
498
462
 
499
- // src/bip322/sign-message-bip322-bitcoinjs.ts
500
- import { base64 } from "@scure/base";
501
- import * as bitcoin2 from "bitcoinjs-lib";
463
+ //#endregion
464
+ //#region src/bip322/sign-message-bip322-bitcoinjs.ts
502
465
  function createNativeSegwitBitcoinJsSigner(privateKey) {
503
- return ecPairFromPrivateKey(privateKey);
466
+ return ecPairFromPrivateKey(privateKey);
504
467
  }
505
468
  function createTaprootBitcoinJsSigner(privateKey) {
506
- return tweakSigner(ecPairFromPrivateKey(privateKey));
507
- }
508
- function createToSpendTx(address2, message, network) {
509
- const { prevoutHash, prevoutIndex, sequence } = bip322TransactionToSignValues;
510
- const script2 = bitcoin2.address.toOutputScript(
511
- address2,
512
- getBitcoinJsLibNetworkConfigByMode(network)
513
- );
514
- const hash = hashBip322Message(message);
515
- const commands = [0, Buffer.from(hash)];
516
- const scriptSig = bitcoin2.script.compile(commands);
517
- const virtualToSpend = new bitcoin2.Transaction();
518
- virtualToSpend.version = 0;
519
- virtualToSpend.addInput(Buffer.from(prevoutHash), prevoutIndex, sequence, scriptSig);
520
- virtualToSpend.addOutput(script2, 0);
521
- return { virtualToSpend, script: script2 };
522
- }
523
- function createToSignTx(toSpendTxHex, script2, network) {
524
- const virtualToSign = new bitcoin2.Psbt({ network: getBitcoinJsLibNetworkConfigByMode(network) });
525
- virtualToSign.setVersion(0);
526
- const prevTxHash = toSpendTxHex;
527
- const prevOutIndex = 0;
528
- const toSignScriptSig = bitcoin2.script.compile([bitcoin2.script.OPS.OP_RETURN]);
529
- virtualToSign.addInput({
530
- hash: prevTxHash,
531
- index: prevOutIndex,
532
- sequence: 0,
533
- witnessUtxo: { script: script2, value: 0 }
534
- });
535
- virtualToSign.addOutput({ script: toSignScriptSig, value: 0 });
536
- return virtualToSign;
469
+ return tweakSigner(ecPairFromPrivateKey(privateKey));
470
+ }
471
+ function createToSpendTx(address, message, network) {
472
+ const { prevoutHash, prevoutIndex, sequence } = bip322TransactionToSignValues;
473
+ const script = bitcoinJs.address.toOutputScript(address, getBitcoinJsLibNetworkConfigByMode(network));
474
+ const hash = hashBip322Message(message);
475
+ const commands = [0, Buffer.from(hash)];
476
+ const scriptSig = bitcoinJs.script.compile(commands);
477
+ const virtualToSpend = new bitcoinJs.Transaction();
478
+ virtualToSpend.version = 0;
479
+ virtualToSpend.addInput(Buffer.from(prevoutHash), prevoutIndex, sequence, scriptSig);
480
+ virtualToSpend.addOutput(script, 0);
481
+ return {
482
+ virtualToSpend,
483
+ script
484
+ };
485
+ }
486
+ function createToSignTx(toSpendTxHex, script, network) {
487
+ const virtualToSign = new bitcoinJs.Psbt({ network: getBitcoinJsLibNetworkConfigByMode(network) });
488
+ virtualToSign.setVersion(0);
489
+ const prevTxHash = toSpendTxHex;
490
+ const prevOutIndex = 0;
491
+ const toSignScriptSig = bitcoinJs.script.compile([bitcoinJs.script.OPS.OP_RETURN]);
492
+ virtualToSign.addInput({
493
+ hash: prevTxHash,
494
+ index: prevOutIndex,
495
+ sequence: 0,
496
+ witnessUtxo: {
497
+ script,
498
+ value: 0
499
+ }
500
+ });
501
+ virtualToSign.addOutput({
502
+ script: toSignScriptSig,
503
+ value: 0
504
+ });
505
+ return virtualToSign;
537
506
  }
538
507
  async function signBip322MessageSimple(args) {
539
- const { address: address2, message, network, signPsbt } = args;
540
- const { virtualToSpend, script: script2 } = createToSpendTx(address2, message, network);
541
- const virtualToSign = createToSignTx(virtualToSpend.getHash(), script2, network);
542
- const signedTx = await signPsbt(virtualToSign);
543
- const asBitcoinJsTransaction = bitcoin2.Psbt.fromBuffer(Buffer.from(signedTx.toPSBT()));
544
- asBitcoinJsTransaction.finalizeInput(0);
545
- const toSignTx = asBitcoinJsTransaction.extractTransaction();
546
- const result = encodeMessageWitnessData(toSignTx.ins[0].witness);
547
- return {
548
- virtualToSpend,
549
- virtualToSign: toSignTx,
550
- unencodedSig: result,
551
- signature: base64.encode(result)
552
- };
508
+ const { address, message, network, signPsbt } = args;
509
+ const { virtualToSpend, script } = createToSpendTx(address, message, network);
510
+ const signedTx = await signPsbt(createToSignTx(virtualToSpend.getHash(), script, network));
511
+ const asBitcoinJsTransaction = bitcoinJs.Psbt.fromBuffer(Buffer.from(signedTx.toPSBT()));
512
+ asBitcoinJsTransaction.finalizeInput(0);
513
+ const toSignTx = asBitcoinJsTransaction.extractTransaction();
514
+ const result = encodeMessageWitnessData(toSignTx.ins[0].witness);
515
+ return {
516
+ virtualToSpend,
517
+ virtualToSign: toSignTx,
518
+ unencodedSig: result,
519
+ signature: base64.encode(result)
520
+ };
553
521
  }
554
522
 
555
- // src/coin-selection/calculate-max-spend.ts
556
- import BigNumber3 from "bignumber.js";
557
- import { createMoney, satToBtc } from "@leather.io/utils";
558
-
559
- // src/coin-selection/coin-selection.utils.ts
560
- import BigNumber2 from "bignumber.js";
561
- import validate2, { AddressType, getAddressInfo } from "bitcoin-address-validation";
562
- import { BTC_P2WPKH_DUST_AMOUNT } from "@leather.io/constants";
563
- import { sumNumbers } from "@leather.io/utils";
564
-
565
- // src/fees/btc-size-fee-estimator.ts
566
- import BigNumber from "bignumber.js";
567
- import { assertUnreachable } from "@leather.io/utils";
523
+ //#endregion
524
+ //#region src/fees/btc-size-fee-estimator.ts
568
525
  var BtcSizeFeeEstimator = class {
569
- P2PKH_IN_SIZE = 148;
570
- P2PKH_OUT_SIZE = 34;
571
- P2SH_OUT_SIZE = 32;
572
- P2SH_P2WPKH_OUT_SIZE = 32;
573
- P2SH_P2WSH_OUT_SIZE = 32;
574
- P2SH_P2WPKH_IN_SIZE = 91;
575
- P2WPKH_IN_SIZE = 67.75;
576
- P2WPKH_OUT_SIZE = 31;
577
- P2WSH_OUT_SIZE = 43;
578
- P2TR_OUT_SIZE = 43;
579
- P2TR_IN_SIZE = 57.25;
580
- PUBKEY_SIZE = 33;
581
- SIGNATURE_SIZE = 72;
582
- SUPPORTED_INPUT_SCRIPT_TYPES = [
583
- "p2pkh",
584
- "p2sh",
585
- "p2sh-p2wpkh",
586
- "p2sh-p2wsh",
587
- "p2wpkh",
588
- "p2wsh",
589
- "p2tr"
590
- ];
591
- defaultParams = {
592
- input_count: 0,
593
- input_script: "p2wpkh",
594
- input_m: 0,
595
- input_n: 0,
596
- p2pkh_output_count: 0,
597
- p2sh_output_count: 0,
598
- p2sh_p2wpkh_output_count: 0,
599
- p2sh_p2wsh_output_count: 0,
600
- p2wpkh_output_count: 0,
601
- p2wsh_output_count: 0,
602
- p2tr_output_count: 0
603
- };
604
- params = { ...this.defaultParams };
605
- getSizeOfScriptLengthElement(length) {
606
- if (length < 75) {
607
- return 1;
608
- } else if (length <= 255) {
609
- return 2;
610
- } else if (length <= 65535) {
611
- return 3;
612
- } else if (length <= 4294967295) {
613
- return 5;
614
- } else {
615
- throw new Error("Size of redeem script is too large");
616
- }
617
- }
618
- getSizeOfletInt(length) {
619
- if (length < 253) {
620
- return 1;
621
- } else if (length < 65535) {
622
- return 3;
623
- } else if (length < 4294967295) {
624
- return 5;
625
- } else if (new BigNumber(length).isLessThan("18446744073709551615")) {
626
- return 9;
627
- } else {
628
- throw new Error("Invalid let int");
629
- }
630
- }
631
- getTxOverheadVBytes(input_script, input_count, output_count) {
632
- let witness_vbytes;
633
- if (input_script === "p2pkh" || input_script === "p2sh") {
634
- witness_vbytes = 0;
635
- } else {
636
- witness_vbytes = 0.25 + // segwit marker
637
- 0.25 + // segwit flag
638
- this.getSizeOfletInt(input_count) / 4;
639
- }
640
- return 4 + // nVersion
641
- this.getSizeOfletInt(input_count) + // number of inputs
642
- this.getSizeOfletInt(output_count) + // number of outputs
643
- 4 + // nLockTime
644
- witness_vbytes;
645
- }
646
- getTxOverheadExtraRawBytes(input_script, input_count) {
647
- let witness_vbytes;
648
- if (input_script === "p2pkh" || input_script === "p2sh") {
649
- witness_vbytes = 0;
650
- } else {
651
- witness_vbytes = 0.25 + // segwit marker
652
- 0.25 + // segwit flag
653
- this.getSizeOfletInt(input_count) / 4;
654
- }
655
- return witness_vbytes * 3;
656
- }
657
- prepareParams(opts) {
658
- opts = opts || Object.assign(this.defaultParams);
659
- const input_count = opts.input_count || this.defaultParams.input_count;
660
- if (!Number.isInteger(input_count) || input_count < 0) {
661
- throw new Error("expecting positive input count, got: " + input_count);
662
- }
663
- const input_script = opts.input_script || this.defaultParams.input_script;
664
- if (this.SUPPORTED_INPUT_SCRIPT_TYPES.indexOf(input_script) === -1) {
665
- throw new Error("Not supported input script type");
666
- }
667
- const input_m = opts.input_m || this.defaultParams.input_m;
668
- if (!Number.isInteger(input_m) || input_m < 0) {
669
- throw new Error("expecting positive signature count");
670
- }
671
- const input_n = opts.input_n || this.defaultParams.input_n;
672
- if (!Number.isInteger(input_n) || input_n < 0) {
673
- throw new Error("expecting positive pubkey count");
674
- }
675
- const p2pkh_output_count = opts.p2pkh_output_count || this.defaultParams.p2pkh_output_count;
676
- if (!Number.isInteger(p2pkh_output_count) || p2pkh_output_count < 0) {
677
- throw new Error("expecting positive p2pkh output count");
678
- }
679
- const p2sh_output_count = opts.p2sh_output_count || this.defaultParams.p2sh_output_count;
680
- if (!Number.isInteger(p2sh_output_count) || p2sh_output_count < 0) {
681
- throw new Error("expecting positive p2sh output count");
682
- }
683
- const p2sh_p2wpkh_output_count = opts.p2sh_p2wpkh_output_count || this.defaultParams.p2sh_p2wpkh_output_count;
684
- if (!Number.isInteger(p2sh_p2wpkh_output_count) || p2sh_p2wpkh_output_count < 0) {
685
- throw new Error("expecting positive p2sh-p2wpkh output count");
686
- }
687
- const p2sh_p2wsh_output_count = opts.p2sh_p2wsh_output_count || this.defaultParams.p2sh_p2wsh_output_count;
688
- if (!Number.isInteger(p2sh_p2wsh_output_count) || p2sh_p2wsh_output_count < 0) {
689
- throw new Error("expecting positive p2sh-p2wsh output count");
690
- }
691
- const p2wpkh_output_count = opts.p2wpkh_output_count || this.defaultParams.p2wpkh_output_count;
692
- if (!Number.isInteger(p2wpkh_output_count) || p2wpkh_output_count < 0) {
693
- throw new Error("expecting positive p2wpkh output count");
694
- }
695
- const p2wsh_output_count = opts.p2wsh_output_count || this.defaultParams.p2wsh_output_count;
696
- if (!Number.isInteger(p2wsh_output_count) || p2wsh_output_count < 0) {
697
- throw new Error("expecting positive p2wsh output count");
698
- }
699
- const p2tr_output_count = opts.p2tr_output_count || this.defaultParams.p2tr_output_count;
700
- if (!Number.isInteger(p2tr_output_count) || p2tr_output_count < 0) {
701
- throw new Error("expecting positive p2tr output count");
702
- }
703
- this.params = {
704
- input_count,
705
- input_script,
706
- input_m,
707
- input_n,
708
- p2pkh_output_count,
709
- p2sh_output_count,
710
- p2sh_p2wpkh_output_count,
711
- p2sh_p2wsh_output_count,
712
- p2wpkh_output_count,
713
- p2wsh_output_count,
714
- p2tr_output_count
715
- };
716
- return this.params;
717
- }
718
- getOutputCount() {
719
- return this.params.p2pkh_output_count + this.params.p2sh_output_count + this.params.p2sh_p2wpkh_output_count + this.params.p2sh_p2wsh_output_count + this.params.p2wpkh_output_count + this.params.p2wsh_output_count + this.params.p2tr_output_count;
720
- }
721
- getSizeBasedOnInputType() {
722
- let inputSize = 0;
723
- let inputWitnessSize = 0;
724
- let redeemScriptSize;
725
- switch (this.params.input_script) {
726
- case "p2pkh":
727
- inputSize = this.P2PKH_IN_SIZE;
728
- break;
729
- case "p2sh-p2wpkh":
730
- inputSize = this.P2SH_P2WPKH_IN_SIZE;
731
- inputWitnessSize = 107;
732
- break;
733
- case "p2wpkh":
734
- inputSize = this.P2WPKH_IN_SIZE;
735
- inputWitnessSize = 107;
736
- break;
737
- case "p2tr":
738
- inputSize = this.P2TR_IN_SIZE;
739
- inputWitnessSize = 65;
740
- break;
741
- case "p2sh":
742
- redeemScriptSize = 1 + // OP_M
743
- this.params.input_n * (1 + this.PUBKEY_SIZE) + // OP_PUSH33 <pubkey>
744
- 1 + // OP_N
745
- 1;
746
- const scriptSigSize = 1 + // size(0)
747
- this.params.input_m * (1 + this.SIGNATURE_SIZE) + // size(SIGNATURE_SIZE) + signature
748
- this.getSizeOfScriptLengthElement(redeemScriptSize) + redeemScriptSize;
749
- inputSize = 32 + 4 + this.getSizeOfletInt(scriptSigSize) + scriptSigSize + 4;
750
- break;
751
- case "p2sh-p2wsh":
752
- case "p2wsh":
753
- redeemScriptSize = 1 + // OP_M
754
- this.params.input_n * (1 + this.PUBKEY_SIZE) + // OP_PUSH33 <pubkey>
755
- 1 + // OP_N
756
- 1;
757
- inputWitnessSize = 1 + // size(0)
758
- this.params.input_m * (1 + this.SIGNATURE_SIZE) + // size(SIGNATURE_SIZE) + signature
759
- this.getSizeOfScriptLengthElement(redeemScriptSize) + redeemScriptSize;
760
- inputSize = 36 + // outpoint (spent UTXO ID)
761
- inputWitnessSize / 4 + // witness program
762
- 4;
763
- if (this.params.input_script === "p2sh-p2wsh") {
764
- inputSize += 32 + 3;
765
- }
766
- break;
767
- default:
768
- assertUnreachable(this.params.input_script);
769
- }
770
- return {
771
- inputSize,
772
- inputWitnessSize
773
- };
774
- }
775
- calcTxSize(opts) {
776
- this.prepareParams(opts);
777
- const output_count = this.getOutputCount();
778
- const { inputSize, inputWitnessSize } = this.getSizeBasedOnInputType();
779
- const txVBytes = this.getTxOverheadVBytes(this.params.input_script, this.params.input_count, output_count) + inputSize * this.params.input_count + this.P2PKH_OUT_SIZE * this.params.p2pkh_output_count + this.P2SH_OUT_SIZE * this.params.p2sh_output_count + this.P2SH_P2WPKH_OUT_SIZE * this.params.p2sh_p2wpkh_output_count + this.P2SH_P2WSH_OUT_SIZE * this.params.p2sh_p2wsh_output_count + this.P2WPKH_OUT_SIZE * this.params.p2wpkh_output_count + this.P2WSH_OUT_SIZE * this.params.p2wsh_output_count + this.P2TR_OUT_SIZE * this.params.p2tr_output_count;
780
- const txBytes = this.getTxOverheadExtraRawBytes(this.params.input_script, this.params.input_count) + txVBytes + inputWitnessSize * this.params.input_count;
781
- const txWeight = txVBytes * 4;
782
- return { txVBytes, txBytes, txWeight };
783
- }
784
- estimateFee(vbyte, satVb) {
785
- if (isNaN(vbyte) || isNaN(satVb)) {
786
- throw new Error("Parameters should be numbers");
787
- }
788
- return vbyte * satVb;
789
- }
790
- formatFeeRange(fee, multiplier) {
791
- if (isNaN(fee) || isNaN(multiplier)) {
792
- throw new Error("Parameters should be numbers");
793
- }
794
- if (multiplier < 0) {
795
- throw new Error("Multiplier cant be negative");
796
- }
797
- const multipliedFee = fee * multiplier;
798
- return fee - multipliedFee + " - " + (fee + multipliedFee);
799
- }
526
+ P2PKH_IN_SIZE = 148;
527
+ P2PKH_OUT_SIZE = 34;
528
+ P2SH_OUT_SIZE = 32;
529
+ P2SH_P2WPKH_OUT_SIZE = 32;
530
+ P2SH_P2WSH_OUT_SIZE = 32;
531
+ P2SH_P2WPKH_IN_SIZE = 91;
532
+ P2WPKH_IN_SIZE = 67.75;
533
+ P2WPKH_OUT_SIZE = 31;
534
+ P2WSH_OUT_SIZE = 43;
535
+ P2TR_OUT_SIZE = 43;
536
+ P2TR_IN_SIZE = 57.25;
537
+ PUBKEY_SIZE = 33;
538
+ SIGNATURE_SIZE = 72;
539
+ SUPPORTED_INPUT_SCRIPT_TYPES = [
540
+ "p2pkh",
541
+ "p2sh",
542
+ "p2sh-p2wpkh",
543
+ "p2sh-p2wsh",
544
+ "p2wpkh",
545
+ "p2wsh",
546
+ "p2tr"
547
+ ];
548
+ defaultParams = {
549
+ input_count: 0,
550
+ input_script: "p2wpkh",
551
+ input_m: 0,
552
+ input_n: 0,
553
+ p2pkh_output_count: 0,
554
+ p2sh_output_count: 0,
555
+ p2sh_p2wpkh_output_count: 0,
556
+ p2sh_p2wsh_output_count: 0,
557
+ p2wpkh_output_count: 0,
558
+ p2wsh_output_count: 0,
559
+ p2tr_output_count: 0
560
+ };
561
+ params = { ...this.defaultParams };
562
+ getSizeOfScriptLengthElement(length) {
563
+ if (length < 75) return 1;
564
+ else if (length <= 255) return 2;
565
+ else if (length <= 65535) return 3;
566
+ else if (length <= 4294967295) return 5;
567
+ else throw new Error("Size of redeem script is too large");
568
+ }
569
+ getSizeOfletInt(length) {
570
+ if (length < 253) return 1;
571
+ else if (length < 65535) return 3;
572
+ else if (length < 4294967295) return 5;
573
+ else if (new BigNumber(length).isLessThan("18446744073709551615")) return 9;
574
+ else throw new Error("Invalid let int");
575
+ }
576
+ getTxOverheadVBytes(input_script, input_count, output_count) {
577
+ let witness_vbytes;
578
+ if (input_script === "p2pkh" || input_script === "p2sh") witness_vbytes = 0;
579
+ else witness_vbytes = .5 + this.getSizeOfletInt(input_count) / 4;
580
+ return 4 + this.getSizeOfletInt(input_count) + this.getSizeOfletInt(output_count) + 4 + witness_vbytes;
581
+ }
582
+ getTxOverheadExtraRawBytes(input_script, input_count) {
583
+ let witness_vbytes;
584
+ if (input_script === "p2pkh" || input_script === "p2sh") witness_vbytes = 0;
585
+ else witness_vbytes = .5 + this.getSizeOfletInt(input_count) / 4;
586
+ return witness_vbytes * 3;
587
+ }
588
+ prepareParams(opts) {
589
+ opts = opts || Object.assign(this.defaultParams);
590
+ const input_count = opts.input_count || this.defaultParams.input_count;
591
+ if (!Number.isInteger(input_count) || input_count < 0) throw new Error("expecting positive input count, got: " + input_count);
592
+ const input_script = opts.input_script || this.defaultParams.input_script;
593
+ if (this.SUPPORTED_INPUT_SCRIPT_TYPES.indexOf(input_script) === -1) throw new Error("Not supported input script type");
594
+ const input_m = opts.input_m || this.defaultParams.input_m;
595
+ if (!Number.isInteger(input_m) || input_m < 0) throw new Error("expecting positive signature count");
596
+ const input_n = opts.input_n || this.defaultParams.input_n;
597
+ if (!Number.isInteger(input_n) || input_n < 0) throw new Error("expecting positive pubkey count");
598
+ const p2pkh_output_count = opts.p2pkh_output_count || this.defaultParams.p2pkh_output_count;
599
+ if (!Number.isInteger(p2pkh_output_count) || p2pkh_output_count < 0) throw new Error("expecting positive p2pkh output count");
600
+ const p2sh_output_count = opts.p2sh_output_count || this.defaultParams.p2sh_output_count;
601
+ if (!Number.isInteger(p2sh_output_count) || p2sh_output_count < 0) throw new Error("expecting positive p2sh output count");
602
+ const p2sh_p2wpkh_output_count = opts.p2sh_p2wpkh_output_count || this.defaultParams.p2sh_p2wpkh_output_count;
603
+ if (!Number.isInteger(p2sh_p2wpkh_output_count) || p2sh_p2wpkh_output_count < 0) throw new Error("expecting positive p2sh-p2wpkh output count");
604
+ const p2sh_p2wsh_output_count = opts.p2sh_p2wsh_output_count || this.defaultParams.p2sh_p2wsh_output_count;
605
+ if (!Number.isInteger(p2sh_p2wsh_output_count) || p2sh_p2wsh_output_count < 0) throw new Error("expecting positive p2sh-p2wsh output count");
606
+ const p2wpkh_output_count = opts.p2wpkh_output_count || this.defaultParams.p2wpkh_output_count;
607
+ if (!Number.isInteger(p2wpkh_output_count) || p2wpkh_output_count < 0) throw new Error("expecting positive p2wpkh output count");
608
+ const p2wsh_output_count = opts.p2wsh_output_count || this.defaultParams.p2wsh_output_count;
609
+ if (!Number.isInteger(p2wsh_output_count) || p2wsh_output_count < 0) throw new Error("expecting positive p2wsh output count");
610
+ const p2tr_output_count = opts.p2tr_output_count || this.defaultParams.p2tr_output_count;
611
+ if (!Number.isInteger(p2tr_output_count) || p2tr_output_count < 0) throw new Error("expecting positive p2tr output count");
612
+ this.params = {
613
+ input_count,
614
+ input_script,
615
+ input_m,
616
+ input_n,
617
+ p2pkh_output_count,
618
+ p2sh_output_count,
619
+ p2sh_p2wpkh_output_count,
620
+ p2sh_p2wsh_output_count,
621
+ p2wpkh_output_count,
622
+ p2wsh_output_count,
623
+ p2tr_output_count
624
+ };
625
+ return this.params;
626
+ }
627
+ getOutputCount() {
628
+ return this.params.p2pkh_output_count + this.params.p2sh_output_count + this.params.p2sh_p2wpkh_output_count + this.params.p2sh_p2wsh_output_count + this.params.p2wpkh_output_count + this.params.p2wsh_output_count + this.params.p2tr_output_count;
629
+ }
630
+ getSizeBasedOnInputType() {
631
+ let inputSize = 0;
632
+ let inputWitnessSize = 0;
633
+ let redeemScriptSize;
634
+ switch (this.params.input_script) {
635
+ case "p2pkh":
636
+ inputSize = this.P2PKH_IN_SIZE;
637
+ break;
638
+ case "p2sh-p2wpkh":
639
+ inputSize = this.P2SH_P2WPKH_IN_SIZE;
640
+ inputWitnessSize = 107;
641
+ break;
642
+ case "p2wpkh":
643
+ inputSize = this.P2WPKH_IN_SIZE;
644
+ inputWitnessSize = 107;
645
+ break;
646
+ case "p2tr":
647
+ inputSize = this.P2TR_IN_SIZE;
648
+ inputWitnessSize = 65;
649
+ break;
650
+ case "p2sh":
651
+ redeemScriptSize = 1 + this.params.input_n * (1 + this.PUBKEY_SIZE) + 1 + 1;
652
+ const scriptSigSize = 1 + this.params.input_m * (1 + this.SIGNATURE_SIZE) + this.getSizeOfScriptLengthElement(redeemScriptSize) + redeemScriptSize;
653
+ inputSize = 36 + this.getSizeOfletInt(scriptSigSize) + scriptSigSize + 4;
654
+ break;
655
+ case "p2sh-p2wsh":
656
+ case "p2wsh":
657
+ redeemScriptSize = 1 + this.params.input_n * (1 + this.PUBKEY_SIZE) + 1 + 1;
658
+ inputWitnessSize = 1 + this.params.input_m * (1 + this.SIGNATURE_SIZE) + this.getSizeOfScriptLengthElement(redeemScriptSize) + redeemScriptSize;
659
+ inputSize = 36 + inputWitnessSize / 4 + 4;
660
+ if (this.params.input_script === "p2sh-p2wsh") inputSize += 35;
661
+ break;
662
+ default: assertUnreachable(this.params.input_script);
663
+ }
664
+ return {
665
+ inputSize,
666
+ inputWitnessSize
667
+ };
668
+ }
669
+ calcTxSize(opts) {
670
+ this.prepareParams(opts);
671
+ const output_count = this.getOutputCount();
672
+ const { inputSize, inputWitnessSize } = this.getSizeBasedOnInputType();
673
+ const txVBytes = this.getTxOverheadVBytes(this.params.input_script, this.params.input_count, output_count) + inputSize * this.params.input_count + this.P2PKH_OUT_SIZE * this.params.p2pkh_output_count + this.P2SH_OUT_SIZE * this.params.p2sh_output_count + this.P2SH_P2WPKH_OUT_SIZE * this.params.p2sh_p2wpkh_output_count + this.P2SH_P2WSH_OUT_SIZE * this.params.p2sh_p2wsh_output_count + this.P2WPKH_OUT_SIZE * this.params.p2wpkh_output_count + this.P2WSH_OUT_SIZE * this.params.p2wsh_output_count + this.P2TR_OUT_SIZE * this.params.p2tr_output_count;
674
+ return {
675
+ txVBytes,
676
+ txBytes: this.getTxOverheadExtraRawBytes(this.params.input_script, this.params.input_count) + txVBytes + inputWitnessSize * this.params.input_count,
677
+ txWeight: txVBytes * 4
678
+ };
679
+ }
680
+ estimateFee(vbyte, satVb) {
681
+ if (isNaN(vbyte) || isNaN(satVb)) throw new Error("Parameters should be numbers");
682
+ return vbyte * satVb;
683
+ }
684
+ formatFeeRange(fee, multiplier) {
685
+ if (isNaN(fee) || isNaN(multiplier)) throw new Error("Parameters should be numbers");
686
+ if (multiplier < 0) throw new Error("Multiplier cant be negative");
687
+ const multipliedFee = fee * multiplier;
688
+ return fee - multipliedFee + " - " + (fee + multipliedFee);
689
+ }
800
690
  };
801
691
 
802
- // src/coin-selection/coin-selection.utils.ts
692
+ //#endregion
693
+ //#region src/coin-selection/coin-selection.utils.ts
803
694
  function getUtxoTotal(utxos) {
804
- return sumNumbers(utxos.map((utxo) => utxo.value));
695
+ return sumNumbers(utxos.map((utxo) => utxo.value));
805
696
  }
806
697
  function getSizeInfo(payload) {
807
- const { inputLength, recipients, isSendMax } = payload;
808
- const validAddressesInfo = recipients.map((recipient) => validate2(recipient.address) && getAddressInfo(recipient.address)).filter(Boolean);
809
- function getTxOutputsLengthByPaymentType() {
810
- return validAddressesInfo.reduce(
811
- (acc, { type }) => {
812
- acc[type] = (acc[type] || 0) + 1;
813
- return acc;
814
- },
815
- {}
816
- );
817
- }
818
- const outputTypesCount = getTxOutputsLengthByPaymentType();
819
- if (!isSendMax) {
820
- outputTypesCount[AddressType.p2wpkh] = (outputTypesCount[AddressType.p2wpkh] || 0) + 1;
821
- }
822
- const outputsData = Object.entries(outputTypesCount).reduce(
823
- (acc, [type, count]) => {
824
- acc[type + "_output_count"] = count;
825
- return acc;
826
- },
827
- {}
828
- );
829
- const txSizer = new BtcSizeFeeEstimator();
830
- const sizeInfo = txSizer.calcTxSize({
831
- input_script: "p2wpkh",
832
- input_count: inputLength,
833
- ...outputsData
834
- });
835
- return sizeInfo;
836
- }
837
- function getSpendableAmount({
838
- utxos,
839
- feeRate,
840
- recipients
841
- }) {
842
- const balance = utxos.map((utxo) => utxo.value).reduce((prevVal, curVal) => prevVal + curVal, 0);
843
- const size = getSizeInfo({
844
- inputLength: utxos.length,
845
- recipients
846
- });
847
- const fee = Math.ceil(size.txVBytes * feeRate);
848
- const bigNumberBalance = BigNumber2(balance);
849
- return {
850
- spendableAmount: BigNumber2.max(0, bigNumberBalance.minus(fee)),
851
- fee
852
- };
853
- }
854
- function filterUneconomicalUtxos({
855
- utxos,
856
- feeRate,
857
- recipients
858
- }) {
859
- const { spendableAmount: fullSpendableAmount } = getSpendableAmount({
860
- utxos,
861
- feeRate,
862
- recipients
863
- });
864
- const filteredUtxos = utxos.filter((utxo) => Number(utxo.value) >= BTC_P2WPKH_DUST_AMOUNT).filter((utxo) => {
865
- const { spendableAmount } = getSpendableAmount({
866
- utxos: utxos.filter((u) => u.txid !== utxo.txid),
867
- feeRate,
868
- recipients
869
- });
870
- return spendableAmount.toNumber() < fullSpendableAmount.toNumber();
871
- });
872
- return filteredUtxos;
698
+ const { inputLength, recipients, isSendMax } = payload;
699
+ const validAddressesInfo = recipients.map((recipient) => validate$1(recipient.address) && getAddressInfo(recipient.address)).filter(Boolean);
700
+ function getTxOutputsLengthByPaymentType() {
701
+ return validAddressesInfo.reduce((acc, { type }) => {
702
+ acc[type] = (acc[type] || 0) + 1;
703
+ return acc;
704
+ }, {});
705
+ }
706
+ const outputTypesCount = getTxOutputsLengthByPaymentType();
707
+ if (!isSendMax) outputTypesCount[AddressType.p2wpkh] = (outputTypesCount[AddressType.p2wpkh] || 0) + 1;
708
+ const outputsData = Object.entries(outputTypesCount).reduce((acc, [type, count]) => {
709
+ acc[type + "_output_count"] = count;
710
+ return acc;
711
+ }, {});
712
+ return new BtcSizeFeeEstimator().calcTxSize({
713
+ input_script: "p2wpkh",
714
+ input_count: inputLength,
715
+ ...outputsData
716
+ });
717
+ }
718
+ function getSpendableAmount({ utxos, feeRate, recipients }) {
719
+ const balance = utxos.map((utxo) => utxo.value).reduce((prevVal, curVal) => prevVal + curVal, 0);
720
+ const size = getSizeInfo({
721
+ inputLength: utxos.length,
722
+ recipients
723
+ });
724
+ const fee = Math.ceil(size.txVBytes * feeRate);
725
+ const bigNumberBalance = BigNumber(balance);
726
+ return {
727
+ spendableAmount: BigNumber.max(0, bigNumberBalance.minus(fee)),
728
+ fee
729
+ };
730
+ }
731
+ function filterUneconomicalUtxos({ utxos, feeRate, recipients }) {
732
+ const { spendableAmount: fullSpendableAmount } = getSpendableAmount({
733
+ utxos,
734
+ feeRate,
735
+ recipients
736
+ });
737
+ return utxos.filter((utxo) => Number(utxo.value) >= BTC_P2WPKH_DUST_AMOUNT).filter((utxo) => {
738
+ const { spendableAmount } = getSpendableAmount({
739
+ utxos: utxos.filter((u) => u.txid !== utxo.txid),
740
+ feeRate,
741
+ recipients
742
+ });
743
+ return spendableAmount.toNumber() < fullSpendableAmount.toNumber();
744
+ });
873
745
  }
874
746
 
875
- // src/coin-selection/calculate-max-spend.ts
876
- function calculateMaxSpend({
877
- recipient,
878
- utxos,
879
- feeRate,
880
- feeRates
881
- }) {
882
- if (!utxos.length || !feeRates)
883
- return {
884
- spendAllFee: 0,
885
- amount: createMoney(0, "BTC"),
886
- spendableBitcoin: new BigNumber3(0)
887
- };
888
- const currentFeeRate = feeRate ?? feeRates.halfHourFee.toNumber();
889
- const filteredUtxos = filterUneconomicalUtxos({
890
- utxos,
891
- feeRate: currentFeeRate,
892
- recipients: [{ address: recipient, amount: createMoney(0, "BTC") }]
893
- });
894
- const { spendableAmount, fee } = getSpendableAmount({
895
- utxos: filteredUtxos,
896
- feeRate: currentFeeRate,
897
- recipients: [{ address: recipient, amount: createMoney(0, "BTC") }],
898
- isSendMax: true
899
- });
900
- return {
901
- spendAllFee: fee,
902
- amount: createMoney(spendableAmount, "BTC"),
903
- spendableBitcoin: satToBtc(spendableAmount)
904
- };
747
+ //#endregion
748
+ //#region src/coin-selection/calculate-max-spend.ts
749
+ function calculateMaxSpend({ recipient, utxos, feeRate, feeRates }) {
750
+ if (!utxos.length || !feeRates) return {
751
+ spendAllFee: 0,
752
+ amount: createMoney(0, "BTC"),
753
+ spendableBitcoin: new BigNumber(0)
754
+ };
755
+ const currentFeeRate = feeRate ?? feeRates.halfHourFee.toNumber();
756
+ const { spendableAmount, fee } = getSpendableAmount({
757
+ utxos: filterUneconomicalUtxos({
758
+ utxos,
759
+ feeRate: currentFeeRate,
760
+ recipients: [{
761
+ address: recipient,
762
+ amount: createMoney(0, "BTC")
763
+ }]
764
+ }),
765
+ feeRate: currentFeeRate,
766
+ recipients: [{
767
+ address: recipient,
768
+ amount: createMoney(0, "BTC")
769
+ }],
770
+ isSendMax: true
771
+ });
772
+ return {
773
+ spendAllFee: fee,
774
+ amount: createMoney(spendableAmount, "BTC"),
775
+ spendableBitcoin: satToBtc(spendableAmount)
776
+ };
905
777
  }
906
778
 
907
- // src/coin-selection/coin-selection.ts
908
- import BigNumber4 from "bignumber.js";
909
- import { validate as validate3 } from "bitcoin-address-validation";
910
- import { BTC_P2WPKH_DUST_AMOUNT as BTC_P2WPKH_DUST_AMOUNT2 } from "@leather.io/constants";
911
- import { createMoney as createMoney2, sumMoney } from "@leather.io/utils";
912
- function determineUtxosForSpendAll({
913
- feeRate,
914
- recipients,
915
- utxos
916
- }) {
917
- recipients.forEach((recipient) => {
918
- if (!validate3(recipient.address)) throw new BitcoinError("InvalidAddress");
919
- });
920
- const filteredUtxos = filterUneconomicalUtxos({ utxos, feeRate, recipients });
921
- const sizeInfo = getSizeInfo({
922
- inputLength: filteredUtxos.length,
923
- isSendMax: true,
924
- recipients
925
- });
926
- const outputs = recipients.map(({ address: address2, amount }) => ({
927
- value: BigInt(amount.amount.toNumber()),
928
- address: address2
929
- }));
930
- const fee = Math.ceil(sizeInfo.txVBytes * feeRate);
931
- return {
932
- inputs: filteredUtxos,
933
- outputs,
934
- size: sizeInfo.txVBytes,
935
- fee: createMoney2(new BigNumber4(fee), "BTC")
936
- };
937
- }
938
- function determineUtxosForSpend({
939
- feeRate,
940
- recipients,
941
- utxos
942
- }) {
943
- recipients.forEach((recipient) => {
944
- if (!validate3(recipient.address)) throw new BitcoinError("InvalidAddress");
945
- });
946
- const filteredUtxos = filterUneconomicalUtxos({
947
- utxos: utxos.sort((a, b) => b.value - a.value),
948
- feeRate,
949
- recipients
950
- });
951
- if (!filteredUtxos.length) throw new BitcoinError("InsufficientFunds");
952
- const amount = sumMoney(recipients.map((recipient) => recipient.amount));
953
- const neededUtxos = [filteredUtxos[0]];
954
- function estimateTransactionSize() {
955
- return getSizeInfo({
956
- inputLength: neededUtxos.length,
957
- recipients
958
- });
959
- }
960
- function hasSufficientUtxosForTx() {
961
- const txEstimation = estimateTransactionSize();
962
- const neededAmount = new BigNumber4(txEstimation.txVBytes * feeRate).plus(amount.amount);
963
- return getUtxoTotal(neededUtxos).isGreaterThanOrEqualTo(neededAmount);
964
- }
965
- function getRemainingUnspentUtxos() {
966
- return filteredUtxos.filter((utxo) => !neededUtxos.includes(utxo));
967
- }
968
- while (!hasSufficientUtxosForTx()) {
969
- const [nextUtxo] = getRemainingUnspentUtxos();
970
- if (!nextUtxo) throw new BitcoinError("InsufficientFunds");
971
- neededUtxos.push(nextUtxo);
972
- }
973
- const fee = Math.ceil(
974
- new BigNumber4(estimateTransactionSize().txVBytes).multipliedBy(feeRate).toNumber()
975
- );
976
- const changeAmount = BigInt(getUtxoTotal(neededUtxos).toString()) - BigInt(amount.amount.toNumber()) - BigInt(fee);
977
- const changeUtxos = changeAmount > BTC_P2WPKH_DUST_AMOUNT2 ? [
978
- {
979
- value: changeAmount
980
- }
981
- ] : [];
982
- const outputs = [
983
- ...recipients.map(({ address: address2, amount: amount2 }) => ({
984
- value: BigInt(amount2.amount.toNumber()),
985
- address: address2
986
- })),
987
- ...changeUtxos
988
- ];
989
- return {
990
- filteredUtxos,
991
- inputs: neededUtxos,
992
- outputs,
993
- size: estimateTransactionSize().txVBytes,
994
- fee: createMoney2(new BigNumber4(fee), "BTC"),
995
- ...estimateTransactionSize()
996
- };
779
+ //#endregion
780
+ //#region src/coin-selection/coin-selection.ts
781
+ function determineUtxosForSpendAll({ feeRate, recipients, utxos }) {
782
+ recipients.forEach((recipient) => {
783
+ if (!validate(recipient.address)) throw new BitcoinError("InvalidAddress");
784
+ });
785
+ const filteredUtxos = filterUneconomicalUtxos({
786
+ utxos,
787
+ feeRate,
788
+ recipients
789
+ });
790
+ const sizeInfo = getSizeInfo({
791
+ inputLength: filteredUtxos.length,
792
+ isSendMax: true,
793
+ recipients
794
+ });
795
+ const outputs = recipients.map(({ address, amount }) => ({
796
+ value: BigInt(amount.amount.toNumber()),
797
+ address
798
+ }));
799
+ const fee = Math.ceil(sizeInfo.txVBytes * feeRate);
800
+ return {
801
+ inputs: filteredUtxos,
802
+ outputs,
803
+ size: sizeInfo.txVBytes,
804
+ fee: createMoney(new BigNumber(fee), "BTC")
805
+ };
806
+ }
807
+ function determineUtxosForSpend({ feeRate, recipients, utxos }) {
808
+ recipients.forEach((recipient) => {
809
+ if (!validate(recipient.address)) throw new BitcoinError("InvalidAddress");
810
+ });
811
+ const filteredUtxos = filterUneconomicalUtxos({
812
+ utxos: utxos.sort((a, b) => b.value - a.value),
813
+ feeRate,
814
+ recipients
815
+ });
816
+ if (!filteredUtxos.length) throw new BitcoinError("InsufficientFunds");
817
+ const amount = sumMoney(recipients.map((recipient) => recipient.amount));
818
+ const neededUtxos = [filteredUtxos[0]];
819
+ function estimateTransactionSize() {
820
+ return getSizeInfo({
821
+ inputLength: neededUtxos.length,
822
+ recipients
823
+ });
824
+ }
825
+ function hasSufficientUtxosForTx() {
826
+ const neededAmount = new BigNumber(estimateTransactionSize().txVBytes * feeRate).plus(amount.amount);
827
+ return getUtxoTotal(neededUtxos).isGreaterThanOrEqualTo(neededAmount);
828
+ }
829
+ function getRemainingUnspentUtxos() {
830
+ return filteredUtxos.filter((utxo) => !neededUtxos.includes(utxo));
831
+ }
832
+ while (!hasSufficientUtxosForTx()) {
833
+ const [nextUtxo] = getRemainingUnspentUtxos();
834
+ if (!nextUtxo) throw new BitcoinError("InsufficientFunds");
835
+ neededUtxos.push(nextUtxo);
836
+ }
837
+ const fee = Math.ceil(new BigNumber(estimateTransactionSize().txVBytes).multipliedBy(feeRate).toNumber());
838
+ const changeAmount = BigInt(getUtxoTotal(neededUtxos).toString()) - BigInt(amount.amount.toNumber()) - BigInt(fee);
839
+ const changeUtxos = changeAmount > BTC_P2WPKH_DUST_AMOUNT ? [{ value: changeAmount }] : [];
840
+ return {
841
+ filteredUtxos,
842
+ inputs: neededUtxos,
843
+ outputs: [...recipients.map(({ address, amount: amount$1 }) => ({
844
+ value: BigInt(amount$1.amount.toNumber()),
845
+ address
846
+ })), ...changeUtxos],
847
+ size: estimateTransactionSize().txVBytes,
848
+ fee: createMoney(new BigNumber(fee), "BTC"),
849
+ ...estimateTransactionSize()
850
+ };
997
851
  }
998
852
 
999
- // src/fees/bitcoin-fees.ts
853
+ //#endregion
854
+ //#region src/fees/bitcoin-fees.ts
1000
855
  function getBitcoinTransactionFee({ isSendingMax, ...props }) {
1001
- try {
1002
- const { fee } = isSendingMax ? determineUtxosForSpendAll({ ...props }) : determineUtxosForSpend({ ...props });
1003
- return fee;
1004
- } catch {
1005
- return null;
1006
- }
856
+ try {
857
+ const { fee } = isSendingMax ? determineUtxosForSpendAll({ ...props }) : determineUtxosForSpend({ ...props });
858
+ return fee;
859
+ } catch {
860
+ return null;
861
+ }
1007
862
  }
1008
863
  function getBitcoinFees({ feeRates, isSendingMax, recipients, utxos }) {
1009
- const defaultArgs = {
1010
- isSendingMax,
1011
- recipients,
1012
- utxos
1013
- };
1014
- const highFeeRate = feeRates.fastestFee.toNumber();
1015
- const standardFeeRate = feeRates.halfHourFee.toNumber();
1016
- const lowFeeRate = feeRates.hourFee.toNumber();
1017
- const highFeeValue = getBitcoinTransactionFee({
1018
- ...defaultArgs,
1019
- feeRate: highFeeRate
1020
- });
1021
- const standardFeeValue = getBitcoinTransactionFee({
1022
- ...defaultArgs,
1023
- feeRate: standardFeeRate
1024
- });
1025
- const lowFeeValue = getBitcoinTransactionFee({
1026
- ...defaultArgs,
1027
- feeRate: lowFeeRate
1028
- });
1029
- return {
1030
- high: { feeRate: highFeeRate, fee: highFeeValue },
1031
- standard: { feeRate: standardFeeRate, fee: standardFeeValue },
1032
- low: { feeRate: lowFeeRate, fee: lowFeeValue }
1033
- };
864
+ const defaultArgs = {
865
+ isSendingMax,
866
+ recipients,
867
+ utxos
868
+ };
869
+ const highFeeRate = feeRates.fastestFee.toNumber();
870
+ const standardFeeRate = feeRates.halfHourFee.toNumber();
871
+ const lowFeeRate = feeRates.hourFee.toNumber();
872
+ const highFeeValue = getBitcoinTransactionFee({
873
+ ...defaultArgs,
874
+ feeRate: highFeeRate
875
+ });
876
+ const standardFeeValue = getBitcoinTransactionFee({
877
+ ...defaultArgs,
878
+ feeRate: standardFeeRate
879
+ });
880
+ const lowFeeValue = getBitcoinTransactionFee({
881
+ ...defaultArgs,
882
+ feeRate: lowFeeRate
883
+ });
884
+ return {
885
+ high: {
886
+ feeRate: highFeeRate,
887
+ fee: highFeeValue
888
+ },
889
+ standard: {
890
+ feeRate: standardFeeRate,
891
+ fee: standardFeeValue
892
+ },
893
+ low: {
894
+ feeRate: lowFeeRate,
895
+ fee: lowFeeValue
896
+ }
897
+ };
1034
898
  }
1035
899
 
1036
- // src/mocks/mocks.ts
1037
- var TEST_ACCOUNT_1_NATIVE_SEGWIT_ADDRESS = createBitcoinAddress(
1038
- "bc1q530dz4h80kwlzywlhx2qn0k6vdtftd93c499yq"
1039
- );
1040
- var TEST_ACCOUNT_1_TAPROOT_ADDRESS = createBitcoinAddress(
1041
- "bc1putuzj9lyfcm8fef9jpy85nmh33cxuq9u6wyuk536t9kemdk37yjqmkc0pg"
1042
- );
1043
- var TEST_ACCOUNT_2_TAPROOT_ADDRESS = createBitcoinAddress(
1044
- "bc1pmk2sacpfyy4v5phl8tq6eggu4e8laztep7fsgkkx0nc6m9vydjesaw0g2r"
1045
- );
1046
- var TEST_TESNET_ACCOUNT_1_NATIVE_SEGWIT_ADDRESS = createBitcoinAddress(
1047
- "tb1q4qgnjewwun2llgken94zqjrx5kpqqycaz5522d"
1048
- );
1049
- var TEST_TESTNET_ACCOUNT_2_BTC_ADDRESS = createBitcoinAddress(
1050
- "tb1qr8me8t9gu9g6fu926ry5v44yp0wyljrespjtnz"
1051
- );
1052
- var TEST_TESTNET_ACCOUNT_2_TAPROOT_ADDRESS = createBitcoinAddress(
1053
- "tb1pve00jmp43whpqj2wpcxtc7m8wqhz0azq689y4r7h8tmj8ltaj87qj2nj6w"
1054
- );
1055
- var recipientAddress = createBitcoinAddress("tb1qt28eagxcl9gvhq2rpj5slg7dwgxae2dn2hk93m");
1056
- var legacyAddress = createBitcoinAddress("15PyZveQd28E2SHZu2ugkWZBp6iER41vXj");
1057
- var segwitAddress = createBitcoinAddress("33SVjoCHJovrXxjDKLFSXo1h3t5KgkPzfH");
1058
- var taprootAddress = createBitcoinAddress(
1059
- "tb1parwmj7533de3k2fw2kntyqacspvhm67qnjcmpqnnpfvzu05l69nsczdywd"
1060
- );
1061
- var invalidAddress = "whoop-de-da-boop-da-de-not-a-bitcoin-address";
1062
- var inValidCharactersAddress = createBitcoinAddress(
1063
- "tb1&*%wmj7533de3k2fw2kntyqacspvhm67qnjcmpqnnpfvzu05l69nsczdywd"
1064
- );
1065
- var inValidLengthAddress = createBitcoinAddress("tb1parwmj7533de3k2fw2kntyqacspvhm67wd");
900
+ //#endregion
901
+ //#region src/mocks/mocks.ts
902
+ const TEST_ACCOUNT_1_NATIVE_SEGWIT_ADDRESS = createBitcoinAddress("bc1q530dz4h80kwlzywlhx2qn0k6vdtftd93c499yq");
903
+ const TEST_ACCOUNT_1_TAPROOT_ADDRESS = createBitcoinAddress("bc1putuzj9lyfcm8fef9jpy85nmh33cxuq9u6wyuk536t9kemdk37yjqmkc0pg");
904
+ const TEST_ACCOUNT_2_TAPROOT_ADDRESS = createBitcoinAddress("bc1pmk2sacpfyy4v5phl8tq6eggu4e8laztep7fsgkkx0nc6m9vydjesaw0g2r");
905
+ const TEST_TESNET_ACCOUNT_1_NATIVE_SEGWIT_ADDRESS = createBitcoinAddress("tb1q4qgnjewwun2llgken94zqjrx5kpqqycaz5522d");
906
+ const TEST_TESTNET_ACCOUNT_2_BTC_ADDRESS = createBitcoinAddress("tb1qr8me8t9gu9g6fu926ry5v44yp0wyljrespjtnz");
907
+ const TEST_TESTNET_ACCOUNT_2_TAPROOT_ADDRESS = createBitcoinAddress("tb1pve00jmp43whpqj2wpcxtc7m8wqhz0azq689y4r7h8tmj8ltaj87qj2nj6w");
908
+ const recipientAddress = createBitcoinAddress("tb1qt28eagxcl9gvhq2rpj5slg7dwgxae2dn2hk93m");
909
+ const legacyAddress = createBitcoinAddress("15PyZveQd28E2SHZu2ugkWZBp6iER41vXj");
910
+ const segwitAddress = createBitcoinAddress("33SVjoCHJovrXxjDKLFSXo1h3t5KgkPzfH");
911
+ const taprootAddress = createBitcoinAddress("tb1parwmj7533de3k2fw2kntyqacspvhm67qnjcmpqnnpfvzu05l69nsczdywd");
912
+ const invalidAddress = "whoop-de-da-boop-da-de-not-a-bitcoin-address";
913
+ const inValidCharactersAddress = createBitcoinAddress("tb1&*%wmj7533de3k2fw2kntyqacspvhm67qnjcmpqnnpfvzu05l69nsczdywd");
914
+ const inValidLengthAddress = createBitcoinAddress("tb1parwmj7533de3k2fw2kntyqacspvhm67wd");
1066
915
 
1067
- // src/schemas/address-schema.ts
1068
- import { Network as Network2, getAddressInfo as getAddressInfo2, validate as validate4 } from "bitcoin-address-validation";
1069
- import { z } from "zod";
1070
- import { isEmptyString as isEmptyString2, isUndefined as isUndefined2 } from "@leather.io/utils";
916
+ //#endregion
917
+ //#region src/schemas/address-schema.ts
1071
918
  function nonEmptyStringValidator(message = "") {
1072
- return z.string().refine((value) => value !== void 0 && value.trim() !== "", { message });
919
+ return z.string().refine((value) => value !== void 0 && value.trim() !== "", { message });
1073
920
  }
1074
921
  function btcAddressValidator() {
1075
- return z.string().refine(
1076
- (value) => {
1077
- if (isUndefined2(value) || isEmptyString2(value)) return true;
1078
- return validate4(value);
1079
- },
1080
- { message: "Bitcoin address is not valid" }
1081
- );
922
+ return z.string().refine((value) => {
923
+ if (isUndefined(value) || isEmptyString(value)) return true;
924
+ return validate(value);
925
+ }, { message: "Bitcoin address is not valid" });
1082
926
  }
1083
- function getNetworkTypeFromAddress(address2) {
1084
- return getAddressInfo2(address2).network;
927
+ function getNetworkTypeFromAddress(address) {
928
+ return getAddressInfo(address).network;
1085
929
  }
1086
930
  function btcAddressNetworkValidatorFactory(network) {
1087
- function getAddressNetworkType(network2) {
1088
- if (network2 === "signet") return Network2.testnet;
1089
- return network2;
1090
- }
1091
- return (value) => {
1092
- if (isUndefined2(value) || isEmptyString2(value)) return true;
1093
- return validate4(value, getAddressNetworkType(network));
1094
- };
931
+ function getAddressNetworkType(network$1) {
932
+ if (network$1 === "signet") return Network.testnet;
933
+ return network$1;
934
+ }
935
+ return (value) => {
936
+ if (isUndefined(value) || isEmptyString(value)) return true;
937
+ return validate(value, getAddressNetworkType(network));
938
+ };
1095
939
  }
1096
940
  function btcAddressNetworkValidator(network) {
1097
- return z.string().refine(btcAddressNetworkValidatorFactory(network), {
1098
- message: "Address is for incorrect network"
1099
- });
941
+ return z.string().refine(btcAddressNetworkValidatorFactory(network), { message: "Address is for incorrect network" });
1100
942
  }
1101
943
 
1102
- // src/payments/p2wsh-p2sh-address-gen.ts
1103
- import { ripemd160 } from "@noble/hashes/ripemd160";
1104
- import { sha256 as sha2562 } from "@noble/hashes/sha256";
1105
- import { base58check } from "@scure/base";
1106
- import { deriveBip39SeedFromMnemonic, deriveRootBip32Keychain } from "@leather.io/crypto";
1107
- var deriveBtcBip49SeedFromMnemonic = deriveBip39SeedFromMnemonic;
1108
- var deriveRootBtcKeychain = deriveRootBip32Keychain;
944
+ //#endregion
945
+ //#region src/payments/p2wsh-p2sh-address-gen.ts
946
+ /**
947
+ * @deprecated
948
+ * Use `deriveBip39MnemonicFromSeed` from `@leather.io/crypto`
949
+ */
950
+ const deriveBtcBip49SeedFromMnemonic = deriveBip39SeedFromMnemonic;
951
+ /**
952
+ * @deprecated
953
+ * Use `deriveRootBip32Keychain` from `@leather.io/crypto`
954
+ */
955
+ const deriveRootBtcKeychain = deriveRootBip32Keychain;
1109
956
  function decodeCompressedWifPrivateKey(key) {
1110
- const compressedWifFormatPrivateKey = base58check(sha2562).decode(key);
1111
- return compressedWifFormatPrivateKey.slice(1, compressedWifFormatPrivateKey.length - 1);
1112
- }
1113
- var payToScriptHashMainnetPrefix = 5;
1114
- var payToScriptHashTestnetPrefix = 196;
1115
- var payToScriptHashPrefixMap = {
1116
- mainnet: payToScriptHashMainnetPrefix,
1117
- testnet: payToScriptHashTestnetPrefix
957
+ const compressedWifFormatPrivateKey = base58check(sha256).decode(key);
958
+ return compressedWifFormatPrivateKey.slice(1, compressedWifFormatPrivateKey.length - 1);
959
+ }
960
+ const payToScriptHashMainnetPrefix = 5;
961
+ const payToScriptHashTestnetPrefix = 196;
962
+ const payToScriptHashPrefixMap = {
963
+ mainnet: payToScriptHashMainnetPrefix,
964
+ testnet: payToScriptHashTestnetPrefix
1118
965
  };
1119
966
  function hash160(input) {
1120
- return ripemd160(sha2562(input));
967
+ return ripemd160(sha256(input));
1121
968
  }
1122
969
  function makePayToScriptHashKeyHash(publicKey) {
1123
- return hash160(publicKey);
970
+ return hash160(publicKey);
1124
971
  }
1125
972
  function makePayToScriptHashAddressBytes(keyHash) {
1126
- const redeemScript = Uint8Array.from([
1127
- ...Uint8Array.of(0),
1128
- ...Uint8Array.of(keyHash.length),
1129
- ...keyHash
1130
- ]);
1131
- return hash160(redeemScript);
973
+ return hash160(Uint8Array.from([
974
+ ...Uint8Array.of(0),
975
+ ...Uint8Array.of(keyHash.length),
976
+ ...keyHash
977
+ ]));
1132
978
  }
1133
979
  function makePayToScriptHashAddress(addressBytes, network) {
1134
- const networkByte = payToScriptHashPrefixMap[network];
1135
- const addressWithPrefix = Uint8Array.from([networkByte, ...addressBytes]);
1136
- return base58check(sha2562).encode(addressWithPrefix);
980
+ const networkByte = payToScriptHashPrefixMap[network];
981
+ const addressWithPrefix = Uint8Array.from([networkByte, ...addressBytes]);
982
+ return base58check(sha256).encode(addressWithPrefix);
1137
983
  }
1138
984
  function publicKeyToPayToScriptHashAddress(publicKey, network) {
1139
- const hash = makePayToScriptHashKeyHash(publicKey);
1140
- const addrBytes = makePayToScriptHashAddressBytes(hash);
1141
- return makePayToScriptHashAddress(addrBytes, network);
985
+ return makePayToScriptHashAddress(makePayToScriptHashAddressBytes(makePayToScriptHashKeyHash(publicKey)), network);
1142
986
  }
1143
987
 
1144
- // src/psbt/psbt-totals.ts
1145
- import { createMoney as createMoney3, sumNumbers as sumNumbers2 } from "@leather.io/utils";
988
+ //#endregion
989
+ //#region src/psbt/psbt-totals.ts
1146
990
  function calculateAddressInputsTotal(addresses, inputs) {
1147
- const sumsByAddress = addresses.map(
1148
- (address2) => inputs.filter((input) => input.address === address2).map((input) => input.value).reduce((acc, curVal) => acc + curVal, 0)
1149
- );
1150
- return createMoney3(sumNumbers2(sumsByAddress), "BTC");
991
+ return createMoney(sumNumbers(addresses.map((address) => inputs.filter((input) => input.address === address).map((input) => input.value).reduce((acc, curVal) => acc + curVal, 0))), "BTC");
1151
992
  }
1152
993
  function calculateAddressOutputsTotal(addresses, outputs) {
1153
- const sumsByAddress = addresses.map(
1154
- (address2) => outputs.filter((output) => output.address === address2).map((output) => Number(output.value)).reduce((acc, curVal) => acc + curVal, 0)
1155
- );
1156
- return createMoney3(sumNumbers2(sumsByAddress), "BTC");
994
+ return createMoney(sumNumbers(addresses.map((address) => outputs.filter((output) => output.address === address).map((output) => Number(output.value)).reduce((acc, curVal) => acc + curVal, 0))), "BTC");
1157
995
  }
1158
996
  function calculatePsbtInputsTotal(inputs) {
1159
- return createMoney3(sumNumbers2(inputs.map((input) => input.value)), "BTC");
997
+ return createMoney(sumNumbers(inputs.map((input) => input.value)), "BTC");
1160
998
  }
1161
999
  function calculatePsbtOutputsTotal(outputs) {
1162
- return createMoney3(sumNumbers2(outputs.map((output) => output.value)), "BTC");
1000
+ return createMoney(sumNumbers(outputs.map((output) => output.value)), "BTC");
1163
1001
  }
1164
1002
  function getPsbtTotals({ psbtAddresses, parsedInputs, parsedOutputs }) {
1165
- const nativeSegwitAddresses = psbtAddresses.filter(
1166
- (addr) => inferPaymentTypeFromAddress(addr) === "p2wpkh"
1167
- );
1168
- const taprootAddresses = psbtAddresses.filter(
1169
- (addr) => inferPaymentTypeFromAddress(addr) === "p2tr"
1170
- );
1171
- return {
1172
- inputsTotalNativeSegwit: calculateAddressInputsTotal(nativeSegwitAddresses, parsedInputs),
1173
- inputsTotalTaproot: calculateAddressInputsTotal(taprootAddresses, parsedInputs),
1174
- outputsTotalNativeSegwit: calculateAddressOutputsTotal(nativeSegwitAddresses, parsedOutputs),
1175
- outputsTotalTaproot: calculateAddressOutputsTotal(taprootAddresses, parsedOutputs),
1176
- psbtInputsTotal: calculatePsbtInputsTotal(parsedInputs),
1177
- psbtOutputsTotal: calculatePsbtOutputsTotal(parsedOutputs)
1178
- };
1003
+ const nativeSegwitAddresses = psbtAddresses.filter((addr) => inferPaymentTypeFromAddress(addr) === "p2wpkh");
1004
+ const taprootAddresses = psbtAddresses.filter((addr) => inferPaymentTypeFromAddress(addr) === "p2tr");
1005
+ return {
1006
+ inputsTotalNativeSegwit: calculateAddressInputsTotal(nativeSegwitAddresses, parsedInputs),
1007
+ inputsTotalTaproot: calculateAddressInputsTotal(taprootAddresses, parsedInputs),
1008
+ outputsTotalNativeSegwit: calculateAddressOutputsTotal(nativeSegwitAddresses, parsedOutputs),
1009
+ outputsTotalTaproot: calculateAddressOutputsTotal(taprootAddresses, parsedOutputs),
1010
+ psbtInputsTotal: calculatePsbtInputsTotal(parsedInputs),
1011
+ psbtOutputsTotal: calculatePsbtOutputsTotal(parsedOutputs)
1012
+ };
1179
1013
  }
1180
1014
 
1181
- // src/psbt/psbt-inputs.ts
1182
- import { bytesToHex } from "@noble/hashes/utils";
1183
- import { isDefined as isDefined2, isUndefined as isUndefined3 } from "@leather.io/utils";
1184
- function getParsedInputs({
1185
- inputs,
1186
- indexesToSign,
1187
- networkMode,
1188
- psbtAddresses
1189
- }) {
1190
- const bitcoinNetwork = getBtcSignerLibNetworkConfigByMode(networkMode);
1191
- const signAll = isUndefined3(indexesToSign);
1192
- const psbtInputs = inputs.map((input, i) => {
1193
- const bitcoinAddress = isDefined2(input.index) ? getBitcoinInputAddress(input, bitcoinNetwork) : null;
1194
- if (bitcoinAddress === null) {
1195
- throw new Error("PSBT input has unsupported bitcoin address");
1196
- }
1197
- const isCurrentAddress = psbtAddresses.includes(bitcoinAddress);
1198
- const canChange = isCurrentAddress && !(!input.sighashType || input.sighashType === 0 || input.sighashType === 1);
1199
- const toSignAll = isCurrentAddress && signAll;
1200
- const toSignIndex = isCurrentAddress && !signAll && indexesToSign.includes(i);
1201
- return {
1202
- address: bitcoinAddress,
1203
- index: input.index,
1204
- bip32Derivation: input.bip32Derivation,
1205
- tapBip32Derivation: input.tapBip32Derivation,
1206
- // inscription: inscriptions[i],
1207
- isMutable: canChange,
1208
- toSign: toSignAll || toSignIndex,
1209
- txid: input.txid ? bytesToHex(input.txid) : "",
1210
- value: isDefined2(input.index) ? getBitcoinInputValue(input) : 0
1211
- };
1212
- });
1213
- const isPsbtMutable = psbtInputs.some((input) => input.isMutable);
1214
- return { isPsbtMutable, parsedInputs: psbtInputs };
1015
+ //#endregion
1016
+ //#region src/psbt/psbt-inputs.ts
1017
+ function getParsedInputs({ inputs, indexesToSign, networkMode, psbtAddresses }) {
1018
+ const bitcoinNetwork = getBtcSignerLibNetworkConfigByMode(networkMode);
1019
+ const signAll = isUndefined(indexesToSign);
1020
+ const psbtInputs = inputs.map((input, i) => {
1021
+ const bitcoinAddress = isDefined(input.index) ? getBitcoinInputAddress(input, bitcoinNetwork) : null;
1022
+ if (bitcoinAddress === null) throw new Error("PSBT input has unsupported bitcoin address");
1023
+ const isCurrentAddress = psbtAddresses.includes(bitcoinAddress);
1024
+ const canChange = isCurrentAddress && !(!input.sighashType || input.sighashType === 0 || input.sighashType === 1);
1025
+ const toSignAll = isCurrentAddress && signAll;
1026
+ const toSignIndex = isCurrentAddress && !signAll && indexesToSign.includes(i);
1027
+ return {
1028
+ address: bitcoinAddress,
1029
+ index: input.index,
1030
+ bip32Derivation: input.bip32Derivation,
1031
+ tapBip32Derivation: input.tapBip32Derivation,
1032
+ isMutable: canChange,
1033
+ toSign: toSignAll || toSignIndex,
1034
+ txid: input.txid ? bytesToHex(input.txid) : "",
1035
+ value: isDefined(input.index) ? getBitcoinInputValue(input) : 0
1036
+ };
1037
+ });
1038
+ return {
1039
+ isPsbtMutable: psbtInputs.some((input) => input.isMutable),
1040
+ parsedInputs: psbtInputs
1041
+ };
1215
1042
  }
1216
1043
 
1217
- // src/psbt/psbt-outputs.ts
1218
- import { isDefined as isDefined3, isUndefined as isUndefined4 } from "@leather.io/utils";
1219
- function getParsedOutputs({
1220
- isPsbtMutable,
1221
- outputs,
1222
- networkMode,
1223
- psbtAddresses
1224
- }) {
1225
- const bitcoinNetwork = getBtcSignerLibNetworkConfigByMode(networkMode);
1226
- return outputs.map((output) => {
1227
- if (isUndefined4(output.script)) {
1228
- return;
1229
- }
1230
- const outputAddress = getAddressFromOutScript(output.script, bitcoinNetwork);
1231
- const isCurrentAddress = !!outputAddress && psbtAddresses.includes(outputAddress);
1232
- return {
1233
- address: outputAddress,
1234
- isMutable: isPsbtMutable,
1235
- toSign: isCurrentAddress,
1236
- value: Number(output.amount)
1237
- };
1238
- }).filter(isDefined3);
1044
+ //#endregion
1045
+ //#region src/psbt/psbt-outputs.ts
1046
+ function getParsedOutputs({ isPsbtMutable, outputs, networkMode, psbtAddresses }) {
1047
+ const bitcoinNetwork = getBtcSignerLibNetworkConfigByMode(networkMode);
1048
+ return outputs.map((output) => {
1049
+ if (isUndefined(output.script)) return;
1050
+ const outputAddress = getAddressFromOutScript(output.script, bitcoinNetwork);
1051
+ return {
1052
+ address: outputAddress,
1053
+ isMutable: isPsbtMutable,
1054
+ toSign: !!outputAddress && psbtAddresses.includes(outputAddress),
1055
+ value: Number(output.amount)
1056
+ };
1057
+ }).filter(isDefined);
1239
1058
  }
1240
1059
 
1241
- // src/psbt/psbt-details.ts
1242
- import { createMoney as createMoney4, subtractMoney } from "@leather.io/utils";
1243
-
1244
- // src/psbt/utils.ts
1245
- import { hexToBytes as hexToBytes3 } from "@noble/hashes/utils";
1246
- import * as btc4 from "@scure/btc-signer";
1247
- import { RawPSBTV0, RawPSBTV2 } from "@scure/btc-signer/psbt";
1248
- import { isString as isString2 } from "@leather.io/utils";
1060
+ //#endregion
1061
+ //#region src/psbt/utils.ts
1249
1062
  function getPsbtAsTransaction(psbt) {
1250
- const bytes = isString2(psbt) ? hexToBytes3(psbt) : psbt;
1251
- return btc4.Transaction.fromPSBT(bytes);
1063
+ const bytes = isString(psbt) ? hexToBytes(psbt) : psbt;
1064
+ return btc.Transaction.fromPSBT(bytes);
1252
1065
  }
1253
1066
  function getRawPsbt(psbt) {
1254
- const bytes = isString2(psbt) ? hexToBytes3(psbt) : psbt;
1255
- try {
1256
- return RawPSBTV0.decode(bytes);
1257
- } catch (e1) {
1258
- try {
1259
- return RawPSBTV2.decode(bytes);
1260
- } catch (e2) {
1261
- throw new Error(`Unable to decode PSBT, ${e1 ?? e2}`);
1262
- }
1263
- }
1067
+ const bytes = isString(psbt) ? hexToBytes(psbt) : psbt;
1068
+ try {
1069
+ return RawPSBTV0.decode(bytes);
1070
+ } catch (e1) {
1071
+ try {
1072
+ return RawPSBTV2.decode(bytes);
1073
+ } catch (e2) {
1074
+ throw new Error(`Unable to decode PSBT, ${e1 ?? e2}`);
1075
+ }
1076
+ }
1264
1077
  }
1265
1078
 
1266
- // src/psbt/psbt-details.ts
1267
- function getPsbtDetails({
1268
- psbtHex,
1269
- networkMode,
1270
- indexesToSign,
1271
- psbtAddresses
1272
- }) {
1273
- const tx = getPsbtAsTransaction(psbtHex);
1274
- const inputs = getPsbtTxInputs(tx);
1275
- const outputs = getPsbtTxOutputs(tx);
1276
- const { isPsbtMutable, parsedInputs } = getParsedInputs({
1277
- inputs,
1278
- indexesToSign,
1279
- networkMode,
1280
- psbtAddresses
1281
- });
1282
- const parsedOutputs = getParsedOutputs({ isPsbtMutable, outputs, networkMode, psbtAddresses });
1283
- const {
1284
- inputsTotalNativeSegwit,
1285
- inputsTotalTaproot,
1286
- outputsTotalNativeSegwit,
1287
- outputsTotalTaproot,
1288
- psbtInputsTotal,
1289
- psbtOutputsTotal
1290
- } = getPsbtTotals({
1291
- psbtAddresses,
1292
- parsedInputs,
1293
- parsedOutputs
1294
- });
1295
- function getFee() {
1296
- if (psbtInputsTotal.amount.isGreaterThan(psbtOutputsTotal.amount))
1297
- return subtractMoney(psbtInputsTotal, psbtOutputsTotal);
1298
- return createMoney4(0, "BTC");
1299
- }
1300
- return {
1301
- addressNativeSegwitTotal: subtractMoney(inputsTotalNativeSegwit, outputsTotalNativeSegwit),
1302
- addressTaprootTotal: subtractMoney(inputsTotalTaproot, outputsTotalTaproot),
1303
- fee: getFee(),
1304
- isPsbtMutable,
1305
- psbtInputs: parsedInputs,
1306
- psbtOutputs: parsedOutputs
1307
- };
1079
+ //#endregion
1080
+ //#region src/psbt/psbt-details.ts
1081
+ function getPsbtDetails({ psbtHex, networkMode, indexesToSign, psbtAddresses }) {
1082
+ const tx = getPsbtAsTransaction(psbtHex);
1083
+ const inputs = getPsbtTxInputs(tx);
1084
+ const outputs = getPsbtTxOutputs(tx);
1085
+ const { isPsbtMutable, parsedInputs } = getParsedInputs({
1086
+ inputs,
1087
+ indexesToSign,
1088
+ networkMode,
1089
+ psbtAddresses
1090
+ });
1091
+ const parsedOutputs = getParsedOutputs({
1092
+ isPsbtMutable,
1093
+ outputs,
1094
+ networkMode,
1095
+ psbtAddresses
1096
+ });
1097
+ const { inputsTotalNativeSegwit, inputsTotalTaproot, outputsTotalNativeSegwit, outputsTotalTaproot, psbtInputsTotal, psbtOutputsTotal } = getPsbtTotals({
1098
+ psbtAddresses,
1099
+ parsedInputs,
1100
+ parsedOutputs
1101
+ });
1102
+ function getFee() {
1103
+ if (psbtInputsTotal.amount.isGreaterThan(psbtOutputsTotal.amount)) return subtractMoney(psbtInputsTotal, psbtOutputsTotal);
1104
+ return createMoney(0, "BTC");
1105
+ }
1106
+ return {
1107
+ addressNativeSegwitTotal: subtractMoney(inputsTotalNativeSegwit, outputsTotalNativeSegwit),
1108
+ addressTaprootTotal: subtractMoney(inputsTotalTaproot, outputsTotalTaproot),
1109
+ fee: getFee(),
1110
+ isPsbtMutable,
1111
+ psbtInputs: parsedInputs,
1112
+ psbtOutputs: parsedOutputs
1113
+ };
1308
1114
  }
1309
1115
 
1310
- // src/signer/bitcoin-signer.ts
1311
- import { HARDENED_OFFSET } from "@scure/bip32";
1312
- import * as btc5 from "@scure/btc-signer";
1313
- import {
1314
- DerivationPathDepth as DerivationPathDepth4,
1315
- appendAddressIndexToPath,
1316
- decomposeDescriptor,
1317
- deriveKeychainFromXpub,
1318
- extractAddressIndexFromPath,
1319
- extractChangeIndexFromPath,
1320
- keyOriginToDerivationPath
1321
- } from "@leather.io/crypto";
1322
- import { hexToNumber, toHexString } from "@leather.io/utils";
1116
+ //#endregion
1117
+ //#region src/signer/bitcoin-signer.ts
1323
1118
  function initializeBitcoinAccountKeychainFromDescriptor(descriptor) {
1324
- const { fingerprint, keyOrigin } = decomposeDescriptor(descriptor);
1325
- return {
1326
- descriptor,
1327
- xpub: extractExtendedPublicKeyFromPolicy(descriptor),
1328
- keyOrigin,
1329
- masterKeyFingerprint: fingerprint,
1330
- keychain: deriveKeychainFromXpub(extractExtendedPublicKeyFromPolicy(descriptor))
1331
- };
1119
+ const { fingerprint, keyOrigin } = decomposeDescriptor(descriptor);
1120
+ return {
1121
+ descriptor,
1122
+ xpub: extractExtendedPublicKeyFromPolicy(descriptor),
1123
+ keyOrigin,
1124
+ masterKeyFingerprint: fingerprint,
1125
+ keychain: deriveKeychainFromXpub(extractExtendedPublicKeyFromPolicy(descriptor))
1126
+ };
1332
1127
  }
1333
1128
  function deriveBitcoinPayerFromAccount(descriptor, network) {
1334
- const { fingerprint, keyOrigin } = decomposeDescriptor(descriptor);
1335
- const accountKeychain = deriveKeychainFromXpub(extractExtendedPublicKeyFromPolicy(descriptor));
1336
- const paymentType = inferPaymentTypeFromPath(keyOrigin);
1337
- if (accountKeychain.depth !== DerivationPathDepth4.Account)
1338
- throw new Error("Keychain passed is not an account");
1339
- return ({ change, addressIndex }) => {
1340
- const childKeychain = accountKeychain.deriveChild(change).deriveChild(addressIndex);
1341
- const derivePayerFromAccount = whenSupportedPaymentType(paymentType)({
1342
- p2tr: getTaprootPaymentFromAddressIndex,
1343
- p2wpkh: getNativeSegwitPaymentFromAddressIndex
1344
- });
1345
- const payment = derivePayerFromAccount(childKeychain, network);
1346
- return {
1347
- keyOrigin: appendAddressIndexToPath(keyOrigin, change, addressIndex),
1348
- masterKeyFingerprint: fingerprint,
1349
- paymentType,
1350
- network,
1351
- payment,
1352
- get address() {
1353
- if (!payment.address) throw new Error("Payment address could not be derived");
1354
- return payment.address;
1355
- },
1356
- get publicKey() {
1357
- if (!childKeychain.publicKey) throw new Error("Public key could not be derived");
1358
- return childKeychain.publicKey;
1359
- }
1360
- };
1361
- };
1362
- }
1129
+ const { fingerprint, keyOrigin } = decomposeDescriptor(descriptor);
1130
+ const accountKeychain = deriveKeychainFromXpub(extractExtendedPublicKeyFromPolicy(descriptor));
1131
+ const paymentType = inferPaymentTypeFromPath(keyOrigin);
1132
+ if (accountKeychain.depth !== DerivationPathDepth.Account) throw new Error("Keychain passed is not an account");
1133
+ return ({ change, addressIndex }) => {
1134
+ const childKeychain = accountKeychain.deriveChild(change).deriveChild(addressIndex);
1135
+ const payment = whenSupportedPaymentType(paymentType)({
1136
+ p2tr: getTaprootPaymentFromAddressIndex,
1137
+ p2wpkh: getNativeSegwitPaymentFromAddressIndex
1138
+ })(childKeychain, network);
1139
+ return {
1140
+ keyOrigin: appendAddressIndexToPath(keyOrigin, change, addressIndex),
1141
+ masterKeyFingerprint: fingerprint,
1142
+ paymentType,
1143
+ network,
1144
+ payment,
1145
+ get address() {
1146
+ if (!payment.address) throw new Error("Payment address could not be derived");
1147
+ return payment.address;
1148
+ },
1149
+ get publicKey() {
1150
+ if (!childKeychain.publicKey) throw new Error("Public key could not be derived");
1151
+ return childKeychain.publicKey;
1152
+ }
1153
+ };
1154
+ };
1155
+ }
1156
+ /**
1157
+ * @example
1158
+ * ```ts
1159
+ * tx.addInput({
1160
+ * ...input,
1161
+ * bip32Derivation: [payerToBip32Derivation(payer)],
1162
+ * })
1163
+ * ```
1164
+ */
1363
1165
  function payerToBip32Derivation(args) {
1364
- return [
1365
- args.publicKey,
1366
- {
1367
- fingerprint: hexToNumber(args.masterKeyFingerprint),
1368
- path: btc5.bip32Path(keyOriginToDerivationPath(args.keyOrigin))
1369
- }
1370
- ];
1371
- }
1166
+ return [args.publicKey, {
1167
+ fingerprint: hexToNumber(args.masterKeyFingerprint),
1168
+ path: btc.bip32Path(keyOriginToDerivationPath(args.keyOrigin))
1169
+ }];
1170
+ }
1171
+ /**
1172
+ * @example
1173
+ * ```ts
1174
+ * tx.addInput({
1175
+ * ...input,
1176
+ * tapBip32Derivation: [payerToTapBip32Derivation(payer)],
1177
+ * })
1178
+ * ```
1179
+ */
1372
1180
  function payerToTapBip32Derivation(args) {
1373
- return [
1374
- // TODO: @kyranjamie to default to schnoor when TR so conversion isn't
1375
- // necessary here?
1376
- ecdsaPublicKeyToSchnorr(args.publicKey),
1377
- {
1378
- hashes: [],
1379
- der: {
1380
- fingerprint: hexToNumber(args.masterKeyFingerprint),
1381
- path: btc5.bip32Path(keyOriginToDerivationPath(args.keyOrigin))
1382
- }
1383
- }
1384
- ];
1181
+ return [ecdsaPublicKeyToSchnorr(args.publicKey), {
1182
+ hashes: [],
1183
+ der: {
1184
+ fingerprint: hexToNumber(args.masterKeyFingerprint),
1185
+ path: btc.bip32Path(keyOriginToDerivationPath(args.keyOrigin))
1186
+ }
1187
+ }];
1385
1188
  }
1386
1189
  function payerToTapBip32DerivationBitcoinJsLib(args) {
1387
- return {
1388
- masterFingerprint: Buffer.from(args.masterKeyFingerprint, "hex"),
1389
- path: keyOriginToDerivationPath(args.keyOrigin),
1390
- leafHashes: [],
1391
- pubkey: Buffer.from(ecdsaPublicKeyToSchnorr(args.publicKey))
1392
- };
1190
+ return {
1191
+ masterFingerprint: Buffer.from(args.masterKeyFingerprint, "hex"),
1192
+ path: keyOriginToDerivationPath(args.keyOrigin),
1193
+ leafHashes: [],
1194
+ pubkey: Buffer.from(ecdsaPublicKeyToSchnorr(args.publicKey))
1195
+ };
1393
1196
  }
1394
1197
  function payerToBip32DerivationBitcoinJsLib(args) {
1395
- return {
1396
- masterFingerprint: Buffer.from(args.masterKeyFingerprint, "hex"),
1397
- path: keyOriginToDerivationPath(args.keyOrigin),
1398
- pubkey: Buffer.from(args.publicKey)
1399
- };
1198
+ return {
1199
+ masterFingerprint: Buffer.from(args.masterKeyFingerprint, "hex"),
1200
+ path: keyOriginToDerivationPath(args.keyOrigin),
1201
+ pubkey: Buffer.from(args.publicKey)
1202
+ };
1400
1203
  }
1401
1204
  function extractPayerInfoFromDerivationPath(path) {
1402
- return {
1403
- change: extractChangeIndexFromPath(path),
1404
- addressIndex: extractAddressIndexFromPath(path)
1405
- };
1406
- }
1205
+ return {
1206
+ change: extractChangeIndexFromPath(path),
1207
+ addressIndex: extractAddressIndexFromPath(path)
1208
+ };
1209
+ }
1210
+ /**
1211
+ * @description
1212
+ * Turns key format from @scure/btc-signer lib back into key origin string
1213
+ * @example
1214
+ * ```ts
1215
+ * const [inputOne] = getPsbtTxInputs(tx);
1216
+ * const keyOrigin = serializeKeyOrigin(inputOne.bip32Derivation[0][1]);
1217
+ * ```
1218
+ */
1407
1219
  function serializeKeyOrigin({ fingerprint, path }) {
1408
- const values = path.map((num) => num >= HARDENED_OFFSET ? num - HARDENED_OFFSET + "'" : num);
1409
- return `${toHexString(fingerprint)}/${values.join("/")}`;
1410
- }
1220
+ const values = path.map((num) => num >= HARDENED_OFFSET ? num - HARDENED_OFFSET + "'" : num);
1221
+ return `${toHexString(fingerprint)}/${values.join("/")}`;
1222
+ }
1223
+ /**
1224
+ * @description
1225
+ * Of a given set of a `tx.input`s bip32 derivation paths from
1226
+ * `@scure/btc-signer`, serialize the paths back to the string format used
1227
+ * internally
1228
+ */
1411
1229
  function extractRequiredKeyOrigins(derivation) {
1412
- return derivation.map(
1413
- ([_pubkey, path]) => serializeKeyOrigin("hashes" in path ? path.der : path)
1414
- );
1230
+ return derivation.map(([_pubkey, path]) => serializeKeyOrigin("hashes" in path ? path.der : path));
1415
1231
  }
1416
1232
 
1417
- // src/transactions/generate-unsigned-transaction.ts
1418
- import * as btc6 from "@scure/btc-signer";
1419
- function generateBitcoinUnsignedTransaction({
1420
- feeRate,
1421
- isSendingMax,
1422
- network,
1423
- recipients,
1424
- changeAddress,
1425
- utxos,
1426
- payerLookup
1427
- }) {
1428
- const determineUtxosArgs = { feeRate, recipients, utxos };
1429
- const { inputs, outputs, fee } = isSendingMax ? determineUtxosForSpendAll(determineUtxosArgs) : determineUtxosForSpend(determineUtxosArgs);
1430
- if (!inputs.length) throw new BitcoinError("NoInputsToSign");
1431
- if (!outputs.length) throw new BitcoinError("NoOutputsToSign");
1432
- const tx = new btc6.Transaction();
1433
- for (const input of inputs) {
1434
- const payer = payerLookup(input.keyOrigin);
1435
- if (!payer) {
1436
- console.log(`No payer found for input with keyOrigin ${input.keyOrigin}`);
1437
- continue;
1438
- }
1439
- const bip32Derivation = payer.paymentType === "p2tr" ? { tapBip32Derivation: [payerToTapBip32Derivation(payer)] } : { bip32Derivation: [payerToBip32Derivation(payer)] };
1440
- const tapInternalKey = payer.paymentType === "p2tr" ? { tapInternalKey: payer.payment.tapInternalKey } : {};
1441
- tx.addInput({
1442
- txid: input.txid,
1443
- index: input.vout,
1444
- witnessUtxo: {
1445
- script: payer.payment.script,
1446
- amount: BigInt(input.value)
1447
- },
1448
- ...bip32Derivation,
1449
- ...tapInternalKey
1450
- });
1451
- }
1452
- outputs.forEach((output) => {
1453
- if (!output.address) {
1454
- tx.addOutputAddress(changeAddress, BigInt(output.value), network);
1455
- return;
1456
- }
1457
- tx.addOutputAddress(output.address, BigInt(output.value), network);
1458
- });
1459
- return { tx, hex: tx.hex, psbt: tx.toPSBT(), inputs, fee };
1233
+ //#endregion
1234
+ //#region src/transactions/generate-unsigned-transaction.ts
1235
+ function generateBitcoinUnsignedTransaction({ feeRate, isSendingMax, network, recipients, changeAddress, utxos, payerLookup }) {
1236
+ const determineUtxosArgs = {
1237
+ feeRate,
1238
+ recipients,
1239
+ utxos
1240
+ };
1241
+ const { inputs, outputs, fee } = isSendingMax ? determineUtxosForSpendAll(determineUtxosArgs) : determineUtxosForSpend(determineUtxosArgs);
1242
+ if (!inputs.length) throw new BitcoinError("NoInputsToSign");
1243
+ if (!outputs.length) throw new BitcoinError("NoOutputsToSign");
1244
+ const tx = new btc.Transaction();
1245
+ for (const input of inputs) {
1246
+ const payer = payerLookup(input.keyOrigin);
1247
+ if (!payer) {
1248
+ console.log(`No payer found for input with keyOrigin ${input.keyOrigin}`);
1249
+ continue;
1250
+ }
1251
+ const bip32Derivation = payer.paymentType === "p2tr" ? { tapBip32Derivation: [payerToTapBip32Derivation(payer)] } : { bip32Derivation: [payerToBip32Derivation(payer)] };
1252
+ const tapInternalKey = payer.paymentType === "p2tr" ? { tapInternalKey: payer.payment.tapInternalKey } : {};
1253
+ tx.addInput({
1254
+ txid: input.txid,
1255
+ index: input.vout,
1256
+ witnessUtxo: {
1257
+ script: payer.payment.script,
1258
+ amount: BigInt(input.value)
1259
+ },
1260
+ ...bip32Derivation,
1261
+ ...tapInternalKey
1262
+ });
1263
+ }
1264
+ outputs.forEach((output) => {
1265
+ if (!output.address) {
1266
+ tx.addOutputAddress(changeAddress, BigInt(output.value), network);
1267
+ return;
1268
+ }
1269
+ tx.addOutputAddress(output.address, BigInt(output.value), network);
1270
+ });
1271
+ return {
1272
+ tx,
1273
+ hex: tx.hex,
1274
+ psbt: tx.toPSBT(),
1275
+ inputs,
1276
+ fee
1277
+ };
1460
1278
  }
1461
1279
 
1462
- // src/validation/amount-validation.ts
1463
- import { BITCOIN_MINIMUM_SPEND_IN_SATS } from "@leather.io/constants";
1280
+ //#endregion
1281
+ //#region src/validation/amount-validation.ts
1464
1282
  function isBtcBalanceSufficient({ desiredSpend, maxSpend }) {
1465
- return !desiredSpend.amount.isGreaterThan(maxSpend.amount);
1283
+ return !desiredSpend.amount.isGreaterThan(maxSpend.amount);
1466
1284
  }
1467
1285
  function isBtcMinimumSpend(desiredSpend) {
1468
- return !desiredSpend.amount.isLessThan(BITCOIN_MINIMUM_SPEND_IN_SATS);
1286
+ return !desiredSpend.amount.isLessThan(BITCOIN_MINIMUM_SPEND_IN_SATS);
1469
1287
  }
1470
1288
 
1471
- // src/validation/transaction-validation.ts
1472
- function isValidBitcoinTransaction({
1473
- amount,
1474
- payer,
1475
- recipient,
1476
- network,
1477
- utxos,
1478
- feeRate,
1479
- feeRates
1480
- }) {
1481
- if (!isValidBitcoinAddress(payer) || !isValidBitcoinAddress(recipient)) {
1482
- throw new BitcoinError("InvalidAddress");
1483
- }
1484
- if (!isValidBitcoinNetworkAddress(payer, network) || !isValidBitcoinNetworkAddress(recipient, network)) {
1485
- throw new BitcoinError("InvalidNetworkAddress");
1486
- }
1487
- if (!isBtcMinimumSpend(amount)) {
1488
- throw new BitcoinError("InsufficientAmount");
1489
- }
1490
- const maxSpend = calculateMaxSpend({ recipient, utxos, feeRate, feeRates });
1491
- if (!isBtcBalanceSufficient({ desiredSpend: amount, maxSpend: maxSpend.amount })) {
1492
- throw new BitcoinError("InsufficientFunds");
1493
- }
1289
+ //#endregion
1290
+ //#region src/validation/transaction-validation.ts
1291
+ function isValidBitcoinTransaction({ amount, payer, recipient, network, utxos, feeRate, feeRates }) {
1292
+ if (!isValidBitcoinAddress(payer) || !isValidBitcoinAddress(recipient)) throw new BitcoinError("InvalidAddress");
1293
+ if (!isValidBitcoinNetworkAddress(payer, network) || !isValidBitcoinNetworkAddress(recipient, network)) throw new BitcoinError("InvalidNetworkAddress");
1294
+ if (!isBtcMinimumSpend(amount)) throw new BitcoinError("InsufficientAmount");
1295
+ if (!isBtcBalanceSufficient({
1296
+ desiredSpend: amount,
1297
+ maxSpend: calculateMaxSpend({
1298
+ recipient,
1299
+ utxos,
1300
+ feeRate,
1301
+ feeRates
1302
+ }).amount
1303
+ })) throw new BitcoinError("InsufficientFunds");
1494
1304
  }
1495
1305
 
1496
- // src/utils/bitcoin.descriptors.ts
1497
- import { HARDENED_OFFSET as HARDENED_OFFSET2, HDKey as HDKey3 } from "@scure/bip32";
1306
+ //#endregion
1307
+ //#region src/utils/bitcoin.descriptors.ts
1498
1308
  function getDescriptorFromKeychain(accountKeychain) {
1499
- switch (inferPaymentTypeFromPath(accountKeychain.keyOrigin)) {
1500
- case "p2tr":
1501
- return `tr(${accountKeychain.xpub})`;
1502
- case "p2wpkh":
1503
- return `wpkh(${accountKeychain.xpub})`;
1504
- default:
1505
- return void 0;
1506
- }
1309
+ switch (inferPaymentTypeFromPath(accountKeychain.keyOrigin)) {
1310
+ case "p2tr": return `tr(${accountKeychain.xpub})`;
1311
+ case "p2wpkh": return `wpkh(${accountKeychain.xpub})`;
1312
+ default: return;
1313
+ }
1507
1314
  }
1508
1315
  function inferPaymentTypeFromDescriptor(descriptor) {
1509
- const descriptorPrefix = descriptor.split("(")[0];
1510
- switch (descriptorPrefix) {
1511
- case "tr":
1512
- return "p2tr";
1513
- case "wpkh":
1514
- return "p2wpkh";
1515
- default:
1516
- throw new Error("Unrecognized descriptor");
1517
- }
1316
+ switch (descriptor.split("(")[0]) {
1317
+ case "tr": return "p2tr";
1318
+ case "wpkh": return "p2wpkh";
1319
+ default: throw new Error("Unrecognized descriptor");
1320
+ }
1518
1321
  }
1519
1322
  function extractXpubFromDescriptor(descriptor) {
1520
- const match = descriptor.match(/\((xpub[0-9A-Za-z]+)\)/);
1521
- if (match && match[1]) {
1522
- return match[1];
1523
- }
1524
- throw new Error("Invalid descriptor format");
1525
- }
1526
- function deriveAddressesFromDescriptor({
1527
- accountDescriptor,
1528
- network,
1529
- limit = 1
1530
- }) {
1531
- const accountKeychain = HDKey3.fromExtendedKey(extractXpubFromDescriptor(accountDescriptor));
1532
- const paymentType = inferPaymentTypeFromDescriptor(accountDescriptor);
1533
- const derivationPathFn = whenSupportedPaymentType(paymentType)({
1534
- p2tr: makeTaprootAddressIndexDerivationPath,
1535
- p2wpkh: makeNativeSegwitAddressIndexDerivationPath
1536
- });
1537
- const results = [];
1538
- for (let i = 0; i < limit; i++) {
1539
- const address2 = whenSupportedPaymentType(paymentType)({
1540
- p2tr: getTaprootAddress({ index: i, keychain: accountKeychain, network }),
1541
- p2wpkh: getNativeSegwitAddress({ index: i, keychain: accountKeychain, network })
1542
- });
1543
- results.push({
1544
- address: address2,
1545
- path: derivationPathFn(network, accountKeychain.index - HARDENED_OFFSET2, i)
1546
- });
1547
- }
1548
- return results;
1323
+ const match = descriptor.match(/\((xpub[0-9A-Za-z]+)\)/);
1324
+ if (match && match[1]) return match[1];
1325
+ throw new Error("Invalid descriptor format");
1326
+ }
1327
+ function deriveAddressesFromDescriptor({ accountDescriptor, network, limit = 1 }) {
1328
+ const accountKeychain = HDKey.fromExtendedKey(extractXpubFromDescriptor(accountDescriptor));
1329
+ const paymentType = inferPaymentTypeFromDescriptor(accountDescriptor);
1330
+ const derivationPathFn = whenSupportedPaymentType(paymentType)({
1331
+ p2tr: makeTaprootAddressIndexDerivationPath,
1332
+ p2wpkh: makeNativeSegwitAddressIndexDerivationPath
1333
+ });
1334
+ const results = [];
1335
+ for (let i = 0; i < limit; i++) {
1336
+ const address = whenSupportedPaymentType(paymentType)({
1337
+ p2tr: getTaprootAddress({
1338
+ index: i,
1339
+ keychain: accountKeychain,
1340
+ network
1341
+ }),
1342
+ p2wpkh: getNativeSegwitAddress({
1343
+ index: i,
1344
+ keychain: accountKeychain,
1345
+ network
1346
+ })
1347
+ });
1348
+ results.push({
1349
+ address,
1350
+ path: derivationPathFn(network, accountKeychain.index - HARDENED_OFFSET, i)
1351
+ });
1352
+ }
1353
+ return results;
1549
1354
  }
1550
1355
 
1551
- // src/utils/lookup-derivation-by-address.ts
1552
- import { HARDENED_OFFSET as HARDENED_OFFSET3, HDKey as HDKey4 } from "@scure/bip32";
1553
- import { createCounter } from "@leather.io/utils";
1356
+ //#endregion
1357
+ //#region src/utils/lookup-derivation-by-address.ts
1554
1358
  function lookupDerivationByAddress(args) {
1555
- const { taprootXpub, nativeSegwitXpub, iterationLimit } = args;
1556
- const taprootKeychain = HDKey4.fromExtendedKey(taprootXpub);
1557
- const nativeSegwitKeychain = HDKey4.fromExtendedKey(nativeSegwitXpub);
1558
- return (address2) => {
1559
- const network = inferNetworkFromAddress(address2);
1560
- const paymentType = inferPaymentTypeFromAddress(address2);
1561
- const accountIndex = whenSupportedPaymentType(paymentType)({
1562
- p2tr: taprootKeychain.index - HARDENED_OFFSET3,
1563
- p2wpkh: nativeSegwitKeychain.index - HARDENED_OFFSET3
1564
- });
1565
- function getTaprootAddressAtIndex(index) {
1566
- return getTaprootAddress({ index, keychain: taprootKeychain, network });
1567
- }
1568
- function getNativeSegwitAddressAtIndex(index) {
1569
- return getNativeSegwitAddress({ index, keychain: nativeSegwitKeychain, network });
1570
- }
1571
- const paymentFn = whenSupportedPaymentType(paymentType)({
1572
- p2tr: getTaprootAddressAtIndex,
1573
- p2wpkh: getNativeSegwitAddressAtIndex
1574
- });
1575
- const derivationPathFn = whenSupportedPaymentType(paymentType)({
1576
- p2tr: makeTaprootAddressIndexDerivationPath,
1577
- p2wpkh: makeNativeSegwitAddressIndexDerivationPath
1578
- });
1579
- const count = createCounter();
1580
- const t0 = performance.now();
1581
- while (count.getValue() <= iterationLimit) {
1582
- const currentIndex = count.getValue();
1583
- const addressToCheck = paymentFn(currentIndex);
1584
- if (addressToCheck !== address2) {
1585
- count.increment();
1586
- continue;
1587
- }
1588
- const t1 = performance.now();
1589
- return {
1590
- status: "success",
1591
- duration: t1 - t0,
1592
- path: derivationPathFn(network, accountIndex, currentIndex)
1593
- };
1594
- }
1595
- return { status: "failure" };
1596
- };
1597
- }
1598
- export {
1599
- BitcoinError,
1600
- TEST_ACCOUNT_1_NATIVE_SEGWIT_ADDRESS,
1601
- TEST_ACCOUNT_1_TAPROOT_ADDRESS,
1602
- TEST_ACCOUNT_2_TAPROOT_ADDRESS,
1603
- TEST_TESNET_ACCOUNT_1_NATIVE_SEGWIT_ADDRESS,
1604
- TEST_TESTNET_ACCOUNT_2_BTC_ADDRESS,
1605
- TEST_TESTNET_ACCOUNT_2_TAPROOT_ADDRESS,
1606
- bip21,
1607
- bip322TransactionToSignValues,
1608
- bitcoinNetworkModeToCoreNetworkMode,
1609
- bitcoinNetworkToCoreNetworkMap,
1610
- btcAddressNetworkValidator,
1611
- btcAddressValidator,
1612
- btcSignerLibPaymentTypeToPaymentTypeMap,
1613
- calculateMaxSpend,
1614
- coinTypeMap,
1615
- createBitcoinAddress,
1616
- createNativeSegwitBitcoinJsSigner,
1617
- createTaprootBitcoinJsSigner,
1618
- createToSpendTx,
1619
- createWalletIdDecoratedPath,
1620
- decodeBitcoinTx,
1621
- decodeCompressedWifPrivateKey,
1622
- deriveAddressIndexKeychainFromAccount,
1623
- deriveAddressIndexZeroFromAccount,
1624
- deriveAddressesFromDescriptor,
1625
- deriveBitcoinPayerFromAccount,
1626
- deriveBtcBip49SeedFromMnemonic,
1627
- deriveNativeSegwitAccountFromRootKeychain,
1628
- deriveNativeSegwitReceiveAddressIndexZero,
1629
- deriveRootBtcKeychain,
1630
- deriveTaprootAccount,
1631
- deriveTaprootReceiveAddressIndexZero,
1632
- determineUtxosForSpend,
1633
- determineUtxosForSpendAll,
1634
- ecPairFromPrivateKey,
1635
- ecdsaPublicKeyLength,
1636
- ecdsaPublicKeyToSchnorr,
1637
- encodeMessageWitnessData,
1638
- extractExtendedPublicKeyFromPolicy,
1639
- extractPayerInfoFromDerivationPath,
1640
- extractRequiredKeyOrigins,
1641
- extractXpubFromDescriptor,
1642
- filterUneconomicalUtxos,
1643
- generateBitcoinUnsignedTransaction,
1644
- getAddressFromOutScript,
1645
- getBitcoinAddressNetworkType,
1646
- getBitcoinCoinTypeIndexByNetwork,
1647
- getBitcoinFees,
1648
- getBitcoinInputAddress,
1649
- getBitcoinInputValue,
1650
- getBitcoinJsLibNetworkConfigByMode,
1651
- getBitcoinTransactionFee,
1652
- getBtcSignerLibNetworkConfigByMode,
1653
- getDescriptorFromKeychain,
1654
- getHdKeyVersionsFromNetwork,
1655
- getInputPaymentType,
1656
- getNativeSegwitAccountDerivationPath,
1657
- getNativeSegwitAddress,
1658
- getNativeSegwitAddressIndexDerivationPath,
1659
- getNativeSegwitPaymentFromAddressIndex,
1660
- getNetworkTypeFromAddress,
1661
- getParsedInputs,
1662
- getParsedOutputs,
1663
- getPsbtAsTransaction,
1664
- getPsbtDetails,
1665
- getPsbtTotals,
1666
- getPsbtTxInputs,
1667
- getPsbtTxOutputs,
1668
- getRawPsbt,
1669
- getSizeInfo,
1670
- getSpendableAmount,
1671
- getTaprootAccountDerivationPath,
1672
- getTaprootAddress,
1673
- getTaprootAddressIndexDerivationPath,
1674
- getTaprootPayment,
1675
- getTaprootPaymentFromAddressIndex,
1676
- getUtxoTotal,
1677
- hashBip322Message,
1678
- inValidCharactersAddress,
1679
- inValidLengthAddress,
1680
- inferNetworkFromAddress,
1681
- inferNetworkFromPath,
1682
- inferPaymentTypeFromAddress,
1683
- inferPaymentTypeFromDescriptor,
1684
- inferPaymentTypeFromPath,
1685
- initBitcoinAccount,
1686
- initializeBitcoinAccountKeychainFromDescriptor,
1687
- invalidAddress,
1688
- isBitcoinAddress,
1689
- isBtcBalanceSufficient,
1690
- isBtcMinimumSpend,
1691
- isBtcSignerLibPaymentType,
1692
- isSupportedMessageSigningPaymentType,
1693
- isValidBitcoinAddress,
1694
- isValidBitcoinNetworkAddress,
1695
- isValidBitcoinTransaction,
1696
- legacyAddress,
1697
- lookUpLedgerKeysByPath,
1698
- lookupDerivationByAddress,
1699
- makeNativeSegwitAccountDerivationPath,
1700
- makeNativeSegwitAddressIndexDerivationPath,
1701
- makePayToScriptHashAddress,
1702
- makePayToScriptHashAddressBytes,
1703
- makePayToScriptHashKeyHash,
1704
- makeTaprootAccountDerivationPath,
1705
- makeTaprootAddressIndexDerivationPath,
1706
- mnemonicToRootNode,
1707
- nonEmptyStringValidator,
1708
- parseKnownPaymentType,
1709
- payToScriptHashTestnetPrefix,
1710
- payerToBip32Derivation,
1711
- payerToBip32DerivationBitcoinJsLib,
1712
- payerToTapBip32Derivation,
1713
- payerToTapBip32DerivationBitcoinJsLib,
1714
- paymentTypeMap,
1715
- publicKeyToPayToScriptHashAddress,
1716
- recipientAddress,
1717
- segwitAddress,
1718
- serializeKeyOrigin,
1719
- signBip322MessageSimple,
1720
- taprootAddress,
1721
- toXOnly,
1722
- tweakSigner,
1723
- whenBitcoinNetwork,
1724
- whenPaymentType,
1725
- whenSupportedPaymentType
1726
- };
1359
+ const { taprootXpub, nativeSegwitXpub, iterationLimit } = args;
1360
+ const taprootKeychain = HDKey.fromExtendedKey(taprootXpub);
1361
+ const nativeSegwitKeychain = HDKey.fromExtendedKey(nativeSegwitXpub);
1362
+ return (address) => {
1363
+ const network = inferNetworkFromAddress(address);
1364
+ const paymentType = inferPaymentTypeFromAddress(address);
1365
+ const accountIndex = whenSupportedPaymentType(paymentType)({
1366
+ p2tr: taprootKeychain.index - HARDENED_OFFSET,
1367
+ p2wpkh: nativeSegwitKeychain.index - HARDENED_OFFSET
1368
+ });
1369
+ function getTaprootAddressAtIndex(index) {
1370
+ return getTaprootAddress({
1371
+ index,
1372
+ keychain: taprootKeychain,
1373
+ network
1374
+ });
1375
+ }
1376
+ function getNativeSegwitAddressAtIndex(index) {
1377
+ return getNativeSegwitAddress({
1378
+ index,
1379
+ keychain: nativeSegwitKeychain,
1380
+ network
1381
+ });
1382
+ }
1383
+ const paymentFn = whenSupportedPaymentType(paymentType)({
1384
+ p2tr: getTaprootAddressAtIndex,
1385
+ p2wpkh: getNativeSegwitAddressAtIndex
1386
+ });
1387
+ const derivationPathFn = whenSupportedPaymentType(paymentType)({
1388
+ p2tr: makeTaprootAddressIndexDerivationPath,
1389
+ p2wpkh: makeNativeSegwitAddressIndexDerivationPath
1390
+ });
1391
+ const count = createCounter();
1392
+ const t0 = performance.now();
1393
+ while (count.getValue() <= iterationLimit) {
1394
+ const currentIndex = count.getValue();
1395
+ if (paymentFn(currentIndex) !== address) {
1396
+ count.increment();
1397
+ continue;
1398
+ }
1399
+ return {
1400
+ status: "success",
1401
+ duration: performance.now() - t0,
1402
+ path: derivationPathFn(network, accountIndex, currentIndex)
1403
+ };
1404
+ }
1405
+ return { status: "failure" };
1406
+ };
1407
+ }
1408
+
1409
+ //#endregion
1410
+ export { BitcoinError, TEST_ACCOUNT_1_NATIVE_SEGWIT_ADDRESS, TEST_ACCOUNT_1_TAPROOT_ADDRESS, TEST_ACCOUNT_2_TAPROOT_ADDRESS, TEST_TESNET_ACCOUNT_1_NATIVE_SEGWIT_ADDRESS, TEST_TESTNET_ACCOUNT_2_BTC_ADDRESS, TEST_TESTNET_ACCOUNT_2_TAPROOT_ADDRESS, bip21, bip322TransactionToSignValues, bitcoinNetworkModeToCoreNetworkMode, bitcoinNetworkToCoreNetworkMap, btcAddressNetworkValidator, btcAddressValidator, btcSignerLibPaymentTypeToPaymentTypeMap, calculateMaxSpend, coinTypeMap, createBitcoinAddress, createNativeSegwitBitcoinJsSigner, createTaprootBitcoinJsSigner, createToSpendTx, createWalletIdDecoratedPath, decodeBitcoinTx, decodeCompressedWifPrivateKey, deriveAddressIndexKeychainFromAccount, deriveAddressIndexZeroFromAccount, deriveAddressesFromDescriptor, deriveBitcoinPayerFromAccount, deriveBtcBip49SeedFromMnemonic, deriveNativeSegwitAccountFromRootKeychain, deriveNativeSegwitReceiveAddressIndexZero, deriveRootBtcKeychain, deriveTaprootAccount, deriveTaprootReceiveAddressIndexZero, determineUtxosForSpend, determineUtxosForSpendAll, ecPairFromPrivateKey, ecdsaPublicKeyLength, ecdsaPublicKeyToSchnorr, encodeMessageWitnessData, extractExtendedPublicKeyFromPolicy, extractPayerInfoFromDerivationPath, extractRequiredKeyOrigins, extractXpubFromDescriptor, filterUneconomicalUtxos, generateBitcoinUnsignedTransaction, getAddressFromOutScript, getBitcoinAddressNetworkType, getBitcoinCoinTypeIndexByNetwork, getBitcoinFees, getBitcoinInputAddress, getBitcoinInputValue, getBitcoinJsLibNetworkConfigByMode, getBitcoinTransactionFee, getBtcSignerLibNetworkConfigByMode, getDescriptorFromKeychain, getHdKeyVersionsFromNetwork, getInputPaymentType, getNativeSegwitAccountDerivationPath, getNativeSegwitAddress, getNativeSegwitAddressIndexDerivationPath, getNativeSegwitPaymentFromAddressIndex, getNetworkTypeFromAddress, getParsedInputs, getParsedOutputs, getPsbtAsTransaction, getPsbtDetails, getPsbtTotals, getPsbtTxInputs, getPsbtTxOutputs, getRawPsbt, getSizeInfo, getSpendableAmount, getTaprootAccountDerivationPath, getTaprootAddress, getTaprootAddressIndexDerivationPath, getTaprootPayment, getTaprootPaymentFromAddressIndex, getUtxoTotal, hashBip322Message, inValidCharactersAddress, inValidLengthAddress, inferNetworkFromAddress, inferNetworkFromPath, inferPaymentTypeFromAddress, inferPaymentTypeFromDescriptor, inferPaymentTypeFromPath, initBitcoinAccount, initializeBitcoinAccountKeychainFromDescriptor, invalidAddress, isBitcoinAddress, isBtcBalanceSufficient, isBtcMinimumSpend, isBtcSignerLibPaymentType, isSupportedMessageSigningPaymentType, isValidBitcoinAddress, isValidBitcoinNetworkAddress, isValidBitcoinTransaction, legacyAddress, lookUpLedgerKeysByPath, lookupDerivationByAddress, makeNativeSegwitAccountDerivationPath, makeNativeSegwitAddressIndexDerivationPath, makePayToScriptHashAddress, makePayToScriptHashAddressBytes, makePayToScriptHashKeyHash, makeTaprootAccountDerivationPath, makeTaprootAddressIndexDerivationPath, mnemonicToRootNode, nonEmptyStringValidator, parseKnownPaymentType, payToScriptHashTestnetPrefix, payerToBip32Derivation, payerToBip32DerivationBitcoinJsLib, payerToTapBip32Derivation, payerToTapBip32DerivationBitcoinJsLib, paymentTypeMap, publicKeyToPayToScriptHashAddress, recipientAddress, segwitAddress, serializeKeyOrigin, signBip322MessageSimple, taprootAddress, toXOnly, tweakSigner, whenBitcoinNetwork, whenPaymentType, whenSupportedPaymentType };
1727
1411
  //# sourceMappingURL=index.js.map