@sidhujag/sysweb3-keyring 1.0.545 → 1.0.547
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/coverage/clover.xml +2875 -0
- package/coverage/coverage-final.json +29468 -0
- package/coverage/lcov-report/base.css +354 -0
- package/coverage/lcov-report/block-navigation.js +85 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +320 -0
- package/coverage/lcov-report/prettify.css +101 -0
- package/coverage/lcov-report/prettify.js +1008 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +191 -0
- package/coverage/lcov-report/src/index.html +276 -0
- package/coverage/lcov-report/src/index.ts.html +114 -0
- package/coverage/lcov-report/src/initial-state.ts.html +558 -0
- package/coverage/lcov-report/src/keyring-manager.ts.html +6279 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/index.html +178 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/index.ts.html +144 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/appClient.ts.html +1560 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/bip32.ts.html +276 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/buffertools.ts.html +495 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/clientCommands.ts.html +1138 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/index.html +363 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkelizedPsbt.ts.html +289 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkle.ts.html +486 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkleMap.ts.html +240 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/policy.ts.html +342 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/psbtv2.ts.html +2388 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/varint.ts.html +453 -0
- package/coverage/lcov-report/src/ledger/consts.ts.html +177 -0
- package/coverage/lcov-report/src/ledger/index.html +216 -0
- package/coverage/lcov-report/src/ledger/index.ts.html +1371 -0
- package/coverage/lcov-report/src/ledger/utils.ts.html +102 -0
- package/coverage/lcov-report/src/signers.ts.html +591 -0
- package/coverage/lcov-report/src/storage.ts.html +198 -0
- package/coverage/lcov-report/src/transactions/ethereum.ts.html +5826 -0
- package/coverage/lcov-report/src/transactions/index.html +216 -0
- package/coverage/lcov-report/src/transactions/index.ts.html +93 -0
- package/coverage/lcov-report/src/transactions/syscoin.ts.html +1521 -0
- package/coverage/lcov-report/src/trezor/index.html +176 -0
- package/coverage/lcov-report/src/trezor/index.ts.html +2655 -0
- package/coverage/lcov-report/src/types.ts.html +1443 -0
- package/coverage/lcov-report/src/utils/derivation-paths.ts.html +486 -0
- package/coverage/lcov-report/src/utils/index.html +196 -0
- package/coverage/lcov-report/src/utils/psbt.ts.html +159 -0
- package/coverage/lcov-report/test/helpers/constants.ts.html +627 -0
- package/coverage/lcov-report/test/helpers/index.html +176 -0
- package/coverage/lcov.info +4832 -0
- package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/appClient.js +1 -124
- package/dist/cjs/ledger/bitcoin_client/lib/appClient.js.map +1 -0
- package/{cjs → dist/cjs}/transactions/ethereum.js +6 -2
- package/dist/cjs/transactions/ethereum.js.map +1 -0
- package/dist/package.json +50 -0
- package/{types → dist/types}/ledger/bitcoin_client/lib/appClient.d.ts +0 -6
- package/examples/basic-usage.js +140 -0
- package/jest.config.js +32 -0
- package/package.json +31 -13
- package/readme.md +201 -0
- package/src/declare.d.ts +7 -0
- package/src/errorUtils.ts +83 -0
- package/src/hardware-wallet-manager.ts +655 -0
- package/src/index.ts +12 -0
- package/src/initial-state.ts +108 -0
- package/src/keyring-manager.ts +2698 -0
- package/src/ledger/bitcoin_client/index.ts +19 -0
- package/src/ledger/bitcoin_client/lib/appClient.ts +405 -0
- package/src/ledger/bitcoin_client/lib/bip32.ts +61 -0
- package/src/ledger/bitcoin_client/lib/buffertools.ts +134 -0
- package/src/ledger/bitcoin_client/lib/clientCommands.ts +356 -0
- package/src/ledger/bitcoin_client/lib/constants.ts +12 -0
- package/src/ledger/bitcoin_client/lib/merkelizedPsbt.ts +65 -0
- package/src/ledger/bitcoin_client/lib/merkle.ts +136 -0
- package/src/ledger/bitcoin_client/lib/merkleMap.ts +49 -0
- package/src/ledger/bitcoin_client/lib/policy.ts +91 -0
- package/src/ledger/bitcoin_client/lib/psbtv2.ts +768 -0
- package/src/ledger/bitcoin_client/lib/varint.ts +120 -0
- package/src/ledger/consts.ts +3 -0
- package/src/ledger/index.ts +685 -0
- package/src/ledger/types.ts +74 -0
- package/src/network-utils.ts +99 -0
- package/src/providers.ts +345 -0
- package/src/signers.ts +158 -0
- package/src/storage.ts +63 -0
- package/src/transactions/__tests__/integration.test.ts +303 -0
- package/src/transactions/__tests__/syscoin.test.ts +409 -0
- package/src/transactions/ethereum.ts +2503 -0
- package/src/transactions/index.ts +2 -0
- package/src/transactions/syscoin.ts +542 -0
- package/src/trezor/index.ts +1050 -0
- package/src/types.ts +366 -0
- package/src/utils/derivation-paths.ts +133 -0
- package/src/utils/psbt.ts +24 -0
- package/src/utils.ts +191 -0
- package/test/README.md +158 -0
- package/test/__mocks__/ledger-mock.js +20 -0
- package/test/__mocks__/trezor-mock.js +75 -0
- package/test/cleanup-summary.md +167 -0
- package/test/helpers/README.md +78 -0
- package/test/helpers/constants.ts +79 -0
- package/test/helpers/setup.ts +714 -0
- package/test/integration/import-validation.spec.ts +588 -0
- package/test/unit/hardware/ledger.spec.ts +869 -0
- package/test/unit/hardware/trezor.spec.ts +828 -0
- package/test/unit/keyring-manager/account-management.spec.ts +970 -0
- package/test/unit/keyring-manager/import-watchonly.spec.ts +181 -0
- package/test/unit/keyring-manager/import-wif.spec.ts +126 -0
- package/test/unit/keyring-manager/initialization.spec.ts +782 -0
- package/test/unit/keyring-manager/key-derivation.spec.ts +996 -0
- package/test/unit/keyring-manager/security.spec.ts +505 -0
- package/test/unit/keyring-manager/state-management.spec.ts +375 -0
- package/test/unit/network/network-management.spec.ts +372 -0
- package/test/unit/transactions/ethereum-transactions.spec.ts +382 -0
- package/test/unit/transactions/syscoin-transactions.spec.ts +615 -0
- package/tsconfig.json +14 -0
- package/cjs/ledger/bitcoin_client/lib/appClient.js.map +0 -1
- package/cjs/transactions/ethereum.js.map +0 -1
- /package/{README.md → dist/README.md} +0 -0
- /package/{cjs → dist/cjs}/errorUtils.js +0 -0
- /package/{cjs → dist/cjs}/errorUtils.js.map +0 -0
- /package/{cjs → dist/cjs}/hardware-wallet-manager.js +0 -0
- /package/{cjs → dist/cjs}/hardware-wallet-manager.js.map +0 -0
- /package/{cjs → dist/cjs}/index.js +0 -0
- /package/{cjs → dist/cjs}/index.js.map +0 -0
- /package/{cjs → dist/cjs}/initial-state.js +0 -0
- /package/{cjs → dist/cjs}/initial-state.js.map +0 -0
- /package/{cjs → dist/cjs}/keyring-manager.js +0 -0
- /package/{cjs → dist/cjs}/keyring-manager.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/index.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/index.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/bip32.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/bip32.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/buffertools.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/buffertools.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/clientCommands.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/clientCommands.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/constants.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/constants.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkelizedPsbt.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkelizedPsbt.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkle.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkle.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkleMap.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkleMap.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/policy.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/policy.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/psbtv2.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/psbtv2.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/varint.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/varint.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/consts.js +0 -0
- /package/{cjs → dist/cjs}/ledger/consts.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/index.js +0 -0
- /package/{cjs → dist/cjs}/ledger/index.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/types.js +0 -0
- /package/{cjs → dist/cjs}/ledger/types.js.map +0 -0
- /package/{cjs → dist/cjs}/network-utils.js +0 -0
- /package/{cjs → dist/cjs}/network-utils.js.map +0 -0
- /package/{cjs → dist/cjs}/providers.js +0 -0
- /package/{cjs → dist/cjs}/providers.js.map +0 -0
- /package/{cjs → dist/cjs}/signers.js +0 -0
- /package/{cjs → dist/cjs}/signers.js.map +0 -0
- /package/{cjs → dist/cjs}/storage.js +0 -0
- /package/{cjs → dist/cjs}/storage.js.map +0 -0
- /package/{cjs → dist/cjs}/transactions/__tests__/integration.test.js +0 -0
- /package/{cjs → dist/cjs}/transactions/__tests__/integration.test.js.map +0 -0
- /package/{cjs → dist/cjs}/transactions/__tests__/syscoin.test.js +0 -0
- /package/{cjs → dist/cjs}/transactions/__tests__/syscoin.test.js.map +0 -0
- /package/{cjs → dist/cjs}/transactions/index.js +0 -0
- /package/{cjs → dist/cjs}/transactions/index.js.map +0 -0
- /package/{cjs → dist/cjs}/transactions/syscoin.js +0 -0
- /package/{cjs → dist/cjs}/transactions/syscoin.js.map +0 -0
- /package/{cjs → dist/cjs}/trezor/index.js +0 -0
- /package/{cjs → dist/cjs}/trezor/index.js.map +0 -0
- /package/{cjs → dist/cjs}/types.js +0 -0
- /package/{cjs → dist/cjs}/types.js.map +0 -0
- /package/{cjs → dist/cjs}/utils/derivation-paths.js +0 -0
- /package/{cjs → dist/cjs}/utils/derivation-paths.js.map +0 -0
- /package/{cjs → dist/cjs}/utils/psbt.js +0 -0
- /package/{cjs → dist/cjs}/utils/psbt.js.map +0 -0
- /package/{cjs → dist/cjs}/utils.js +0 -0
- /package/{cjs → dist/cjs}/utils.js.map +0 -0
- /package/{types → dist/types}/errorUtils.d.ts +0 -0
- /package/{types → dist/types}/hardware-wallet-manager.d.ts +0 -0
- /package/{types → dist/types}/index.d.ts +0 -0
- /package/{types → dist/types}/initial-state.d.ts +0 -0
- /package/{types → dist/types}/keyring-manager.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/index.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/bip32.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/buffertools.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/clientCommands.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/constants.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/merkelizedPsbt.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/merkle.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/merkleMap.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/policy.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/psbtv2.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/varint.d.ts +0 -0
- /package/{types → dist/types}/ledger/consts.d.ts +0 -0
- /package/{types → dist/types}/ledger/index.d.ts +0 -0
- /package/{types → dist/types}/ledger/types.d.ts +0 -0
- /package/{types → dist/types}/network-utils.d.ts +0 -0
- /package/{types → dist/types}/providers.d.ts +0 -0
- /package/{types → dist/types}/signers.d.ts +0 -0
- /package/{types → dist/types}/storage.d.ts +0 -0
- /package/{types → dist/types}/transactions/__tests__/integration.test.d.ts +0 -0
- /package/{types → dist/types}/transactions/__tests__/syscoin.test.d.ts +0 -0
- /package/{types → dist/types}/transactions/ethereum.d.ts +0 -0
- /package/{types → dist/types}/transactions/index.d.ts +0 -0
- /package/{types → dist/types}/transactions/syscoin.d.ts +0 -0
- /package/{types → dist/types}/trezor/index.d.ts +0 -0
- /package/{types → dist/types}/types.d.ts +0 -0
- /package/{types → dist/types}/utils/derivation-paths.d.ts +0 -0
- /package/{types → dist/types}/utils/psbt.d.ts +0 -0
- /package/{types → dist/types}/utils.d.ts +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* eslint-disable import/no-named-as-default */
|
|
2
|
+
import AppClient, { PartialSignature } from './lib/appClient';
|
|
3
|
+
import {
|
|
4
|
+
DefaultDescriptorTemplate,
|
|
5
|
+
DefaultWalletPolicy,
|
|
6
|
+
WalletPolicy,
|
|
7
|
+
} from './lib/policy';
|
|
8
|
+
import { PsbtV2 } from './lib/psbtv2';
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
AppClient,
|
|
12
|
+
PsbtV2,
|
|
13
|
+
DefaultDescriptorTemplate,
|
|
14
|
+
DefaultWalletPolicy,
|
|
15
|
+
PartialSignature,
|
|
16
|
+
WalletPolicy,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default AppClient;
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import Transport from '@ledgerhq/hw-transport';
|
|
2
|
+
|
|
3
|
+
import { pathElementsToBuffer, pathStringToArray } from './bip32';
|
|
4
|
+
import { ClientCommandInterpreter } from './clientCommands';
|
|
5
|
+
import { MerkelizedPsbt } from './merkelizedPsbt';
|
|
6
|
+
import { hashLeaf, Merkle } from './merkle';
|
|
7
|
+
import { WalletPolicy } from './policy';
|
|
8
|
+
import { PsbtV2 } from './psbtv2';
|
|
9
|
+
import { createVarint, parseVarint } from './varint';
|
|
10
|
+
|
|
11
|
+
const CLA_BTC = 0xe1;
|
|
12
|
+
const CLA_FRAMEWORK = 0xf8;
|
|
13
|
+
|
|
14
|
+
const CURRENT_PROTOCOL_VERSION = 1; // supported from version 2.1.0 of the app
|
|
15
|
+
|
|
16
|
+
enum BitcoinIns {
|
|
17
|
+
GET_PUBKEY = 0x00,
|
|
18
|
+
REGISTER_WALLET = 0x02,
|
|
19
|
+
GET_WALLET_ADDRESS = 0x03,
|
|
20
|
+
SIGN_PSBT = 0x04,
|
|
21
|
+
GET_MASTER_FINGERPRINT = 0x05,
|
|
22
|
+
SIGN_MESSAGE = 0x10,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
enum FrameworkIns {
|
|
26
|
+
CONTINUE_INTERRUPTED = 0x01,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* This class represents a partial signature produced by the app during signing.
|
|
31
|
+
* It always contains the `signature` and the corresponding `pubkey` whose private key
|
|
32
|
+
* was used for signing; in the case of taproot script paths, it also contains the
|
|
33
|
+
* tapleaf hash.
|
|
34
|
+
*/
|
|
35
|
+
export class PartialSignature {
|
|
36
|
+
readonly pubkey: Buffer;
|
|
37
|
+
readonly signature: Buffer;
|
|
38
|
+
readonly tapleafHash?: Buffer;
|
|
39
|
+
|
|
40
|
+
constructor(pubkey: Buffer, signature: Buffer, tapleafHash?: Buffer) {
|
|
41
|
+
this.pubkey = pubkey;
|
|
42
|
+
this.signature = signature;
|
|
43
|
+
this.tapleafHash = tapleafHash;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Creates an instance of `PartialSignature` from the returned raw augmented pubkey and signature.
|
|
49
|
+
* @param pubkeyAugm the public key, concatenated with the tapleaf hash in the case of taproot script path spend.
|
|
50
|
+
* @param signature the signature
|
|
51
|
+
* @returns an instance of `PartialSignature`.
|
|
52
|
+
*/
|
|
53
|
+
function makePartialSignature(
|
|
54
|
+
pubkeyAugm: Buffer,
|
|
55
|
+
signature: Buffer
|
|
56
|
+
): PartialSignature {
|
|
57
|
+
if (pubkeyAugm.length == 64) {
|
|
58
|
+
// tapscript spend: concatenation of 32-bytes x-only pubkey and 32-bytes tapleaf_hash
|
|
59
|
+
return new PartialSignature(
|
|
60
|
+
pubkeyAugm.slice(0, 32),
|
|
61
|
+
signature,
|
|
62
|
+
pubkeyAugm.slice(32, 64)
|
|
63
|
+
);
|
|
64
|
+
} else if (pubkeyAugm.length == 32 || pubkeyAugm.length == 33) {
|
|
65
|
+
// legacy, segwit or taproot keypath spend: pubkeyAugm is just the pubkey
|
|
66
|
+
return new PartialSignature(pubkeyAugm, signature);
|
|
67
|
+
} else {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Invalid length for pubkeyAugm: ${pubkeyAugm.length} bytes.`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* This class encapsulates the APDU protocol documented at
|
|
76
|
+
* https://github.com/LedgerHQ/app-bitcoin-new/blob/master/doc/bitcoin.md
|
|
77
|
+
*/
|
|
78
|
+
export class AppClient {
|
|
79
|
+
readonly transport: Transport;
|
|
80
|
+
|
|
81
|
+
constructor(transport: Transport) {
|
|
82
|
+
this.transport = transport;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private async makeRequest(
|
|
86
|
+
ins: BitcoinIns,
|
|
87
|
+
data: Buffer,
|
|
88
|
+
cci?: ClientCommandInterpreter
|
|
89
|
+
): Promise<Buffer> {
|
|
90
|
+
let response: Buffer = await this.transport.send(
|
|
91
|
+
CLA_BTC,
|
|
92
|
+
ins,
|
|
93
|
+
0,
|
|
94
|
+
CURRENT_PROTOCOL_VERSION,
|
|
95
|
+
data,
|
|
96
|
+
[0x9000, 0xe000]
|
|
97
|
+
);
|
|
98
|
+
while (response.readUInt16BE(response.length - 2) === 0xe000) {
|
|
99
|
+
if (!cci) {
|
|
100
|
+
throw new Error('Unexpected SW_INTERRUPTED_EXECUTION');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const hwRequest = response.slice(0, -2);
|
|
104
|
+
const commandResponse = cci.execute(hwRequest);
|
|
105
|
+
|
|
106
|
+
response = await this.transport.send(
|
|
107
|
+
CLA_FRAMEWORK,
|
|
108
|
+
FrameworkIns.CONTINUE_INTERRUPTED,
|
|
109
|
+
0,
|
|
110
|
+
0,
|
|
111
|
+
commandResponse,
|
|
112
|
+
[0x9000, 0xe000]
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
return response.slice(0, -2); // drop the status word (can only be 0x9000 at this point)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Returns an object containing the currently running app's name, version and the device status flags.
|
|
120
|
+
*
|
|
121
|
+
* @returns an object with app name, version and device status flags.
|
|
122
|
+
*/
|
|
123
|
+
public async getAppAndVersion(): Promise<{
|
|
124
|
+
flags: number | Buffer;
|
|
125
|
+
name: string;
|
|
126
|
+
version: string;
|
|
127
|
+
}> {
|
|
128
|
+
const r = await this.transport.send(0xb0, 0x01, 0x00, 0x00);
|
|
129
|
+
let i = 0;
|
|
130
|
+
const format = r[i++];
|
|
131
|
+
if (format !== 1) throw new Error('Unexpected response');
|
|
132
|
+
|
|
133
|
+
const nameLength = r[i++];
|
|
134
|
+
const name = r.slice(i, (i += nameLength)).toString('ascii');
|
|
135
|
+
const versionLength = r[i++];
|
|
136
|
+
const version = r.slice(i, (i += versionLength)).toString('ascii');
|
|
137
|
+
const flagLength = r[i++];
|
|
138
|
+
const flags = r.slice(i, (i += flagLength));
|
|
139
|
+
return {
|
|
140
|
+
name,
|
|
141
|
+
version,
|
|
142
|
+
flags,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Requests the BIP-32 extended pubkey to the hardware wallet.
|
|
148
|
+
* If `display` is `false`, only standard paths will be accepted; an error is returned if an unusual path is
|
|
149
|
+
* requested.
|
|
150
|
+
* If `display` is `true`, the requested path is shown on screen for user verification; unusual paths can be
|
|
151
|
+
* requested, and a warning is shown to the user in that case.
|
|
152
|
+
*
|
|
153
|
+
* @param path the requested BIP-32 path as a string
|
|
154
|
+
* @param display `false` to silently retrieve a pubkey for a standard path, `true` to display the path on screen
|
|
155
|
+
* @returns the base58-encoded serialized extended pubkey (xpub)
|
|
156
|
+
*/
|
|
157
|
+
async getExtendedPubkey(path: string, display = false): Promise<string> {
|
|
158
|
+
const pathElements = pathStringToArray(path);
|
|
159
|
+
if (pathElements.length > 6) {
|
|
160
|
+
throw new Error('Path too long. At most 6 levels allowed.');
|
|
161
|
+
}
|
|
162
|
+
const response = await this.makeRequest(
|
|
163
|
+
BitcoinIns.GET_PUBKEY,
|
|
164
|
+
Buffer.concat([
|
|
165
|
+
Buffer.from(display ? [1] : [0]),
|
|
166
|
+
pathElementsToBuffer(pathElements),
|
|
167
|
+
])
|
|
168
|
+
);
|
|
169
|
+
return response.toString('ascii');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Registers a `WalletPolicy`, after interactive verification from the user.
|
|
174
|
+
* On success, after user's approval, this function returns the id (which is the same that can be computed with
|
|
175
|
+
* `walletPolicy.getid()`), followed by the 32-byte hmac. The client should store the hmac to use it for future
|
|
176
|
+
* requests to `getWalletAddress` or `signPsbt` using this `WalletPolicy`.
|
|
177
|
+
*
|
|
178
|
+
* @param walletPolicy the `WalletPolicy` to register
|
|
179
|
+
* @returns a pair of two 32-byte arrays: the id of the Wallet Policy, followed by the policy hmac
|
|
180
|
+
*/
|
|
181
|
+
async registerWallet(
|
|
182
|
+
walletPolicy: WalletPolicy
|
|
183
|
+
): Promise<readonly [Buffer, Buffer]> {
|
|
184
|
+
const clientInterpreter = new ClientCommandInterpreter();
|
|
185
|
+
|
|
186
|
+
clientInterpreter.addKnownWalletPolicy(walletPolicy);
|
|
187
|
+
|
|
188
|
+
const serializedWalletPolicy = walletPolicy.serialize();
|
|
189
|
+
const response = await this.makeRequest(
|
|
190
|
+
BitcoinIns.REGISTER_WALLET,
|
|
191
|
+
Buffer.concat([
|
|
192
|
+
createVarint(serializedWalletPolicy.length),
|
|
193
|
+
serializedWalletPolicy,
|
|
194
|
+
]),
|
|
195
|
+
clientInterpreter
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
if (response.length != 64) {
|
|
199
|
+
throw Error(
|
|
200
|
+
`Invalid response length. Expected 64 bytes, got ${response.length}`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
const walletId = response.subarray(0, 32);
|
|
204
|
+
const walletHMAC = response.subarray(32);
|
|
205
|
+
|
|
206
|
+
// Note: Address validation removed - trusting Ledger device for address generation
|
|
207
|
+
|
|
208
|
+
return [walletId, walletHMAC];
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Returns the address of `walletPolicy` for the given `change` and `addressIndex`.
|
|
213
|
+
*
|
|
214
|
+
* @param walletPolicy the `WalletPolicy` to use
|
|
215
|
+
* @param walletHMAC the 32-byte hmac returned during wallet registration for a registered policy; otherwise
|
|
216
|
+
* `null` for a standard policy
|
|
217
|
+
* @param change `0` for a normal receive address, `1` for a change address
|
|
218
|
+
* @param addressIndex the address index to retrieve
|
|
219
|
+
* @param display `True` to show the address on screen, `False` to retrieve it silently
|
|
220
|
+
* @returns the address, as an ascii string.
|
|
221
|
+
*/
|
|
222
|
+
async getWalletAddress(
|
|
223
|
+
walletPolicy: WalletPolicy,
|
|
224
|
+
walletHMAC: Buffer | null,
|
|
225
|
+
change: number,
|
|
226
|
+
addressIndex: number,
|
|
227
|
+
display: boolean
|
|
228
|
+
): Promise<string> {
|
|
229
|
+
if (change !== 0 && change !== 1)
|
|
230
|
+
throw new Error('Change can only be 0 or 1');
|
|
231
|
+
if (addressIndex < 0 || !Number.isInteger(addressIndex))
|
|
232
|
+
throw new Error('Invalid address index');
|
|
233
|
+
|
|
234
|
+
if (walletHMAC != null && walletHMAC.length != 32) {
|
|
235
|
+
throw new Error('Invalid HMAC length');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const clientInterpreter = new ClientCommandInterpreter();
|
|
239
|
+
// Provide wallet policy artifacts to the interpreter
|
|
240
|
+
clientInterpreter.addKnownWalletPolicy(walletPolicy);
|
|
241
|
+
|
|
242
|
+
const addressIndexBuffer = Buffer.alloc(4);
|
|
243
|
+
addressIndexBuffer.writeUInt32BE(addressIndex, 0);
|
|
244
|
+
|
|
245
|
+
const response = await this.makeRequest(
|
|
246
|
+
BitcoinIns.GET_WALLET_ADDRESS,
|
|
247
|
+
Buffer.concat([
|
|
248
|
+
Buffer.from(display ? [1] : [0]),
|
|
249
|
+
walletPolicy.getId(),
|
|
250
|
+
walletHMAC || Buffer.alloc(32, 0),
|
|
251
|
+
Buffer.from([change]),
|
|
252
|
+
addressIndexBuffer,
|
|
253
|
+
]),
|
|
254
|
+
clientInterpreter
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
const address = response.toString('ascii');
|
|
258
|
+
return address;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Signs a psbt using a (standard or registered) `WalletPolicy`. This is an interactive command, as user validation
|
|
263
|
+
* is necessary using the device's secure screen.
|
|
264
|
+
* On success, a map of input indexes and signatures is returned.
|
|
265
|
+
* @param psbt a base64-encoded string, or a psbt in a binary Buffer. Using the `PsbtV2` type is deprecated.
|
|
266
|
+
* @param walletPolicy the `WalletPolicy` to use for signing
|
|
267
|
+
* @param walletHMAC the 32-byte hmac obtained during wallet policy registration, or `null` for a standard policy
|
|
268
|
+
* @param progressCallback optionally, a callback that will be called every time a signature is produced during
|
|
269
|
+
* the signing process. The callback does not receive any argument, but can be used to track progress.
|
|
270
|
+
* @returns an array of of tuples with 2 elements containing:
|
|
271
|
+
* - the index of the input being signed;
|
|
272
|
+
* - an instance of PartialSignature
|
|
273
|
+
*/
|
|
274
|
+
async signPsbt(
|
|
275
|
+
psbt: PsbtV2 | string | Buffer,
|
|
276
|
+
walletPolicy: WalletPolicy,
|
|
277
|
+
walletHMAC: Buffer | null,
|
|
278
|
+
progressCallback?: () => void
|
|
279
|
+
): Promise<[number, PartialSignature][]> {
|
|
280
|
+
if (typeof psbt === 'string') {
|
|
281
|
+
psbt = Buffer.from(psbt, 'base64');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (Buffer.isBuffer(psbt)) {
|
|
285
|
+
const psbtObj = new PsbtV2();
|
|
286
|
+
psbtObj.deserialize(psbt);
|
|
287
|
+
psbt = psbtObj;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const merkelizedPsbt = new MerkelizedPsbt(psbt);
|
|
291
|
+
|
|
292
|
+
if (walletHMAC != null && walletHMAC.length != 32) {
|
|
293
|
+
throw new Error('Invalid HMAC length');
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const clientInterpreter = new ClientCommandInterpreter(progressCallback);
|
|
297
|
+
|
|
298
|
+
// prepare ClientCommandInterpreter
|
|
299
|
+
clientInterpreter.addKnownWalletPolicy(walletPolicy);
|
|
300
|
+
|
|
301
|
+
clientInterpreter.addKnownMapping(merkelizedPsbt.globalMerkleMap);
|
|
302
|
+
for (const map of merkelizedPsbt.inputMerkleMaps) {
|
|
303
|
+
clientInterpreter.addKnownMapping(map);
|
|
304
|
+
}
|
|
305
|
+
for (const map of merkelizedPsbt.outputMerkleMaps) {
|
|
306
|
+
clientInterpreter.addKnownMapping(map);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
clientInterpreter.addKnownList(merkelizedPsbt.inputMapCommitments);
|
|
310
|
+
const inputMapsRoot = new Merkle(
|
|
311
|
+
merkelizedPsbt.inputMapCommitments.map((m) => hashLeaf(m))
|
|
312
|
+
).getRoot();
|
|
313
|
+
clientInterpreter.addKnownList(merkelizedPsbt.outputMapCommitments);
|
|
314
|
+
const outputMapsRoot = new Merkle(
|
|
315
|
+
merkelizedPsbt.outputMapCommitments.map((m) => hashLeaf(m))
|
|
316
|
+
).getRoot();
|
|
317
|
+
|
|
318
|
+
await this.makeRequest(
|
|
319
|
+
BitcoinIns.SIGN_PSBT,
|
|
320
|
+
Buffer.concat([
|
|
321
|
+
merkelizedPsbt.getGlobalKeysValuesRoot(),
|
|
322
|
+
createVarint(merkelizedPsbt.getGlobalInputCount()),
|
|
323
|
+
inputMapsRoot,
|
|
324
|
+
createVarint(merkelizedPsbt.getGlobalOutputCount()),
|
|
325
|
+
outputMapsRoot,
|
|
326
|
+
walletPolicy.getId(),
|
|
327
|
+
walletHMAC || Buffer.alloc(32, 0),
|
|
328
|
+
]),
|
|
329
|
+
clientInterpreter
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
const yielded = clientInterpreter.getYielded();
|
|
333
|
+
|
|
334
|
+
const ret: [number, PartialSignature][] = [];
|
|
335
|
+
for (const inputAndSig of yielded) {
|
|
336
|
+
// inputAndSig contains:
|
|
337
|
+
// <inputIndex : varint> <pubkeyLen : 1 byte> <pubkey : pubkeyLen bytes (32 or 33)> <signature : variable length>
|
|
338
|
+
const [inputIndex, inputIndexLen] = parseVarint(inputAndSig, 0);
|
|
339
|
+
const pubkeyAugmLen = inputAndSig[inputIndexLen];
|
|
340
|
+
const pubkeyAugm = inputAndSig.subarray(
|
|
341
|
+
inputIndexLen + 1,
|
|
342
|
+
inputIndexLen + 1 + pubkeyAugmLen
|
|
343
|
+
);
|
|
344
|
+
const signature = inputAndSig.subarray(inputIndexLen + 1 + pubkeyAugmLen);
|
|
345
|
+
|
|
346
|
+
const partialSig = makePartialSignature(pubkeyAugm, signature);
|
|
347
|
+
|
|
348
|
+
ret.push([Number(inputIndex), partialSig]);
|
|
349
|
+
}
|
|
350
|
+
return ret;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Returns the fingerprint of the master public key, as per BIP-32 standard.
|
|
355
|
+
* @returns the master key fingerprint as a string of 8 hexadecimal digits.
|
|
356
|
+
*/
|
|
357
|
+
async getMasterFingerprint(): Promise<string> {
|
|
358
|
+
const fpr = await this.makeRequest(
|
|
359
|
+
BitcoinIns.GET_MASTER_FINGERPRINT,
|
|
360
|
+
Buffer.from([])
|
|
361
|
+
);
|
|
362
|
+
return fpr.toString('hex');
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Signs a message using the legacy Bitcoin Message Signing standard. The signed message is
|
|
367
|
+
* the double-sha256 hash of the concatenation of:
|
|
368
|
+
* - "\x18Bitcoin Signed Message:\n";
|
|
369
|
+
* - the length of `message`, encoded as a Bitcoin-style variable length integer;
|
|
370
|
+
* - `message`.
|
|
371
|
+
*
|
|
372
|
+
* @param message the serialized message to sign
|
|
373
|
+
* @param path the BIP-32 path of the key used to sign the message
|
|
374
|
+
* @returns base64-encoded signature of the message.
|
|
375
|
+
*/
|
|
376
|
+
async signMessage(message: Buffer, path: string): Promise<string> {
|
|
377
|
+
const pathElements = pathStringToArray(path);
|
|
378
|
+
|
|
379
|
+
const clientInterpreter = new ClientCommandInterpreter();
|
|
380
|
+
|
|
381
|
+
// prepare ClientCommandInterpreter
|
|
382
|
+
const nChunks = Math.ceil(message.length / 64);
|
|
383
|
+
const chunks: Buffer[] = [];
|
|
384
|
+
for (let i = 0; i < nChunks; i++) {
|
|
385
|
+
chunks.push(message.subarray(64 * i, 64 * i + 64));
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
clientInterpreter.addKnownList(chunks);
|
|
389
|
+
const chunksRoot = new Merkle(chunks.map((m) => hashLeaf(m))).getRoot();
|
|
390
|
+
|
|
391
|
+
const result = await this.makeRequest(
|
|
392
|
+
BitcoinIns.SIGN_MESSAGE,
|
|
393
|
+
Buffer.concat([
|
|
394
|
+
pathElementsToBuffer(pathElements),
|
|
395
|
+
createVarint(message.length),
|
|
396
|
+
chunksRoot,
|
|
397
|
+
]),
|
|
398
|
+
clientInterpreter
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
return result.toString('base64');
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export default AppClient;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import bippath from 'bip32-path';
|
|
2
|
+
import bs58check from 'bs58check';
|
|
3
|
+
|
|
4
|
+
export function pathElementsToBuffer(paths: readonly number[]): Buffer {
|
|
5
|
+
const buffer = Buffer.alloc(1 + paths.length * 4);
|
|
6
|
+
buffer[0] = paths.length;
|
|
7
|
+
paths.forEach((element, index) => {
|
|
8
|
+
buffer.writeUInt32BE(element, 1 + 4 * index);
|
|
9
|
+
});
|
|
10
|
+
return buffer;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function bip32asBuffer(path: string): Buffer {
|
|
14
|
+
const pathElements = !path ? [] : pathStringToArray(path);
|
|
15
|
+
return pathElementsToBuffer(pathElements);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function pathArrayToString(pathElements: readonly number[]): string {
|
|
19
|
+
// bippath doesn't handle an empty path.
|
|
20
|
+
if (pathElements.length == 0) {
|
|
21
|
+
return 'm';
|
|
22
|
+
}
|
|
23
|
+
return bippath.fromPathArray(pathElements).toString();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function pathStringToArray(path: string): readonly number[] {
|
|
27
|
+
// bippath doesn't handle an empty path.
|
|
28
|
+
if (path == 'm' || path == '') {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
return bippath.fromString(path).toPathArray();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function pubkeyFromXpub(xpub: string): Buffer {
|
|
35
|
+
const xpubBuf = Buffer.from(bs58check.decode(xpub));
|
|
36
|
+
return xpubBuf.slice(xpubBuf.length - 33);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getXpubComponents(xpub: string): {
|
|
40
|
+
readonly chaincode: Buffer;
|
|
41
|
+
readonly pubkey: Buffer;
|
|
42
|
+
readonly version: number;
|
|
43
|
+
} {
|
|
44
|
+
const xpubBuf = Buffer.from(bs58check.decode(xpub));
|
|
45
|
+
return {
|
|
46
|
+
chaincode: xpubBuf.slice(13, 13 + 32),
|
|
47
|
+
pubkey: xpubBuf.slice(xpubBuf.length - 33),
|
|
48
|
+
version: xpubBuf.readUInt32BE(0),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function hardenedPathOf(
|
|
53
|
+
pathElements: readonly number[]
|
|
54
|
+
): readonly number[] {
|
|
55
|
+
for (let i = pathElements.length - 1; i >= 0; i--) {
|
|
56
|
+
if (pathElements[i] >= 0x80000000) {
|
|
57
|
+
return pathElements.slice(0, i + 1);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { createVarint, parseVarint, sanitizeBigintToNumber } from './varint';
|
|
2
|
+
|
|
3
|
+
export function unsafeTo64bitLE(n: number): Buffer {
|
|
4
|
+
// we want to represent the input as a 8-bytes array
|
|
5
|
+
if (n > Number.MAX_SAFE_INTEGER) {
|
|
6
|
+
throw new Error("Can't convert numbers > MAX_SAFE_INT");
|
|
7
|
+
}
|
|
8
|
+
const byteArray = Buffer.alloc(8, 0);
|
|
9
|
+
for (let index = 0; index < byteArray.length; index++) {
|
|
10
|
+
const byte = n & 0xff;
|
|
11
|
+
byteArray[index] = byte;
|
|
12
|
+
n = (n - byte) / 256;
|
|
13
|
+
}
|
|
14
|
+
return byteArray;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function unsafeFrom64bitLE(byteArray: Buffer): number {
|
|
18
|
+
let value = 0;
|
|
19
|
+
if (byteArray.length != 8) {
|
|
20
|
+
throw new Error('Expected Bufffer of lenght 8');
|
|
21
|
+
}
|
|
22
|
+
if (byteArray[7] != 0) {
|
|
23
|
+
throw new Error("Can't encode numbers > MAX_SAFE_INT");
|
|
24
|
+
}
|
|
25
|
+
if (byteArray[6] > 0x1f) {
|
|
26
|
+
throw new Error("Can't encode numbers > MAX_SAFE_INT");
|
|
27
|
+
}
|
|
28
|
+
for (let i = byteArray.length - 1; i >= 0; i--) {
|
|
29
|
+
value = value * 256 + byteArray[i];
|
|
30
|
+
}
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class BufferWriter {
|
|
35
|
+
private bufs: Buffer[] = [];
|
|
36
|
+
|
|
37
|
+
write(alloc: number, fn: (b: Buffer) => void): void {
|
|
38
|
+
const b = Buffer.alloc(alloc);
|
|
39
|
+
fn(b);
|
|
40
|
+
this.bufs.push(b);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
writeUInt8(i: number): void {
|
|
44
|
+
this.write(1, (b) => b.writeUInt8(i, 0));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
writeInt32(i: number): void {
|
|
48
|
+
this.write(4, (b) => b.writeInt32LE(i, 0));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
writeUInt32(i: number): void {
|
|
52
|
+
this.write(4, (b) => b.writeUInt32LE(i, 0));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
writeUInt64(i: number): void {
|
|
56
|
+
const bytes = unsafeTo64bitLE(i);
|
|
57
|
+
this.writeSlice(bytes);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
writeVarInt(i: number): void {
|
|
61
|
+
this.bufs.push(createVarint(i));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
writeSlice(slice: Buffer): void {
|
|
65
|
+
this.bufs.push(Buffer.from(slice));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
writeVarSlice(slice: Buffer): void {
|
|
69
|
+
this.writeVarInt(slice.length);
|
|
70
|
+
this.writeSlice(slice);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
buffer(): Buffer {
|
|
74
|
+
return Buffer.concat(this.bufs);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export class BufferReader {
|
|
79
|
+
constructor(public readonly buffer: Buffer, public offset: number = 0) {}
|
|
80
|
+
|
|
81
|
+
available(): number {
|
|
82
|
+
return this.buffer.length - this.offset;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
readUInt8(): number {
|
|
86
|
+
const result = this.buffer.readUInt8(this.offset);
|
|
87
|
+
this.offset++;
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
readInt32(): number {
|
|
92
|
+
const result = this.buffer.readInt32LE(this.offset);
|
|
93
|
+
this.offset += 4;
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
readUInt32(): number {
|
|
98
|
+
const result = this.buffer.readUInt32LE(this.offset);
|
|
99
|
+
this.offset += 4;
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
readUInt64(): number {
|
|
104
|
+
const buf = this.readSlice(8);
|
|
105
|
+
return unsafeFrom64bitLE(buf);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
readVarInt(): bigint {
|
|
109
|
+
const [vi, viSize] = parseVarint(this.buffer, this.offset);
|
|
110
|
+
this.offset += viSize;
|
|
111
|
+
return vi;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
readSlice(n: number): Buffer {
|
|
115
|
+
if (this.buffer.length < this.offset + n) {
|
|
116
|
+
throw new Error('Cannot read slice out of bounds');
|
|
117
|
+
}
|
|
118
|
+
const result = this.buffer.slice(this.offset, this.offset + n);
|
|
119
|
+
this.offset += n;
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
readVarSlice(): Buffer {
|
|
124
|
+
const n = sanitizeBigintToNumber(this.readVarInt());
|
|
125
|
+
return this.readSlice(n);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
readVector(): readonly Buffer[] {
|
|
129
|
+
const count = this.readVarInt();
|
|
130
|
+
const vector: Buffer[] = [];
|
|
131
|
+
for (let i = 0; i < count; i++) vector.push(this.readVarSlice());
|
|
132
|
+
return vector;
|
|
133
|
+
}
|
|
134
|
+
}
|