@leather.io/bitcoin 0.19.29 → 0.19.31
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/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +41 -0
- package/dist/index.d.ts +206 -157
- package/dist/index.js +341 -205
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
- package/src/bip322/bip322-utils.ts +1 -1
- package/src/bip322/sign-message-bip322-bitcoinjs.ts +8 -3
- package/src/bip322/sign-message-bip322.spec.ts +13 -13
- package/src/coin-selection/calculate-max-spend.spec.ts +19 -17
- package/src/coin-selection/calculate-max-spend.ts +26 -16
- package/src/coin-selection/coin-selection.spec.ts +29 -26
- package/src/coin-selection/coin-selection.ts +1 -1
- package/src/coin-selection/coin-selection.utils.spec.ts +2 -1
- package/src/coin-selection/coin-selection.utils.ts +5 -8
- package/src/fees/bitcoin-fees.spec.ts +7 -10
- package/src/index.ts +21 -9
- package/src/mocks/mocks.ts +39 -0
- package/src/{p2tr-address-gen.spec.ts → payments/p2tr-address-gen.spec.ts} +1 -1
- package/src/{p2tr-address-gen.ts → payments/p2tr-address-gen.ts} +2 -2
- package/src/{p2wpkh-address-gen.ts → payments/p2wpkh-address-gen.ts} +2 -2
- package/src/psbt/psbt-details.ts +3 -3
- package/src/psbt/psbt-inputs.ts +9 -6
- package/src/psbt/psbt-outputs.ts +10 -7
- package/src/psbt/psbt-totals.ts +3 -3
- package/src/{bitcoin-signer.ts → signer/bitcoin-signer.ts} +6 -5
- package/src/transactions/generate-unsigned-transaction.spec.ts +1 -1
- package/src/transactions/generate-unsigned-transaction.ts +3 -3
- package/src/{bitcoin.network.ts → utils/bitcoin.network.ts} +2 -0
- package/src/{bitcoin.utils.spec.ts → utils/bitcoin.utils.spec.ts} +19 -14
- package/src/{bitcoin.utils.ts → utils/bitcoin.utils.ts} +19 -13
- package/src/{lookup-derivation-by-address.spec.ts → utils/lookup-derivation-by-address.spec.ts} +11 -6
- package/src/{lookup-derivation-by-address.ts → utils/lookup-derivation-by-address.ts} +4 -3
- package/src/validation/address-validation.spec.ts +396 -0
- package/src/validation/address-validation.ts +28 -0
- package/src/validation/amount-validation.spec.ts +39 -0
- package/src/validation/amount-validation.ts +31 -0
- package/src/validation/bitcoin-address.ts +23 -0
- package/src/{bitcoin-error.ts → validation/bitcoin-error.ts} +4 -2
- package/src/validation/transaction-validation.spec.ts +60 -0
- package/src/validation/transaction-validation.ts +46 -0
- /package/src/{btc-size-fee-estimator.spec.ts → fees/btc-size-fee-estimator.spec.ts} +0 -0
- /package/src/{btc-size-fee-estimator.ts → fees/btc-size-fee-estimator.ts} +0 -0
- /package/src/{p2wpkh-address-gen.spec.ts → payments/p2wpkh-address-gen.spec.ts} +0 -0
- /package/src/{p2wsh-p2sh-address-gen.spec.ts → payments/p2wsh-p2sh-address-gen.spec.ts} +0 -0
- /package/src/{p2wsh-p2sh-address-gen.ts → payments/p2wsh-p2sh-address-gen.ts} +0 -0
- /package/src/{bitcoin-signer.spec.ts → signer/bitcoin-signer.spec.ts} +0 -0
package/src/psbt/psbt-outputs.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { TransactionOutput } from '@scure/btc-signer/psbt';
|
|
2
|
-
import { getBtcSignerLibNetworkConfigByMode } from 'bitcoin.network';
|
|
3
|
-
import { getAddressFromOutScript } from 'bitcoin.utils';
|
|
4
2
|
|
|
5
|
-
import
|
|
3
|
+
import { BitcoinNetworkModes } from '@leather.io/models';
|
|
6
4
|
import { isDefined, isUndefined } from '@leather.io/utils';
|
|
7
5
|
|
|
6
|
+
import { getBtcSignerLibNetworkConfigByMode } from '../utils/bitcoin.network';
|
|
7
|
+
import { getAddressFromOutScript } from '../utils/bitcoin.utils';
|
|
8
|
+
import { BitcoinAddress, createBitcoinAddress } from '../validation/bitcoin-address';
|
|
9
|
+
|
|
8
10
|
export interface PsbtOutput {
|
|
9
|
-
address:
|
|
11
|
+
address: BitcoinAddress;
|
|
10
12
|
isMutable: boolean;
|
|
11
13
|
toSign: boolean;
|
|
12
14
|
value: number;
|
|
@@ -16,7 +18,7 @@ interface GetParsedOutputsArgs {
|
|
|
16
18
|
isPsbtMutable: boolean;
|
|
17
19
|
outputs: TransactionOutput[];
|
|
18
20
|
networkMode: BitcoinNetworkModes;
|
|
19
|
-
psbtAddresses:
|
|
21
|
+
psbtAddresses: BitcoinAddress[];
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export function getParsedOutputs({
|
|
@@ -34,8 +36,9 @@ export function getParsedOutputs({
|
|
|
34
36
|
// logger.error('Output has no script');
|
|
35
37
|
return;
|
|
36
38
|
}
|
|
37
|
-
const outputAddress =
|
|
38
|
-
|
|
39
|
+
const outputAddress = createBitcoinAddress(
|
|
40
|
+
getAddressFromOutScript(output.script, bitcoinNetwork)
|
|
41
|
+
);
|
|
39
42
|
const isCurrentAddress = psbtAddresses.includes(outputAddress);
|
|
40
43
|
|
|
41
44
|
return {
|
package/src/psbt/psbt-totals.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { inferPaymentTypeFromAddress } from 'bitcoin.utils';
|
|
2
|
-
|
|
3
1
|
import { createMoney, sumNumbers } from '@leather.io/utils';
|
|
4
2
|
|
|
3
|
+
import { inferPaymentTypeFromAddress } from '../utils/bitcoin.utils';
|
|
4
|
+
import { BitcoinAddress } from '../validation/bitcoin-address';
|
|
5
5
|
import { PsbtInput } from './psbt-inputs';
|
|
6
6
|
import { PsbtOutput } from './psbt-outputs';
|
|
7
7
|
|
|
@@ -35,7 +35,7 @@ function calculatePsbtOutputsTotal(outputs: PsbtOutput[]) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
interface GetPsbtTotalsProps {
|
|
38
|
-
psbtAddresses:
|
|
38
|
+
psbtAddresses: BitcoinAddress[];
|
|
39
39
|
parsedInputs: PsbtInput[];
|
|
40
40
|
parsedOutputs: PsbtOutput[];
|
|
41
41
|
}
|
|
@@ -14,15 +14,16 @@ import type { BitcoinNetworkModes, ValueOf } from '@leather.io/models';
|
|
|
14
14
|
import { PaymentTypes, signatureHash } from '@leather.io/rpc';
|
|
15
15
|
import { hexToNumber, toHexString } from '@leather.io/utils';
|
|
16
16
|
|
|
17
|
+
import { getTaprootPaymentFromAddressIndex } from '../payments/p2tr-address-gen';
|
|
18
|
+
import { getNativeSegwitPaymentFromAddressIndex } from '../payments/p2wpkh-address-gen';
|
|
17
19
|
import {
|
|
18
20
|
SupportedPaymentType,
|
|
19
21
|
ecdsaPublicKeyToSchnorr,
|
|
20
22
|
extractExtendedPublicKeyFromPolicy,
|
|
21
23
|
inferPaymentTypeFromPath,
|
|
22
24
|
whenSupportedPaymentType,
|
|
23
|
-
} from '
|
|
24
|
-
import {
|
|
25
|
-
import { getNativeSegwitPaymentFromAddressIndex } from './p2wpkh-address-gen';
|
|
25
|
+
} from '../utils/bitcoin.utils';
|
|
26
|
+
import { BitcoinAddress } from '../validation/bitcoin-address';
|
|
26
27
|
|
|
27
28
|
export type AllowedSighashTypes = ValueOf<typeof signatureHash> | SigHash;
|
|
28
29
|
|
|
@@ -41,7 +42,7 @@ export interface BitcoinSigner<Payment> {
|
|
|
41
42
|
payment: Payment;
|
|
42
43
|
keychain: HDKey;
|
|
43
44
|
derivationPath: string;
|
|
44
|
-
address:
|
|
45
|
+
address: BitcoinAddress;
|
|
45
46
|
publicKey: Uint8Array;
|
|
46
47
|
sign(tx: btc.Transaction): void;
|
|
47
48
|
signIndex(tx: btc.Transaction, index: number, allowedSighash?: AllowedSighashTypes[]): void;
|
|
@@ -50,7 +51,7 @@ export interface BitcoinSigner<Payment> {
|
|
|
50
51
|
export interface BitcoinPayerBase {
|
|
51
52
|
paymentType: PaymentTypes;
|
|
52
53
|
network: BitcoinNetworkModes;
|
|
53
|
-
address:
|
|
54
|
+
address: BitcoinAddress;
|
|
54
55
|
keyOrigin: string;
|
|
55
56
|
masterKeyFingerprint: string;
|
|
56
57
|
publicKey: Uint8Array;
|
|
@@ -3,7 +3,7 @@ import { describe, expect, it } from 'vitest';
|
|
|
3
3
|
|
|
4
4
|
import { createMoney } from '@leather.io/utils';
|
|
5
5
|
|
|
6
|
-
import { getBtcSignerLibNetworkConfigByMode } from '../bitcoin.network';
|
|
6
|
+
import { getBtcSignerLibNetworkConfigByMode } from '../utils/bitcoin.network';
|
|
7
7
|
import {
|
|
8
8
|
GenerateBitcoinUnsignedTransactionArgs,
|
|
9
9
|
generateBitcoinUnsignedTransactionNativeSegwit,
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { hexToBytes } from '@noble/hashes/utils';
|
|
2
2
|
import * as btc from '@scure/btc-signer';
|
|
3
|
-
import { BtcSignerDefaultBip32Derivation } from 'bitcoin-signer';
|
|
4
3
|
|
|
5
|
-
import { BitcoinError } from '../bitcoin-error';
|
|
6
|
-
import { BtcSignerNetwork } from '../bitcoin.network';
|
|
7
4
|
import {
|
|
8
5
|
CoinSelectionRecipient,
|
|
9
6
|
CoinSelectionUtxo,
|
|
10
7
|
determineUtxosForSpend,
|
|
11
8
|
determineUtxosForSpendAll,
|
|
12
9
|
} from '../coin-selection/coin-selection';
|
|
10
|
+
import { BtcSignerDefaultBip32Derivation } from '../signer/bitcoin-signer';
|
|
11
|
+
import { BtcSignerNetwork } from '../utils/bitcoin.network';
|
|
12
|
+
import { BitcoinError } from '../validation/bitcoin-error';
|
|
13
13
|
|
|
14
14
|
export interface GenerateBitcoinUnsignedTransactionArgs {
|
|
15
15
|
feeRate: number;
|
|
@@ -2,6 +2,8 @@ import * as bitcoinJs from 'bitcoinjs-lib';
|
|
|
2
2
|
|
|
3
3
|
import { BitcoinNetworkModes } from '@leather.io/models';
|
|
4
4
|
|
|
5
|
+
// TODO - this PR was merged so we could update this
|
|
6
|
+
// https://github.com/paulmillr/scure-btc-signer/blob/main/src/utils.ts
|
|
5
7
|
// See this PR https://github.com/paulmillr/@scure/btc-signer/pull/15
|
|
6
8
|
// Atttempting to add these directly to the library
|
|
7
9
|
export interface BtcSignerNetwork {
|
|
@@ -1,45 +1,50 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
|
|
3
|
+
import { createBitcoinAddress } from '../validation/bitcoin-address';
|
|
3
4
|
import { inferNetworkFromAddress, inferPaymentTypeFromAddress } from './bitcoin.utils';
|
|
4
5
|
|
|
5
6
|
describe(inferNetworkFromAddress.name, () => {
|
|
6
7
|
it('should return "mainnet" for P2PKH mainnet addresses', () => {
|
|
7
|
-
const mainnetAddress = '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa';
|
|
8
|
+
const mainnetAddress = createBitcoinAddress('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa');
|
|
8
9
|
expect(inferNetworkFromAddress(mainnetAddress)).toBe('mainnet');
|
|
9
10
|
});
|
|
10
11
|
|
|
11
12
|
it('should return "mainnet" for P2SH mainnet addresses', () => {
|
|
12
|
-
const mainnetP2SHAddress = '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy';
|
|
13
|
+
const mainnetP2SHAddress = createBitcoinAddress('3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy');
|
|
13
14
|
expect(inferNetworkFromAddress(mainnetP2SHAddress)).toBe('mainnet');
|
|
14
15
|
});
|
|
15
16
|
|
|
16
17
|
it('should return "mainnet" for Bech32 mainnet addresses', () => {
|
|
17
|
-
const mainnetBech32Address = 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kygt080';
|
|
18
|
+
const mainnetBech32Address = createBitcoinAddress('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kygt080');
|
|
18
19
|
expect(inferNetworkFromAddress(mainnetBech32Address)).toBe('mainnet');
|
|
19
20
|
});
|
|
20
21
|
|
|
21
22
|
it('should return "testnet" for P2PKH testnet addresses', () => {
|
|
22
|
-
const testnetP2PKHAddress = 'mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn';
|
|
23
|
+
const testnetP2PKHAddress = createBitcoinAddress('mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn');
|
|
23
24
|
expect(inferNetworkFromAddress(testnetP2PKHAddress)).toBe('testnet');
|
|
24
25
|
});
|
|
25
26
|
|
|
26
27
|
it('should return "testnet" for P2SH testnet addresses', () => {
|
|
27
|
-
const testnetP2SHAddress = '2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n';
|
|
28
|
+
const testnetP2SHAddress = createBitcoinAddress('2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n');
|
|
28
29
|
expect(inferNetworkFromAddress(testnetP2SHAddress)).toBe('testnet');
|
|
29
30
|
});
|
|
30
31
|
|
|
31
32
|
it('should return "testnet" for Bech32 testnet addresses', () => {
|
|
32
|
-
const testnetBech32Address =
|
|
33
|
+
const testnetBech32Address = createBitcoinAddress(
|
|
34
|
+
'tb1qxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyz'
|
|
35
|
+
);
|
|
33
36
|
expect(inferNetworkFromAddress(testnetBech32Address)).toBe('testnet');
|
|
34
37
|
});
|
|
35
38
|
|
|
36
39
|
it('should return "regtest" for Bech32 regtest addresses', () => {
|
|
37
|
-
const regtestBech32Address =
|
|
40
|
+
const regtestBech32Address = createBitcoinAddress(
|
|
41
|
+
'bcrt1qxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyz'
|
|
42
|
+
);
|
|
38
43
|
expect(inferNetworkFromAddress(regtestBech32Address)).toBe('regtest');
|
|
39
44
|
});
|
|
40
45
|
|
|
41
46
|
it('should throw an error for invalid addresses', () => {
|
|
42
|
-
const invalidAddress = 'invalidAddress';
|
|
47
|
+
const invalidAddress = createBitcoinAddress('invalidAddress');
|
|
43
48
|
expect(() => inferNetworkFromAddress(invalidAddress)).toThrow(
|
|
44
49
|
'Invalid or unsupported Bitcoin address format'
|
|
45
50
|
);
|
|
@@ -49,32 +54,32 @@ describe(inferNetworkFromAddress.name, () => {
|
|
|
49
54
|
|
|
50
55
|
describe(inferPaymentTypeFromAddress.name, () => {
|
|
51
56
|
it('should return p2wpkh for mainnet P2WPKH address', () => {
|
|
52
|
-
const address = 'bc1qxyzabc123'; // Example P2WPKH mainnet address
|
|
57
|
+
const address = createBitcoinAddress('bc1qxyzabc123'); // Example P2WPKH mainnet address
|
|
53
58
|
expect(inferPaymentTypeFromAddress(address)).toBe('p2wpkh');
|
|
54
59
|
});
|
|
55
60
|
|
|
56
61
|
it('should return p2tr for mainnet P2TR address', () => {
|
|
57
|
-
const address = 'bc1pxyzabc123'; // Example P2TR mainnet address
|
|
62
|
+
const address = createBitcoinAddress('bc1pxyzabc123'); // Example P2TR mainnet address
|
|
58
63
|
expect(inferPaymentTypeFromAddress(address)).toBe('p2tr');
|
|
59
64
|
});
|
|
60
65
|
|
|
61
66
|
it('should return p2wpkh for testnet P2WPKH address', () => {
|
|
62
|
-
const address = 'tb1qxyzabc123'; // Example P2WPKH testnet address
|
|
67
|
+
const address = createBitcoinAddress('tb1qxyzabc123'); // Example P2WPKH testnet address
|
|
63
68
|
expect(inferPaymentTypeFromAddress(address)).toBe('p2wpkh');
|
|
64
69
|
});
|
|
65
70
|
|
|
66
71
|
it('should return p2tr for testnet P2TR address', () => {
|
|
67
|
-
const address = 'tb1pxyzabc123'; // Example P2TR testnet address
|
|
72
|
+
const address = createBitcoinAddress('tb1pxyzabc123'); // Example P2TR testnet address
|
|
68
73
|
expect(inferPaymentTypeFromAddress(address)).toBe('p2tr');
|
|
69
74
|
});
|
|
70
75
|
|
|
71
76
|
it('should return p2wpkh for regtest P2WPKH address', () => {
|
|
72
|
-
const address = 'bcrt1qxyzabc123'; // Example P2WPKH regtest address
|
|
77
|
+
const address = createBitcoinAddress('bcrt1qxyzabc123'); // Example P2WPKH regtest address
|
|
73
78
|
expect(inferPaymentTypeFromAddress(address)).toBe('p2wpkh');
|
|
74
79
|
});
|
|
75
80
|
|
|
76
81
|
it('should return p2tr for regtest P2TR address', () => {
|
|
77
|
-
const address = 'bcrt1pxyzabc123'; // Example P2TR regtest address
|
|
82
|
+
const address = createBitcoinAddress('bcrt1pxyzabc123'); // Example P2TR regtest address
|
|
78
83
|
expect(inferPaymentTypeFromAddress(address)).toBe('p2tr');
|
|
79
84
|
});
|
|
80
85
|
});
|
|
@@ -10,15 +10,16 @@ import {
|
|
|
10
10
|
extractPurposeFromPath,
|
|
11
11
|
} from '@leather.io/crypto';
|
|
12
12
|
import { BitcoinNetworkModes, NetworkModes } from '@leather.io/models';
|
|
13
|
-
import type {
|
|
13
|
+
import type { BitcoinPaymentTypes } from '@leather.io/rpc';
|
|
14
14
|
import { defaultWalletKeyId, isDefined, whenNetwork } from '@leather.io/utils';
|
|
15
15
|
|
|
16
|
+
import { getTaprootPayment } from '../payments/p2tr-address-gen';
|
|
17
|
+
import { getNativeSegwitPaymentFromAddressIndex } from '../payments/p2wpkh-address-gen';
|
|
18
|
+
import { BitcoinAddress } from '../validation/bitcoin-address';
|
|
16
19
|
import { BtcSignerNetwork, getBtcSignerLibNetworkConfigByMode } from './bitcoin.network';
|
|
17
|
-
import { getTaprootPayment } from './p2tr-address-gen';
|
|
18
|
-
import { getNativeSegwitPaymentFromAddressIndex } from './p2wpkh-address-gen';
|
|
19
20
|
|
|
20
21
|
export interface BitcoinAccount {
|
|
21
|
-
type:
|
|
22
|
+
type: BitcoinPaymentTypes;
|
|
22
23
|
derivationPath: string;
|
|
23
24
|
keychain: HDKey;
|
|
24
25
|
accountIndex: number;
|
|
@@ -100,7 +101,10 @@ export function decodeBitcoinTx(tx: string): ReturnType<typeof btc.RawTx.decode>
|
|
|
100
101
|
return btc.RawTx.decode(hexToBytes(tx));
|
|
101
102
|
}
|
|
102
103
|
|
|
103
|
-
export function getAddressFromOutScript(
|
|
104
|
+
export function getAddressFromOutScript(
|
|
105
|
+
script: Uint8Array,
|
|
106
|
+
bitcoinNetwork: BtcSignerNetwork
|
|
107
|
+
): string {
|
|
104
108
|
const outputScript = btc.OutScript.decode(script);
|
|
105
109
|
|
|
106
110
|
switch (outputScript.type) {
|
|
@@ -135,7 +139,7 @@ export function getAddressFromOutScript(script: Uint8Array, bitcoinNetwork: BtcS
|
|
|
135
139
|
*/
|
|
136
140
|
export type BtcSignerLibPaymentTypeIdentifers = 'wpkh' | 'wsh' | 'tr' | 'pkh' | 'sh';
|
|
137
141
|
|
|
138
|
-
export const paymentTypeMap: Record<BtcSignerLibPaymentTypeIdentifers,
|
|
142
|
+
export const paymentTypeMap: Record<BtcSignerLibPaymentTypeIdentifers, BitcoinPaymentTypes> = {
|
|
139
143
|
wpkh: 'p2wpkh',
|
|
140
144
|
wsh: 'p2wpkh-p2sh',
|
|
141
145
|
tr: 'p2tr',
|
|
@@ -155,14 +159,16 @@ export function isBtcSignerLibPaymentType(
|
|
|
155
159
|
return payment in paymentTypeMap;
|
|
156
160
|
}
|
|
157
161
|
|
|
158
|
-
export function parseKnownPaymentType(
|
|
162
|
+
export function parseKnownPaymentType(
|
|
163
|
+
payment: BtcSignerLibPaymentTypeIdentifers | BitcoinPaymentTypes
|
|
164
|
+
) {
|
|
159
165
|
return isBtcSignerLibPaymentType(payment)
|
|
160
166
|
? btcSignerLibPaymentTypeToPaymentTypeMap(payment)
|
|
161
167
|
: payment;
|
|
162
168
|
}
|
|
163
169
|
|
|
164
|
-
export type PaymentTypeMap<T> = Record<
|
|
165
|
-
export function whenPaymentType(mode:
|
|
170
|
+
export type PaymentTypeMap<T> = Record<BitcoinPaymentTypes, T>;
|
|
171
|
+
export function whenPaymentType(mode: BitcoinPaymentTypes | BtcSignerLibPaymentTypeIdentifers) {
|
|
166
172
|
return <T>(paymentMap: PaymentTypeMap<T>): T => paymentMap[parseKnownPaymentType(mode)];
|
|
167
173
|
}
|
|
168
174
|
|
|
@@ -178,7 +184,7 @@ export function whenSupportedPaymentType(mode: SupportedPaymentType) {
|
|
|
178
184
|
* @example
|
|
179
185
|
* `m/86'/1'/0'/0/0`
|
|
180
186
|
*/
|
|
181
|
-
export function inferPaymentTypeFromPath(path: string):
|
|
187
|
+
export function inferPaymentTypeFromPath(path: string): BitcoinPaymentTypes {
|
|
182
188
|
const purpose = extractPurposeFromPath(path);
|
|
183
189
|
switch (purpose) {
|
|
184
190
|
case 84:
|
|
@@ -230,7 +236,7 @@ export function getBitcoinInputAddress(input: TransactionInput, bitcoinNetwork:
|
|
|
230
236
|
export function getInputPaymentType(
|
|
231
237
|
input: TransactionInput,
|
|
232
238
|
network: BitcoinNetworkModes
|
|
233
|
-
):
|
|
239
|
+
): BitcoinPaymentTypes {
|
|
234
240
|
const address = getBitcoinInputAddress(input, getBtcSignerLibNetworkConfigByMode(network));
|
|
235
241
|
if (address === '') throw new Error('Input address cannot be empty');
|
|
236
242
|
if (address.startsWith('bc1p') || address.startsWith('tb1p') || address.startsWith('bcrt1p'))
|
|
@@ -319,7 +325,7 @@ export function getPsbtTxOutputs(psbtTx: btc.Transaction): TransactionOutput[] {
|
|
|
319
325
|
return outputs;
|
|
320
326
|
}
|
|
321
327
|
|
|
322
|
-
export function inferNetworkFromAddress(address:
|
|
328
|
+
export function inferNetworkFromAddress(address: BitcoinAddress): BitcoinNetworkModes {
|
|
323
329
|
if (address.startsWith('bc1')) return 'mainnet';
|
|
324
330
|
if (address.startsWith('tb1')) return 'testnet';
|
|
325
331
|
if (address.startsWith('bcrt1')) return 'regtest';
|
|
@@ -333,7 +339,7 @@ export function inferNetworkFromAddress(address: string): BitcoinNetworkModes {
|
|
|
333
339
|
throw new Error('Invalid or unsupported Bitcoin address format');
|
|
334
340
|
}
|
|
335
341
|
|
|
336
|
-
export function inferPaymentTypeFromAddress(address:
|
|
342
|
+
export function inferPaymentTypeFromAddress(address: BitcoinAddress): SupportedPaymentType {
|
|
337
343
|
if (address.startsWith('bc1q') || address.startsWith('tb1q') || address.startsWith('bcrt1q'))
|
|
338
344
|
return 'p2wpkh';
|
|
339
345
|
|
package/src/{lookup-derivation-by-address.spec.ts → utils/lookup-derivation-by-address.spec.ts}
RENAMED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { deriveRootKeychainFromMnemonic } from '@leather.io/crypto';
|
|
2
2
|
|
|
3
|
-
import { testMnemonic } from '
|
|
3
|
+
import { testMnemonic } from '../../../../config/test-helpers';
|
|
4
|
+
import { deriveTaprootAccount } from '../payments/p2tr-address-gen';
|
|
5
|
+
import { deriveNativeSegwitAccountFromRootKeychain } from '../payments/p2wpkh-address-gen';
|
|
6
|
+
import { createBitcoinAddress } from '../validation/bitcoin-address';
|
|
4
7
|
import { lookupDerivationByAddress } from './lookup-derivation-by-address';
|
|
5
|
-
import { deriveTaprootAccount } from './p2tr-address-gen';
|
|
6
|
-
import { deriveNativeSegwitAccountFromRootKeychain } from './p2wpkh-address-gen';
|
|
7
8
|
|
|
8
9
|
describe(lookupDerivationByAddress.name, async () => {
|
|
9
10
|
const rootKeychain = await deriveRootKeychainFromMnemonic(testMnemonic);
|
|
@@ -35,7 +36,7 @@ describe(lookupDerivationByAddress.name, async () => {
|
|
|
35
36
|
nativeSegwitXpub: firstNativeSegwitAccountKeychain.keychain.publicExtendedKey,
|
|
36
37
|
iterationLimit: 100,
|
|
37
38
|
});
|
|
38
|
-
expect(lookup(address).path).toEqual(path);
|
|
39
|
+
expect(lookup(createBitcoinAddress(address)).path).toEqual(path);
|
|
39
40
|
});
|
|
40
41
|
});
|
|
41
42
|
|
|
@@ -50,7 +51,9 @@ describe(lookupDerivationByAddress.name, async () => {
|
|
|
50
51
|
iterationLimit: 10,
|
|
51
52
|
});
|
|
52
53
|
|
|
53
|
-
expect(lookup('bc1qvgtk702cayady9wvkhvs5jn8c2ldurhazx9nzf').path).toBe(
|
|
54
|
+
expect(lookup(createBitcoinAddress('bc1qvgtk702cayady9wvkhvs5jn8c2ldurhazx9nzf')).path).toBe(
|
|
55
|
+
`m/84'/0'/1'/0/0`
|
|
56
|
+
);
|
|
54
57
|
});
|
|
55
58
|
});
|
|
56
59
|
|
|
@@ -65,7 +68,9 @@ describe(lookupDerivationByAddress.name, async () => {
|
|
|
65
68
|
iterationLimit: 10,
|
|
66
69
|
});
|
|
67
70
|
|
|
68
|
-
expect(lookup('bc1qvgsomefakeaddressitwontfind').status).toBe(
|
|
71
|
+
expect(lookup(createBitcoinAddress('bc1qvgsomefakeaddressitwontfind')).status).toBe(
|
|
72
|
+
'failure'
|
|
73
|
+
);
|
|
69
74
|
});
|
|
70
75
|
});
|
|
71
76
|
});
|
|
@@ -2,6 +2,9 @@ import { HARDENED_OFFSET, HDKey } from '@scure/bip32';
|
|
|
2
2
|
|
|
3
3
|
import { createCounter } from '@leather.io/utils';
|
|
4
4
|
|
|
5
|
+
import { makeTaprootAddressIndexDerivationPath } from '../payments/p2tr-address-gen';
|
|
6
|
+
import { makeNativeSegwitAddressIndexDerivationPath } from '../payments/p2wpkh-address-gen';
|
|
7
|
+
import { BitcoinAddress } from '../validation/bitcoin-address';
|
|
5
8
|
import {
|
|
6
9
|
getNativeSegwitAddress,
|
|
7
10
|
getTaprootAddress,
|
|
@@ -9,8 +12,6 @@ import {
|
|
|
9
12
|
inferPaymentTypeFromAddress,
|
|
10
13
|
whenSupportedPaymentType,
|
|
11
14
|
} from './bitcoin.utils';
|
|
12
|
-
import { makeTaprootAddressIndexDerivationPath } from './p2tr-address-gen';
|
|
13
|
-
import { makeNativeSegwitAddressIndexDerivationPath } from './p2wpkh-address-gen';
|
|
14
15
|
|
|
15
16
|
interface LookUpDerivationByAddressArgs {
|
|
16
17
|
taprootXpub: string;
|
|
@@ -23,7 +24,7 @@ export function lookupDerivationByAddress(args: LookUpDerivationByAddressArgs) {
|
|
|
23
24
|
const taprootKeychain = HDKey.fromExtendedKey(taprootXpub);
|
|
24
25
|
const nativeSegwitKeychain = HDKey.fromExtendedKey(nativeSegwitXpub);
|
|
25
26
|
|
|
26
|
-
return (address:
|
|
27
|
+
return (address: BitcoinAddress) => {
|
|
27
28
|
const network = inferNetworkFromAddress(address);
|
|
28
29
|
const paymentType = inferPaymentTypeFromAddress(address);
|
|
29
30
|
|