@ledgerhq/hw-app-btc 6.27.1 → 6.27.2-nightly.0
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 -0
- package/CHANGELOG.md +10 -0
- package/jest.config.ts +6 -0
- package/lib/bip32.d.ts.map +1 -1
- package/lib/bip32.js.map +1 -1
- package/lib/getTrustedInput.d.ts.map +1 -1
- package/lib/getTrustedInput.js.map +1 -1
- package/lib/newops/appClient.d.ts.map +1 -1
- package/lib/newops/appClient.js +1 -4
- package/lib/newops/appClient.js.map +1 -1
- package/lib/newops/psbtv2.d.ts.map +1 -1
- package/lib/newops/psbtv2.js.map +1 -1
- package/lib-es/bip32.d.ts.map +1 -1
- package/lib-es/bip32.js.map +1 -1
- package/lib-es/getTrustedInput.d.ts.map +1 -1
- package/lib-es/getTrustedInput.js.map +1 -1
- package/lib-es/newops/appClient.d.ts.map +1 -1
- package/lib-es/newops/appClient.js +1 -4
- package/lib-es/newops/appClient.js.map +1 -1
- package/lib-es/newops/psbtv2.d.ts.map +1 -1
- package/lib-es/newops/psbtv2.js.map +1 -1
- package/package.json +16 -7
- package/src/bip32.ts +5 -3
- package/src/getTrustedInput.ts +2 -8
- package/src/newops/appClient.ts +8 -4
- package/src/newops/psbtv2.ts +13 -9
- package/LICENSE +0 -202
- package/lib-es/Btc.js.flow +0 -280
- package/lib-es/bip32.js.flow +0 -13
- package/lib-es/compressPublicKey.js.flow +0 -8
- package/lib-es/constants.js.flow +0 -13
- package/lib-es/createTransaction.js.flow +0 -419
- package/lib-es/debug.js.flow +0 -41
- package/lib-es/finalizeInput.js.flow +0 -38
- package/lib-es/getAppAndVersion.js.flow +0 -19
- package/lib-es/getTrustedInput.js.flow +0 -163
- package/lib-es/getTrustedInputBIP143.js.flow +0 -37
- package/lib-es/getWalletPublicKey.js.flow +0 -51
- package/lib-es/hashPublicKey.js.flow +0 -8
- package/lib-es/serializeTransaction.js.flow +0 -77
- package/lib-es/shouldUseTrustedInputForSegwit.js.flow +0 -15
- package/lib-es/signMessage.js.flow +0 -67
- package/lib-es/signP2SHTransaction.js.flow +0 -170
- package/lib-es/signTransaction.js.flow +0 -40
- package/lib-es/splitTransaction.js.flow +0 -145
- package/lib-es/startUntrustedHashTransactionInput.js.flow +0 -136
- package/lib-es/types.js.flow +0 -31
- package/lib-es/varint.js.flow +0 -43
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
//@flow
|
|
2
|
-
|
|
3
|
-
import Transport from "@ledgerhq/hw-transport";
|
|
4
|
-
import shajs from "sha.js";
|
|
5
|
-
import type { Transaction } from "./types";
|
|
6
|
-
import { serializeTransaction } from "./serializeTransaction";
|
|
7
|
-
|
|
8
|
-
export function getTrustedInputBIP143(
|
|
9
|
-
transport: Transport<*>,
|
|
10
|
-
indexLookup: number,
|
|
11
|
-
transaction: Transaction,
|
|
12
|
-
additionals: Array<string> = []
|
|
13
|
-
) {
|
|
14
|
-
if (!transaction) {
|
|
15
|
-
throw new Error("getTrustedInputBIP143: missing tx");
|
|
16
|
-
}
|
|
17
|
-
const isDecred = additionals.includes("decred");
|
|
18
|
-
if (isDecred) {
|
|
19
|
-
throw new Error("Decred does not implement BIP143");
|
|
20
|
-
}
|
|
21
|
-
let hash = shajs("sha256")
|
|
22
|
-
.update(
|
|
23
|
-
shajs("sha256").update(serializeTransaction(transaction, true)).digest()
|
|
24
|
-
)
|
|
25
|
-
.digest();
|
|
26
|
-
const data = Buffer.alloc(4);
|
|
27
|
-
data.writeUInt32LE(indexLookup, 0);
|
|
28
|
-
const { outputs, locktime } = transaction;
|
|
29
|
-
if (!outputs || !locktime) {
|
|
30
|
-
throw new Error("getTrustedInputBIP143: locktime & outputs is expected");
|
|
31
|
-
}
|
|
32
|
-
if (!outputs[indexLookup]) {
|
|
33
|
-
throw new Error("getTrustedInputBIP143: wrong index");
|
|
34
|
-
}
|
|
35
|
-
hash = Buffer.concat([hash, data, outputs[indexLookup].amount]);
|
|
36
|
-
return hash.toString("hex");
|
|
37
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
import type Transport from "@ledgerhq/hw-transport";
|
|
3
|
-
import { bip32asBuffer } from "./bip32";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* address format is one of legacy | p2sh | bech32 | cashaddr
|
|
7
|
-
*/
|
|
8
|
-
export type AddressFormat = "legacy" | "p2sh" | "bech32" | "cashaddr";
|
|
9
|
-
|
|
10
|
-
const addressFormatMap = {
|
|
11
|
-
legacy: 0,
|
|
12
|
-
p2sh: 1,
|
|
13
|
-
bech32: 2,
|
|
14
|
-
cashaddr: 3,
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export async function getWalletPublicKey(
|
|
18
|
-
transport: Transport<*>,
|
|
19
|
-
options: { path: string, verify?: boolean, format?: AddressFormat }
|
|
20
|
-
): Promise<{
|
|
21
|
-
publicKey: string,
|
|
22
|
-
bitcoinAddress: string,
|
|
23
|
-
chainCode: string,
|
|
24
|
-
}> {
|
|
25
|
-
const { path, verify, format } = {
|
|
26
|
-
verify: false,
|
|
27
|
-
format: "legacy",
|
|
28
|
-
...options,
|
|
29
|
-
};
|
|
30
|
-
if (!(format in addressFormatMap)) {
|
|
31
|
-
throw new Error("btc.getWalletPublicKey invalid format=" + format);
|
|
32
|
-
}
|
|
33
|
-
const buffer = bip32asBuffer(path);
|
|
34
|
-
var p1 = verify ? 1 : 0;
|
|
35
|
-
var p2 = addressFormatMap[format];
|
|
36
|
-
const response = await transport.send(0xe0, 0x40, p1, p2, buffer);
|
|
37
|
-
|
|
38
|
-
const publicKeyLength = response[0];
|
|
39
|
-
const addressLength = response[1 + publicKeyLength];
|
|
40
|
-
const publicKey = response.slice(1, 1 + publicKeyLength).toString("hex");
|
|
41
|
-
const bitcoinAddress = response
|
|
42
|
-
.slice(1 + publicKeyLength + 1, 1 + publicKeyLength + 1 + addressLength)
|
|
43
|
-
.toString("ascii");
|
|
44
|
-
const chainCode = response
|
|
45
|
-
.slice(
|
|
46
|
-
1 + publicKeyLength + 1 + addressLength,
|
|
47
|
-
1 + publicKeyLength + 1 + addressLength + 32
|
|
48
|
-
)
|
|
49
|
-
.toString("hex");
|
|
50
|
-
return { publicKey, bitcoinAddress, chainCode };
|
|
51
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
import type { Transaction } from "./types";
|
|
3
|
-
import { createVarint } from "./varint";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
@example
|
|
7
|
-
const tx1 = btc.splitTransaction("01000000014ea60aeac5252c14291d428915bd7ccd1bfc4af009f4d4dc57ae597ed0420b71010000008a47304402201f36a12c240dbf9e566bc04321050b1984cd6eaf6caee8f02bb0bfec08e3354b022012ee2aeadcbbfd1e92959f57c15c1c6debb757b798451b104665aa3010569b49014104090b15bde569386734abf2a2b99f9ca6a50656627e77de663ca7325702769986cf26cc9dd7fdea0af432c8e2becc867c932e1b9dd742f2a108997c2252e2bdebffffffff0281b72e00000000001976a91472a5d75c8d2d0565b656a5232703b167d50d5a2b88aca0860100000000001976a9144533f5fb9b4817f713c48f0bfe96b9f50c476c9b88ac00000000");
|
|
8
|
-
const outputScript = btc.serializeTransactionOutputs(tx1).toString('hex');
|
|
9
|
-
*/
|
|
10
|
-
export function serializeTransactionOutputs({ outputs }: Transaction): Buffer {
|
|
11
|
-
let outputBuffer = Buffer.alloc(0);
|
|
12
|
-
if (typeof outputs !== "undefined") {
|
|
13
|
-
outputBuffer = Buffer.concat([outputBuffer, createVarint(outputs.length)]);
|
|
14
|
-
outputs.forEach((output) => {
|
|
15
|
-
outputBuffer = Buffer.concat([
|
|
16
|
-
outputBuffer,
|
|
17
|
-
output.amount,
|
|
18
|
-
createVarint(output.script.length),
|
|
19
|
-
output.script,
|
|
20
|
-
]);
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
return outputBuffer;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function serializeTransaction(
|
|
27
|
-
transaction: Transaction,
|
|
28
|
-
skipWitness: boolean,
|
|
29
|
-
timestamp?: Buffer,
|
|
30
|
-
additionals: string[] = []
|
|
31
|
-
) {
|
|
32
|
-
const isDecred = additionals.includes("decred");
|
|
33
|
-
const isBech32 = additionals.includes("bech32");
|
|
34
|
-
let inputBuffer = Buffer.alloc(0);
|
|
35
|
-
let useWitness = typeof transaction["witness"] != "undefined" && !skipWitness;
|
|
36
|
-
transaction.inputs.forEach((input) => {
|
|
37
|
-
inputBuffer =
|
|
38
|
-
isDecred || isBech32
|
|
39
|
-
? Buffer.concat([
|
|
40
|
-
inputBuffer,
|
|
41
|
-
input.prevout,
|
|
42
|
-
Buffer.from([0x00]), //tree
|
|
43
|
-
input.sequence,
|
|
44
|
-
])
|
|
45
|
-
: Buffer.concat([
|
|
46
|
-
inputBuffer,
|
|
47
|
-
input.prevout,
|
|
48
|
-
createVarint(input.script.length),
|
|
49
|
-
input.script,
|
|
50
|
-
input.sequence,
|
|
51
|
-
]);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
let outputBuffer = serializeTransactionOutputs(transaction);
|
|
55
|
-
if (
|
|
56
|
-
typeof transaction.outputs !== "undefined" &&
|
|
57
|
-
typeof transaction.locktime !== "undefined"
|
|
58
|
-
) {
|
|
59
|
-
outputBuffer = Buffer.concat([
|
|
60
|
-
outputBuffer,
|
|
61
|
-
(useWitness && transaction.witness) || Buffer.alloc(0),
|
|
62
|
-
transaction.locktime,
|
|
63
|
-
transaction.nExpiryHeight || Buffer.alloc(0),
|
|
64
|
-
transaction.extraData || Buffer.alloc(0),
|
|
65
|
-
]);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return Buffer.concat([
|
|
69
|
-
transaction.version,
|
|
70
|
-
timestamp ? timestamp : Buffer.alloc(0),
|
|
71
|
-
transaction.nVersionGroupId || Buffer.alloc(0),
|
|
72
|
-
useWitness ? Buffer.from("0001", "hex") : Buffer.alloc(0),
|
|
73
|
-
createVarint(transaction.inputs.length),
|
|
74
|
-
inputBuffer,
|
|
75
|
-
outputBuffer,
|
|
76
|
-
]);
|
|
77
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
|
|
3
|
-
import semver from "semver";
|
|
4
|
-
|
|
5
|
-
export function shouldUseTrustedInputForSegwit({
|
|
6
|
-
version,
|
|
7
|
-
name,
|
|
8
|
-
}: {
|
|
9
|
-
version: string,
|
|
10
|
-
name: string,
|
|
11
|
-
}) {
|
|
12
|
-
if (name === "Decred") return false;
|
|
13
|
-
if (name === "Exchange") return true;
|
|
14
|
-
return semver.gte(version, "1.4.0");
|
|
15
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
import type Transport from "@ledgerhq/hw-transport";
|
|
3
|
-
import bippath from "bip32-path";
|
|
4
|
-
import { MAX_SCRIPT_BLOCK } from "./constants";
|
|
5
|
-
|
|
6
|
-
export async function signMessage(
|
|
7
|
-
transport: Transport<*>,
|
|
8
|
-
{ path, messageHex }: { path: string, messageHex: string }
|
|
9
|
-
): Promise<{
|
|
10
|
-
v: number,
|
|
11
|
-
r: string,
|
|
12
|
-
s: string,
|
|
13
|
-
}> {
|
|
14
|
-
const paths = bippath.fromString(path).toPathArray();
|
|
15
|
-
const message = Buffer.from(messageHex, "hex");
|
|
16
|
-
|
|
17
|
-
let offset = 0;
|
|
18
|
-
while (offset !== message.length) {
|
|
19
|
-
let maxChunkSize =
|
|
20
|
-
offset === 0
|
|
21
|
-
? MAX_SCRIPT_BLOCK - 1 - paths.length * 4 - 4
|
|
22
|
-
: MAX_SCRIPT_BLOCK;
|
|
23
|
-
let chunkSize =
|
|
24
|
-
offset + maxChunkSize > message.length
|
|
25
|
-
? message.length - offset
|
|
26
|
-
: maxChunkSize;
|
|
27
|
-
const buffer = Buffer.alloc(
|
|
28
|
-
offset === 0 ? 1 + paths.length * 4 + 2 + chunkSize : chunkSize
|
|
29
|
-
);
|
|
30
|
-
if (offset === 0) {
|
|
31
|
-
buffer[0] = paths.length;
|
|
32
|
-
paths.forEach((element, index) => {
|
|
33
|
-
buffer.writeUInt32BE(element, 1 + 4 * index);
|
|
34
|
-
});
|
|
35
|
-
buffer.writeUInt16BE(message.length, 1 + 4 * paths.length);
|
|
36
|
-
message.copy(
|
|
37
|
-
buffer,
|
|
38
|
-
1 + 4 * paths.length + 2,
|
|
39
|
-
offset,
|
|
40
|
-
offset + chunkSize
|
|
41
|
-
);
|
|
42
|
-
} else {
|
|
43
|
-
message.copy(buffer, 0, offset, offset + chunkSize);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
await transport.send(0xe0, 0x4e, 0x00, offset === 0 ? 0x01 : 0x80, buffer);
|
|
47
|
-
|
|
48
|
-
offset += chunkSize;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const res = await transport.send(0xe0, 0x4e, 0x80, 0x00, Buffer.from([0x00]));
|
|
52
|
-
|
|
53
|
-
const v = res[0] - 0x30;
|
|
54
|
-
let r = res.slice(4, 4 + res[3]);
|
|
55
|
-
if (r[0] === 0) {
|
|
56
|
-
r = r.slice(1);
|
|
57
|
-
}
|
|
58
|
-
r = r.toString("hex");
|
|
59
|
-
offset = 4 + res[3] + 2;
|
|
60
|
-
let s = res.slice(offset, offset + res[offset - 1]);
|
|
61
|
-
if (s[0] === 0) {
|
|
62
|
-
s = s.slice(1);
|
|
63
|
-
}
|
|
64
|
-
s = s.toString("hex");
|
|
65
|
-
|
|
66
|
-
return { v, r, s };
|
|
67
|
-
}
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
//@flow
|
|
2
|
-
import type Transport from "@ledgerhq/hw-transport";
|
|
3
|
-
import { getTrustedInput } from "./getTrustedInput";
|
|
4
|
-
import { startUntrustedHashTransactionInput } from "./startUntrustedHashTransactionInput";
|
|
5
|
-
import { getTrustedInputBIP143 } from "./getTrustedInputBIP143";
|
|
6
|
-
import { signTransaction } from "./signTransaction";
|
|
7
|
-
import { hashOutputFull } from "./finalizeInput";
|
|
8
|
-
import type { TransactionOutput, Transaction } from "./types";
|
|
9
|
-
import {
|
|
10
|
-
DEFAULT_LOCKTIME,
|
|
11
|
-
DEFAULT_VERSION,
|
|
12
|
-
DEFAULT_SEQUENCE,
|
|
13
|
-
SIGHASH_ALL,
|
|
14
|
-
} from "./constants";
|
|
15
|
-
|
|
16
|
-
const defaultArg = {
|
|
17
|
-
lockTime: DEFAULT_LOCKTIME,
|
|
18
|
-
sigHashType: SIGHASH_ALL,
|
|
19
|
-
segwit: false,
|
|
20
|
-
transactionVersion: DEFAULT_VERSION,
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
*
|
|
25
|
-
*/
|
|
26
|
-
export type SignP2SHTransactionArg = {
|
|
27
|
-
inputs: Array<[Transaction, number, ?string, ?number]>,
|
|
28
|
-
associatedKeysets: string[],
|
|
29
|
-
outputScriptHex: string,
|
|
30
|
-
lockTime?: number,
|
|
31
|
-
sigHashType?: number,
|
|
32
|
-
segwit?: boolean,
|
|
33
|
-
transactionVersion?: number,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export async function signP2SHTransaction(
|
|
37
|
-
transport: Transport<*>,
|
|
38
|
-
arg: SignP2SHTransactionArg
|
|
39
|
-
) {
|
|
40
|
-
const {
|
|
41
|
-
inputs,
|
|
42
|
-
associatedKeysets,
|
|
43
|
-
outputScriptHex,
|
|
44
|
-
lockTime,
|
|
45
|
-
sigHashType,
|
|
46
|
-
segwit,
|
|
47
|
-
transactionVersion,
|
|
48
|
-
} = { ...defaultArg, ...arg };
|
|
49
|
-
// Inputs are provided as arrays of [transaction, output_index, redeem script, optional sequence]
|
|
50
|
-
// associatedKeysets are provided as arrays of [path]
|
|
51
|
-
const nullScript = Buffer.alloc(0);
|
|
52
|
-
const nullPrevout = Buffer.alloc(0);
|
|
53
|
-
const defaultVersion = Buffer.alloc(4);
|
|
54
|
-
defaultVersion.writeUInt32LE(transactionVersion, 0);
|
|
55
|
-
const trustedInputs = [];
|
|
56
|
-
const regularOutputs: Array<TransactionOutput> = [];
|
|
57
|
-
const signatures = [];
|
|
58
|
-
let firstRun = true;
|
|
59
|
-
const resuming = false;
|
|
60
|
-
let targetTransaction: Transaction = {
|
|
61
|
-
inputs: [],
|
|
62
|
-
version: defaultVersion,
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const getTrustedInputCall = segwit ? getTrustedInputBIP143 : getTrustedInput;
|
|
66
|
-
const outputScript = Buffer.from(outputScriptHex, "hex");
|
|
67
|
-
|
|
68
|
-
for (let input of inputs) {
|
|
69
|
-
if (!resuming) {
|
|
70
|
-
const trustedInput = await getTrustedInputCall(
|
|
71
|
-
transport,
|
|
72
|
-
input[1],
|
|
73
|
-
input[0]
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
let sequence = Buffer.alloc(4);
|
|
77
|
-
sequence.writeUInt32LE(
|
|
78
|
-
input.length >= 4 && typeof input[3] === "number"
|
|
79
|
-
? input[3]
|
|
80
|
-
: DEFAULT_SEQUENCE,
|
|
81
|
-
0
|
|
82
|
-
);
|
|
83
|
-
trustedInputs.push({
|
|
84
|
-
trustedInput: false,
|
|
85
|
-
value: segwit
|
|
86
|
-
? Buffer.from(trustedInput, "hex")
|
|
87
|
-
: Buffer.from(trustedInput, "hex").slice(4, 4 + 0x24),
|
|
88
|
-
sequence,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const { outputs } = input[0];
|
|
93
|
-
const index = input[1];
|
|
94
|
-
if (outputs && index <= outputs.length - 1) {
|
|
95
|
-
regularOutputs.push(outputs[index]);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Pre-build the target transaction
|
|
100
|
-
for (let i = 0; i < inputs.length; i++) {
|
|
101
|
-
let sequence = Buffer.alloc(4);
|
|
102
|
-
sequence.writeUInt32LE(
|
|
103
|
-
inputs[i].length >= 4 && typeof inputs[i][3] === "number"
|
|
104
|
-
? inputs[i][3]
|
|
105
|
-
: DEFAULT_SEQUENCE,
|
|
106
|
-
0
|
|
107
|
-
);
|
|
108
|
-
targetTransaction.inputs.push({
|
|
109
|
-
script: nullScript,
|
|
110
|
-
prevout: nullPrevout,
|
|
111
|
-
sequence,
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (segwit) {
|
|
116
|
-
await startUntrustedHashTransactionInput(
|
|
117
|
-
transport,
|
|
118
|
-
true,
|
|
119
|
-
targetTransaction,
|
|
120
|
-
trustedInputs,
|
|
121
|
-
true
|
|
122
|
-
);
|
|
123
|
-
await hashOutputFull(transport, outputScript);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
for (let i = 0; i < inputs.length; i++) {
|
|
127
|
-
const input = inputs[i];
|
|
128
|
-
let script =
|
|
129
|
-
inputs[i].length >= 3 && typeof input[2] === "string"
|
|
130
|
-
? Buffer.from(input[2], "hex")
|
|
131
|
-
: regularOutputs[i].script;
|
|
132
|
-
let pseudoTX = Object.assign({}, targetTransaction);
|
|
133
|
-
let pseudoTrustedInputs = segwit ? [trustedInputs[i]] : trustedInputs;
|
|
134
|
-
if (segwit) {
|
|
135
|
-
pseudoTX.inputs = [{ ...pseudoTX.inputs[i], script }];
|
|
136
|
-
} else {
|
|
137
|
-
pseudoTX.inputs[i].script = script;
|
|
138
|
-
}
|
|
139
|
-
await startUntrustedHashTransactionInput(
|
|
140
|
-
transport,
|
|
141
|
-
!segwit && firstRun,
|
|
142
|
-
pseudoTX,
|
|
143
|
-
pseudoTrustedInputs,
|
|
144
|
-
segwit
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
if (!segwit) {
|
|
148
|
-
await hashOutputFull(transport, outputScript);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const signature = await signTransaction(
|
|
152
|
-
transport,
|
|
153
|
-
associatedKeysets[i],
|
|
154
|
-
lockTime,
|
|
155
|
-
sigHashType
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
signatures.push(
|
|
159
|
-
segwit
|
|
160
|
-
? signature.toString("hex")
|
|
161
|
-
: signature.slice(0, signature.length - 1).toString("hex")
|
|
162
|
-
);
|
|
163
|
-
targetTransaction.inputs[i].script = nullScript;
|
|
164
|
-
if (firstRun) {
|
|
165
|
-
firstRun = false;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return signatures;
|
|
170
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
import type Transport from "@ledgerhq/hw-transport";
|
|
3
|
-
import { bip32asBuffer } from "./bip32";
|
|
4
|
-
|
|
5
|
-
export function signTransaction(
|
|
6
|
-
transport: Transport<*>,
|
|
7
|
-
path: string,
|
|
8
|
-
lockTime: number,
|
|
9
|
-
sigHashType: number,
|
|
10
|
-
expiryHeight?: Buffer,
|
|
11
|
-
additionals: Array<string> = []
|
|
12
|
-
): Promise<Buffer> {
|
|
13
|
-
const isDecred = additionals.includes("decred");
|
|
14
|
-
const pathsBuffer = bip32asBuffer(path);
|
|
15
|
-
const lockTimeBuffer = Buffer.alloc(4);
|
|
16
|
-
lockTimeBuffer.writeUInt32BE(lockTime, 0);
|
|
17
|
-
let buffer = isDecred
|
|
18
|
-
? Buffer.concat([
|
|
19
|
-
pathsBuffer,
|
|
20
|
-
lockTimeBuffer,
|
|
21
|
-
expiryHeight || Buffer.from([0x00, 0x00, 0x00, 0x00]),
|
|
22
|
-
Buffer.from([sigHashType]),
|
|
23
|
-
])
|
|
24
|
-
: Buffer.concat([
|
|
25
|
-
pathsBuffer,
|
|
26
|
-
Buffer.from([0x00]),
|
|
27
|
-
lockTimeBuffer,
|
|
28
|
-
Buffer.from([sigHashType]),
|
|
29
|
-
]);
|
|
30
|
-
if (expiryHeight && !isDecred) {
|
|
31
|
-
buffer = Buffer.concat([buffer, expiryHeight]);
|
|
32
|
-
}
|
|
33
|
-
return transport.send(0xe0, 0x48, 0x00, 0x00, buffer).then((result) => {
|
|
34
|
-
if (result.length > 0) {
|
|
35
|
-
result[0] = 0x30;
|
|
36
|
-
return result.slice(0, result.length - 2);
|
|
37
|
-
}
|
|
38
|
-
return result;
|
|
39
|
-
});
|
|
40
|
-
}
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
import { log } from "@ledgerhq/logs";
|
|
3
|
-
import type { Transaction } from "./types";
|
|
4
|
-
import { getVarint } from "./varint";
|
|
5
|
-
import { formatTransactionDebug } from "./debug";
|
|
6
|
-
|
|
7
|
-
export function splitTransaction(
|
|
8
|
-
transactionHex: string,
|
|
9
|
-
isSegwitSupported: ?boolean = false,
|
|
10
|
-
hasTimestamp?: boolean = false,
|
|
11
|
-
hasExtraData?: boolean = false,
|
|
12
|
-
additionals: Array<string> = []
|
|
13
|
-
): Transaction {
|
|
14
|
-
const inputs = [];
|
|
15
|
-
const outputs = [];
|
|
16
|
-
var witness = false;
|
|
17
|
-
let offset = 0;
|
|
18
|
-
let timestamp = Buffer.alloc(0);
|
|
19
|
-
let nExpiryHeight = Buffer.alloc(0);
|
|
20
|
-
let nVersionGroupId = Buffer.alloc(0);
|
|
21
|
-
let extraData = Buffer.alloc(0);
|
|
22
|
-
const isDecred = additionals.includes("decred");
|
|
23
|
-
const transaction = Buffer.from(transactionHex, "hex");
|
|
24
|
-
const version = transaction.slice(offset, offset + 4);
|
|
25
|
-
const overwinter =
|
|
26
|
-
version.equals(Buffer.from([0x03, 0x00, 0x00, 0x80])) ||
|
|
27
|
-
version.equals(Buffer.from([0x04, 0x00, 0x00, 0x80]));
|
|
28
|
-
offset += 4;
|
|
29
|
-
if (
|
|
30
|
-
!hasTimestamp &&
|
|
31
|
-
isSegwitSupported &&
|
|
32
|
-
transaction[offset] === 0 &&
|
|
33
|
-
transaction[offset + 1] !== 0
|
|
34
|
-
) {
|
|
35
|
-
offset += 2;
|
|
36
|
-
witness = true;
|
|
37
|
-
}
|
|
38
|
-
if (hasTimestamp) {
|
|
39
|
-
timestamp = transaction.slice(offset, 4 + offset);
|
|
40
|
-
offset += 4;
|
|
41
|
-
}
|
|
42
|
-
if (overwinter) {
|
|
43
|
-
nVersionGroupId = transaction.slice(offset, 4 + offset);
|
|
44
|
-
offset += 4;
|
|
45
|
-
}
|
|
46
|
-
let varint = getVarint(transaction, offset);
|
|
47
|
-
const numberInputs = varint[0];
|
|
48
|
-
offset += varint[1];
|
|
49
|
-
for (let i = 0; i < numberInputs; i++) {
|
|
50
|
-
const prevout = transaction.slice(offset, offset + 36);
|
|
51
|
-
offset += 36;
|
|
52
|
-
let script = Buffer.alloc(0);
|
|
53
|
-
let tree = Buffer.alloc(0);
|
|
54
|
-
//No script for decred, it has a witness
|
|
55
|
-
if (!isDecred) {
|
|
56
|
-
varint = getVarint(transaction, offset);
|
|
57
|
-
offset += varint[1];
|
|
58
|
-
script = transaction.slice(offset, offset + varint[0]);
|
|
59
|
-
offset += varint[0];
|
|
60
|
-
} else {
|
|
61
|
-
//Tree field
|
|
62
|
-
tree = transaction.slice(offset, offset + 1);
|
|
63
|
-
offset += 1;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const sequence = transaction.slice(offset, offset + 4);
|
|
67
|
-
offset += 4;
|
|
68
|
-
inputs.push({ prevout, script, sequence, tree });
|
|
69
|
-
}
|
|
70
|
-
varint = getVarint(transaction, offset);
|
|
71
|
-
const numberOutputs = varint[0];
|
|
72
|
-
offset += varint[1];
|
|
73
|
-
for (let i = 0; i < numberOutputs; i++) {
|
|
74
|
-
const amount = transaction.slice(offset, offset + 8);
|
|
75
|
-
offset += 8;
|
|
76
|
-
|
|
77
|
-
if (isDecred) {
|
|
78
|
-
//Script version
|
|
79
|
-
offset += 2;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
varint = getVarint(transaction, offset);
|
|
83
|
-
offset += varint[1];
|
|
84
|
-
const script = transaction.slice(offset, offset + varint[0]);
|
|
85
|
-
offset += varint[0];
|
|
86
|
-
outputs.push({ amount, script });
|
|
87
|
-
}
|
|
88
|
-
let witnessScript, locktime;
|
|
89
|
-
if (witness) {
|
|
90
|
-
witnessScript = transaction.slice(offset, -4);
|
|
91
|
-
locktime = transaction.slice(transaction.length - 4);
|
|
92
|
-
} else {
|
|
93
|
-
locktime = transaction.slice(offset, offset + 4);
|
|
94
|
-
}
|
|
95
|
-
offset += 4;
|
|
96
|
-
if (overwinter || isDecred) {
|
|
97
|
-
nExpiryHeight = transaction.slice(offset, offset + 4);
|
|
98
|
-
offset += 4;
|
|
99
|
-
}
|
|
100
|
-
if (hasExtraData) {
|
|
101
|
-
extraData = transaction.slice(offset);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
//Get witnesses for Decred
|
|
105
|
-
if (isDecred) {
|
|
106
|
-
varint = getVarint(transaction, offset);
|
|
107
|
-
offset += varint[1];
|
|
108
|
-
if (varint[0] !== numberInputs) {
|
|
109
|
-
throw new Error("splitTransaction: incoherent number of witnesses");
|
|
110
|
-
}
|
|
111
|
-
for (let i = 0; i < numberInputs; i++) {
|
|
112
|
-
//amount
|
|
113
|
-
offset += 8;
|
|
114
|
-
//block height
|
|
115
|
-
offset += 4;
|
|
116
|
-
//block index
|
|
117
|
-
offset += 4;
|
|
118
|
-
//Script size
|
|
119
|
-
varint = getVarint(transaction, offset);
|
|
120
|
-
offset += varint[1];
|
|
121
|
-
const script = transaction.slice(offset, offset + varint[0]);
|
|
122
|
-
offset += varint[0];
|
|
123
|
-
inputs[i].script = script;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const t: Transaction = {
|
|
128
|
-
version,
|
|
129
|
-
inputs,
|
|
130
|
-
outputs,
|
|
131
|
-
locktime,
|
|
132
|
-
witness: witnessScript,
|
|
133
|
-
timestamp,
|
|
134
|
-
nVersionGroupId,
|
|
135
|
-
nExpiryHeight,
|
|
136
|
-
extraData,
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
log(
|
|
140
|
-
"btc",
|
|
141
|
-
`splitTransaction ${transactionHex}:\n${formatTransactionDebug(t)}`
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
return t;
|
|
145
|
-
}
|