@swapkit/wallet-hardware 5.0.1 → 6.0.1
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/THIRD_PARTY_LICENSES.md +2344 -0
- package/dist/chunk-09e51wma.js +4 -0
- package/dist/chunk-09e51wma.js.map +167 -0
- package/dist/chunk-0arpsm5f.js +4 -0
- package/dist/chunk-0arpsm5f.js.map +10 -0
- package/dist/chunk-1amf58aq.js +4 -0
- package/dist/{chunk-xkh15edk.js.map → chunk-1amf58aq.js.map} +2 -2
- package/dist/chunk-3t17wpjg.js +17 -0
- package/dist/chunk-3t17wpjg.js.map +29 -0
- package/dist/chunk-5c7b7z2d.js +4 -0
- package/dist/{chunk-20wx60bn.js.map → chunk-5c7b7z2d.js.map} +2 -2
- package/dist/chunk-5p3ttw6y.js +4 -0
- package/dist/{chunk-1jpcb30j.js.map → chunk-5p3ttw6y.js.map} +1 -1
- package/dist/chunk-dptbnkzm.js +64 -0
- package/dist/chunk-dptbnkzm.js.map +260 -0
- package/dist/chunk-ds2m83jp.js +5 -0
- package/dist/chunk-ds2m83jp.js.map +11 -0
- package/dist/chunk-eenx3cv6.js +4 -0
- package/dist/chunk-eenx3cv6.js.map +33 -0
- package/dist/chunk-gr3eswf1.js +4 -0
- package/dist/chunk-gr3eswf1.js.map +73 -0
- package/dist/{chunk-7fsaymh4.js → chunk-hg71hp4m.js} +3 -3
- package/dist/{chunk-7fsaymh4.js.map → chunk-hg71hp4m.js.map} +1 -1
- package/dist/chunk-jewm2ag3.js +5 -0
- package/dist/{chunk-4tbtxdxa.js.map → chunk-jewm2ag3.js.map} +2 -2
- package/dist/chunk-jzrytcrf.js +4 -0
- package/dist/chunk-jzrytcrf.js.map +12 -0
- package/dist/chunk-k3thje6a.js +4 -0
- package/dist/chunk-k3thje6a.js.map +9 -0
- package/dist/chunk-nhva847d.js +5 -0
- package/dist/chunk-nhva847d.js.map +9 -0
- package/dist/chunk-tm47brht.js +4 -0
- package/dist/chunk-tm47brht.js.map +140 -0
- package/dist/chunk-xmvg4cds.js +4 -0
- package/dist/chunk-xmvg4cds.js.map +127 -0
- package/dist/chunk-xx7cwpzq.js +4 -0
- package/dist/chunk-xx7cwpzq.js.map +9 -0
- package/dist/chunk-yrxe491r.js +20 -0
- package/dist/chunk-yrxe491r.js.map +17 -0
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/keepkey/index.cjs +2 -2
- package/dist/keepkey/index.cjs.map +2 -2
- package/dist/keepkey/index.js +2 -2
- package/dist/keepkey/index.js.map +2 -2
- package/dist/ledger/index.cjs +90 -2
- package/dist/ledger/index.cjs.map +830 -24
- package/dist/ledger/index.js +2 -2
- package/dist/ledger/index.js.map +21 -19
- package/dist/trezor/index.cjs +2 -2
- package/dist/trezor/index.cjs.map +5 -5
- package/dist/trezor/index.js +2 -2
- package/dist/trezor/index.js.map +3 -3
- package/dist/types/ledger/clients/bitcoin.d.ts +36 -0
- package/dist/types/ledger/clients/bitcoin.d.ts.map +1 -0
- package/dist/types/ledger/clients/cosmos.d.ts +38 -10
- package/dist/types/ledger/clients/cosmos.d.ts.map +1 -1
- package/dist/types/ledger/clients/evm.d.ts +37 -46
- package/dist/types/ledger/clients/evm.d.ts.map +1 -1
- package/dist/types/ledger/clients/near.d.ts +5 -2
- package/dist/types/ledger/clients/near.d.ts.map +1 -1
- package/dist/types/ledger/clients/sui.d.ts +8 -12
- package/dist/types/ledger/clients/sui.d.ts.map +1 -1
- package/dist/types/ledger/clients/thorchain/index.d.ts +34 -8
- package/dist/types/ledger/clients/thorchain/index.d.ts.map +1 -1
- package/dist/types/ledger/clients/thorchain/protocol.d.ts +58 -0
- package/dist/types/ledger/clients/thorchain/protocol.d.ts.map +1 -0
- package/dist/types/ledger/clients/tron.d.ts +11 -8
- package/dist/types/ledger/clients/tron.d.ts.map +1 -1
- package/dist/types/ledger/clients/utxo-legacy-adapter.d.ts +3 -2
- package/dist/types/ledger/clients/utxo-legacy-adapter.d.ts.map +1 -1
- package/dist/types/ledger/clients/utxo-legacy-outputs.d.ts +18 -0
- package/dist/types/ledger/clients/utxo-legacy-outputs.d.ts.map +1 -0
- package/dist/types/ledger/clients/utxo.d.ts +10 -13
- package/dist/types/ledger/clients/utxo.d.ts.map +1 -1
- package/dist/types/ledger/clients/xrp.d.ts +4 -1
- package/dist/types/ledger/clients/xrp.d.ts.map +1 -1
- package/dist/types/ledger/clients/zcash.d.ts +53 -0
- package/dist/types/ledger/clients/zcash.d.ts.map +1 -0
- package/dist/types/ledger/helpers/dmk.d.ts +24 -0
- package/dist/types/ledger/helpers/dmk.d.ts.map +1 -0
- package/dist/types/ledger/helpers/executeDeviceAction.d.ts +34 -0
- package/dist/types/ledger/helpers/executeDeviceAction.d.ts.map +1 -0
- package/dist/types/ledger/helpers/getLedgerAddress.d.ts +1 -1
- package/dist/types/ledger/helpers/getLedgerAddress.d.ts.map +1 -1
- package/dist/types/ledger/helpers/getLedgerClient.d.ts +10 -3
- package/dist/types/ledger/helpers/getLedgerClient.d.ts.map +1 -1
- package/dist/types/ledger/helpers/index.d.ts +2 -1
- package/dist/types/ledger/helpers/index.d.ts.map +1 -1
- package/dist/types/ledger/helpers/ledgerJsDmkBridge.d.ts +26 -0
- package/dist/types/ledger/helpers/ledgerJsDmkBridge.d.ts.map +1 -0
- package/dist/types/ledger/helpers/ledgerJsDmkTransport.d.ts +13 -0
- package/dist/types/ledger/helpers/ledgerJsDmkTransport.d.ts.map +1 -0
- package/dist/types/ledger/helpers/lowS.d.ts +6 -0
- package/dist/types/ledger/helpers/lowS.d.ts.map +1 -0
- package/dist/types/ledger/helpers/rawTx.d.ts +2 -0
- package/dist/types/ledger/helpers/rawTx.d.ts.map +1 -0
- package/dist/types/ledger/index.d.ts +19 -7
- package/dist/types/ledger/index.d.ts.map +1 -1
- package/dist/types/ledger/types.d.ts +6 -10
- package/dist/types/ledger/types.d.ts.map +1 -1
- package/dist/types/trezor/index.d.ts +2 -2
- package/dist/types/trezor/index.d.ts.map +1 -1
- package/package.json +36 -36
- package/src/ledger/clients/bitcoin.ts +575 -0
- package/src/ledger/clients/cosmos.ts +180 -51
- package/src/ledger/clients/evm.ts +238 -195
- package/src/ledger/clients/near.ts +43 -13
- package/src/ledger/clients/sui.ts +55 -68
- package/src/ledger/clients/thorchain/index.ts +210 -86
- package/src/ledger/clients/thorchain/protocol.ts +166 -0
- package/src/ledger/clients/tron.ts +49 -37
- package/src/ledger/clients/utxo-legacy-adapter.ts +35 -32
- package/src/ledger/clients/utxo-legacy-outputs.ts +122 -0
- package/src/ledger/clients/utxo.ts +108 -206
- package/src/ledger/clients/xrp.ts +39 -23
- package/src/ledger/clients/zcash.ts +440 -0
- package/src/ledger/helpers/dmk.ts +231 -0
- package/src/ledger/helpers/executeDeviceAction.ts +201 -0
- package/src/ledger/helpers/getLedgerClient.ts +101 -72
- package/src/ledger/helpers/index.ts +6 -1
- package/src/ledger/helpers/ledgerJsDmkBridge.ts +109 -0
- package/src/ledger/helpers/ledgerJsDmkTransport.ts +88 -0
- package/src/ledger/helpers/lowS.ts +30 -0
- package/src/ledger/helpers/rawTx.ts +12 -0
- package/src/ledger/index.ts +564 -369
- package/src/ledger/types.ts +15 -10
- package/src/trezor/index.ts +183 -68
- package/dist/chunk-1jpcb30j.js +0 -5
- package/dist/chunk-20wx60bn.js +0 -4
- package/dist/chunk-4tbtxdxa.js +0 -5
- package/dist/chunk-7v7cgm69.js +0 -4
- package/dist/chunk-7v7cgm69.js.map +0 -10
- package/dist/chunk-83g13ck6.js +0 -5
- package/dist/chunk-83g13ck6.js.map +0 -10
- package/dist/chunk-h2r568rz.js +0 -4
- package/dist/chunk-h2r568rz.js.map +0 -10
- package/dist/chunk-xkh15edk.js +0 -4
- package/dist/types/ledger/clients/thorchain/common.d.ts +0 -28
- package/dist/types/ledger/clients/thorchain/common.d.ts.map +0 -1
- package/dist/types/ledger/clients/thorchain/helpers.d.ts +0 -7
- package/dist/types/ledger/clients/thorchain/helpers.d.ts.map +0 -1
- package/dist/types/ledger/clients/thorchain/lib.d.ts +0 -22
- package/dist/types/ledger/clients/thorchain/lib.d.ts.map +0 -1
- package/dist/types/ledger/clients/thorchain/utils.d.ts +0 -2
- package/dist/types/ledger/clients/thorchain/utils.d.ts.map +0 -1
- package/dist/types/ledger/clients/utxo-psbt.d.ts +0 -18
- package/dist/types/ledger/clients/utxo-psbt.d.ts.map +0 -1
- package/dist/types/ledger/cosmosTypes.d.ts +0 -40
- package/dist/types/ledger/cosmosTypes.d.ts.map +0 -1
- package/dist/types/ledger/helpers/getLedgerTransport.d.ts +0 -3
- package/dist/types/ledger/helpers/getLedgerTransport.d.ts.map +0 -1
- package/dist/types/ledger/helpers/ledgerNetworkInfo.d.ts +0 -14
- package/dist/types/ledger/helpers/ledgerNetworkInfo.d.ts.map +0 -1
- package/dist/types/ledger/interfaces/CosmosLedgerInterface.d.ts +0 -14
- package/dist/types/ledger/interfaces/CosmosLedgerInterface.d.ts.map +0 -1
- package/src/ledger/clients/thorchain/common.ts +0 -93
- package/src/ledger/clients/thorchain/helpers.ts +0 -120
- package/src/ledger/clients/thorchain/lib.ts +0 -258
- package/src/ledger/clients/thorchain/utils.ts +0 -69
- package/src/ledger/clients/utxo-psbt.ts +0 -204
- package/src/ledger/cosmosTypes.ts +0 -98
- package/src/ledger/helpers/getLedgerTransport.ts +0 -102
- package/src/ledger/helpers/ledgerNetworkInfo.ts +0 -127
- package/src/ledger/interfaces/CosmosLedgerInterface.ts +0 -67
|
@@ -1,21 +1,45 @@
|
|
|
1
|
+
import type { UserInteractionRequired } from "@ledgerhq/device-management-kit";
|
|
1
2
|
import type BitcoinApp from "@ledgerhq/hw-app-btc";
|
|
2
3
|
import type { CreateTransactionArg } from "@ledgerhq/hw-app-btc/lib-es/createTransaction";
|
|
3
4
|
import type Transport from "@ledgerhq/hw-transport";
|
|
4
5
|
import { hex } from "@scure/base";
|
|
5
6
|
import { type DerivationPathArray, derivationPathToString, getWalletFormatFor, SwapKitError } from "@swapkit/helpers";
|
|
6
7
|
import type { UTXOType } from "@swapkit/toolboxes/utxo";
|
|
7
|
-
import type {
|
|
8
|
+
import type { Transaction } from "@swapkit/utxo-signer";
|
|
8
9
|
|
|
9
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
LEDGER_USER_INTERACTION_REQUIRED,
|
|
12
|
+
type LedgerJsClientParams,
|
|
13
|
+
normalizeLedgerJsClientParams,
|
|
14
|
+
runLedgerJsOperation,
|
|
15
|
+
} from "../helpers/ledgerJsDmkBridge";
|
|
16
|
+
import { splitOutputsForLegacyApp, withOutputAlignedFinalize } from "./utxo-legacy-outputs";
|
|
10
17
|
|
|
11
18
|
const nonSegwitLedgerChains = ["bitcoin-cash", "dash", "dogecoin", "zcash"];
|
|
12
19
|
|
|
20
|
+
type LedgerUTXOChain = "bitcoin-cash" | "bitcoin" | "litecoin" | "dogecoin" | "dash" | "zcash";
|
|
21
|
+
type UTXOLedgerParams = LedgerJsClientParams<DerivationPathArray | string>;
|
|
22
|
+
|
|
23
|
+
// The Bitcoin Cash, Dash, Dogecoin and Litecoin apps are built on lib-app-bitcoin, which checks every output in a
|
|
24
|
+
// 100-byte buffer (see utxo-legacy-outputs). Bitcoin signs through app-bitcoin-new, and clients/zcash.ts refuses to sign
|
|
25
|
+
// over the legacy Zcash client.
|
|
26
|
+
const libAppBitcoinChains: LedgerUTXOChain[] = ["bitcoin-cash", "dash", "dogecoin", "litecoin"];
|
|
27
|
+
|
|
28
|
+
const ledgerAppNames: Record<LedgerUTXOChain, string> = {
|
|
29
|
+
bitcoin: "Bitcoin",
|
|
30
|
+
"bitcoin-cash": "Bitcoin Cash",
|
|
31
|
+
dash: "Dash",
|
|
32
|
+
dogecoin: "Dogecoin",
|
|
33
|
+
litecoin: "Litecoin",
|
|
34
|
+
zcash: "Zcash",
|
|
35
|
+
};
|
|
36
|
+
|
|
13
37
|
type Params = {
|
|
14
|
-
|
|
38
|
+
outputScriptHex: string;
|
|
15
39
|
inputUtxos: UTXOType[];
|
|
16
40
|
btcApp: BitcoinApp;
|
|
17
41
|
derivationPath: string;
|
|
18
|
-
chain:
|
|
42
|
+
chain: LedgerUTXOChain;
|
|
19
43
|
};
|
|
20
44
|
|
|
21
45
|
type MultiPathParams = Omit<Params, "derivationPath"> & {
|
|
@@ -24,7 +48,7 @@ type MultiPathParams = Omit<Params, "derivationPath"> & {
|
|
|
24
48
|
};
|
|
25
49
|
|
|
26
50
|
const signUTXOTransaction = (
|
|
27
|
-
{
|
|
51
|
+
{ outputScriptHex, inputUtxos, btcApp, derivationPath, chain }: Params,
|
|
28
52
|
options?: Partial<CreateTransactionArg>,
|
|
29
53
|
) => {
|
|
30
54
|
const inputs = inputUtxos.map((item) => {
|
|
@@ -37,11 +61,6 @@ const signUTXOTransaction = (
|
|
|
37
61
|
return [splitTx, item.index, undefined as string | null | undefined, undefined as number | null | undefined] as any;
|
|
38
62
|
});
|
|
39
63
|
|
|
40
|
-
const newTxHex = hex.encode(tx.unsignedTx);
|
|
41
|
-
|
|
42
|
-
const splitNewTx = btcApp.splitTransaction(newTxHex, true);
|
|
43
|
-
const outputScriptHex = btcApp.serializeTransactionOutputs(splitNewTx).toString("hex");
|
|
44
|
-
|
|
45
64
|
// hw-app-btc derives the signing policy from these flags:
|
|
46
65
|
// additionals ["bech32"] + segwit → wpkh (native segwit, m/84')
|
|
47
66
|
// no additionals + segwit → sh(wpkh) (P2SH-P2WPKH, m/49')
|
|
@@ -66,7 +85,7 @@ const signUTXOTransaction = (
|
|
|
66
85
|
* Each input can have its own derivation path for HD wallet multi-address support.
|
|
67
86
|
*/
|
|
68
87
|
const signUTXOTransactionWithMultiplePaths = (
|
|
69
|
-
{
|
|
88
|
+
{ outputScriptHex, inputUtxos, btcApp, derivationPaths, chain }: MultiPathParams,
|
|
70
89
|
options?: Partial<CreateTransactionArg>,
|
|
71
90
|
) => {
|
|
72
91
|
if (derivationPaths.length !== inputUtxos.length) {
|
|
@@ -85,11 +104,6 @@ const signUTXOTransactionWithMultiplePaths = (
|
|
|
85
104
|
return [splitTx, item.index, undefined as string | null | undefined, undefined as number | null | undefined] as any;
|
|
86
105
|
});
|
|
87
106
|
|
|
88
|
-
const newTxHex = hex.encode(tx.unsignedTx);
|
|
89
|
-
|
|
90
|
-
const splitNewTx = btcApp.splitTransaction(newTxHex, true);
|
|
91
|
-
const outputScriptHex = btcApp.serializeTransactionOutputs(splitNewTx).toString("hex");
|
|
92
|
-
|
|
93
107
|
// Same policy/path matching rules as signUTXOTransaction; all paths share
|
|
94
108
|
// one account so the first path determines the format.
|
|
95
109
|
const format = getWalletFormatFor(derivationPaths[0] ?? "");
|
|
@@ -110,52 +124,67 @@ const BaseLedgerUTXO = ({
|
|
|
110
124
|
chain,
|
|
111
125
|
additionalSignParams,
|
|
112
126
|
}: {
|
|
113
|
-
chain:
|
|
127
|
+
chain: LedgerUTXOChain;
|
|
114
128
|
additionalSignParams?: Partial<CreateTransactionArg>;
|
|
115
129
|
}) => {
|
|
116
|
-
|
|
117
|
-
// Per-call state — each BitcoinLedger/LitecoinLedger/... invocation has its own
|
|
118
|
-
// transport + btcApp so different consumers (e.g. concurrent MCP sessions) cannot
|
|
119
|
-
// cross-contaminate each other's Ledger device handle.
|
|
120
|
-
let btcApp: InstanceType<typeof BitcoinApp> | undefined;
|
|
121
|
-
let transport: any = null;
|
|
122
|
-
|
|
123
|
-
async function createTransportWebUSB() {
|
|
124
|
-
transport ||= injectedTransport ?? (await getLedgerTransport());
|
|
125
|
-
const BitcoinApp = (await import("@ledgerhq/hw-app-btc")).default;
|
|
130
|
+
const usesLibAppBitcoin = libAppBitcoinChains.includes(chain);
|
|
126
131
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
132
|
+
return (paramsOrPath?: UTXOLedgerParams | DerivationPathArray | string, transport?: Transport) => {
|
|
133
|
+
const { derivationPath: derivationPathParam, ...connection } = normalizeLedgerJsClientParams({
|
|
134
|
+
paramsOrPath,
|
|
135
|
+
transport,
|
|
136
|
+
});
|
|
137
|
+
const derivationPath =
|
|
138
|
+
typeof derivationPathParam === "string"
|
|
139
|
+
? derivationPathParam
|
|
140
|
+
: derivationPathToString(derivationPathParam as DerivationPathArray);
|
|
141
|
+
const format = getWalletFormatFor(derivationPath);
|
|
130
142
|
|
|
131
|
-
async function
|
|
132
|
-
|
|
143
|
+
async function runBtcOperation<Output>({
|
|
144
|
+
operation,
|
|
145
|
+
requiredUserInteraction,
|
|
146
|
+
}: {
|
|
147
|
+
operation: (app: InstanceType<typeof BitcoinApp>) => Promise<Output> | Output;
|
|
148
|
+
requiredUserInteraction?: UserInteractionRequired;
|
|
149
|
+
}) {
|
|
150
|
+
const BitcoinApp = (await import("@ledgerhq/hw-app-btc")).default;
|
|
151
|
+
return runLedgerJsOperation({
|
|
152
|
+
appName: ledgerAppNames[chain],
|
|
153
|
+
connection,
|
|
154
|
+
// A wrapper per operation, so no collected output chunk outlives the operation that sent it.
|
|
155
|
+
createApp: (ledgerTransport) =>
|
|
156
|
+
new BitcoinApp({
|
|
157
|
+
currency: chain,
|
|
158
|
+
transport: usesLibAppBitcoin ? withOutputAlignedFinalize(ledgerTransport, chain) : ledgerTransport,
|
|
159
|
+
}),
|
|
160
|
+
operation,
|
|
161
|
+
requiredUserInteraction,
|
|
162
|
+
});
|
|
133
163
|
}
|
|
134
164
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
165
|
+
// The outputs hw-app-btc streams to the app, checked before any device call so that an output the app cannot
|
|
166
|
+
// buffer fails with a typed error rather than a 0x6a80 from the device.
|
|
167
|
+
async function getOutputScriptHex(tx: Transaction): Promise<string> {
|
|
168
|
+
const [{ splitTransaction }, { serializeTransactionOutputs }] = await Promise.all([
|
|
169
|
+
import("@ledgerhq/hw-app-btc/splitTransaction"),
|
|
170
|
+
import("@ledgerhq/hw-app-btc/serializeTransaction"),
|
|
171
|
+
]);
|
|
172
|
+
const outputs = serializeTransactionOutputs(splitTransaction(hex.encode(tx.unsignedTx), true));
|
|
173
|
+
if (usesLibAppBitcoin) splitOutputsForLegacyApp(outputs, chain);
|
|
174
|
+
|
|
175
|
+
return outputs.toString("hex");
|
|
139
176
|
}
|
|
140
177
|
|
|
141
|
-
const derivationPath =
|
|
142
|
-
typeof derivationPathArray === "string"
|
|
143
|
-
? derivationPathArray
|
|
144
|
-
: derivationPathToString(derivationPathArray as DerivationPathArray);
|
|
145
|
-
|
|
146
|
-
const format = getWalletFormatFor(derivationPath);
|
|
147
|
-
|
|
148
178
|
return {
|
|
149
179
|
connect: async () => {
|
|
150
|
-
await
|
|
180
|
+
await runBtcOperation({ operation: async () => true });
|
|
151
181
|
},
|
|
152
|
-
disconnect,
|
|
182
|
+
disconnect: async () => {},
|
|
153
183
|
getAddress: async () => {
|
|
154
184
|
const { toCashAddress } = await import("@swapkit/toolboxes/utxo");
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const { bitcoinAddress: address } = await app.getWalletPublicKey(derivationPath, { format });
|
|
185
|
+
const { bitcoinAddress: address } = await runBtcOperation({
|
|
186
|
+
operation: (app) => app.getWalletPublicKey(derivationPath, { format }),
|
|
187
|
+
});
|
|
159
188
|
|
|
160
189
|
if (!address) {
|
|
161
190
|
throw new SwapKitError("wallet_ledger_get_address_error", {
|
|
@@ -168,91 +197,19 @@ const BaseLedgerUTXO = ({
|
|
|
168
197
|
: address;
|
|
169
198
|
},
|
|
170
199
|
getExtendedPublicKey: async (path = "84'/0'/0'", xpubVersion = 76067358) => {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return app.getWalletXpub({ path, xpubVersion });
|
|
200
|
+
return await runBtcOperation({ operation: (app) => app.getWalletXpub({ path, xpubVersion }) });
|
|
174
201
|
},
|
|
175
202
|
|
|
176
|
-
signPCZT: async (pczt: PCZT): Promise<PCZT> => {
|
|
177
|
-
if (chain !== "zcash") {
|
|
178
|
-
throw new SwapKitError("wallet_ledger_chain_not_supported", {
|
|
179
|
-
message: "PCZT signing is only supported for Zcash",
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const app = await getBtcApp();
|
|
184
|
-
|
|
185
|
-
const { ZcashTransaction, Script } = await import("@swapkit/utxo-signer");
|
|
186
|
-
|
|
187
|
-
const global = pczt.getGlobal();
|
|
188
|
-
|
|
189
|
-
const unsignedTx = new ZcashTransaction({
|
|
190
|
-
consensusBranchId: global.consensusBranchId,
|
|
191
|
-
expiryHeight: global.expiryHeight,
|
|
192
|
-
lockTime: global.lockTime,
|
|
193
|
-
version: global.txVersion,
|
|
194
|
-
versionGroupId: global.versionGroupId,
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
const inputUtxos: UTXOType[] = [];
|
|
198
|
-
|
|
199
|
-
for (let i = 0; i < pczt.inputsLength; i++) {
|
|
200
|
-
const input = pczt.getInput(i);
|
|
201
|
-
|
|
202
|
-
unsignedTx.addInput({
|
|
203
|
-
index: input.index,
|
|
204
|
-
script: new Uint8Array(),
|
|
205
|
-
sequence: input.sequence ?? 0xffffffff,
|
|
206
|
-
txid: input.txid,
|
|
207
|
-
value: input.value,
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
inputUtxos.push({
|
|
211
|
-
hash: hex.encode(new Uint8Array([...input.txid].reverse())),
|
|
212
|
-
index: input.index,
|
|
213
|
-
txHex: buildMinimalPrevTxHex(input, global),
|
|
214
|
-
value: Number(input.value),
|
|
215
|
-
witnessUtxo: { script: input.scriptPubkey, value: Number(input.value) },
|
|
216
|
-
} as UTXOType);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
for (let i = 0; i < pczt.outputsLength; i++) {
|
|
220
|
-
const output = pczt.getOutput(i);
|
|
221
|
-
unsignedTx.addOutput({ amount: output.value, script: output.scriptPubkey });
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const signedTxHex = await signUTXOTransaction(
|
|
225
|
-
{ btcApp: app, chain, derivationPath, inputUtxos, tx: unsignedTx as unknown as Transaction },
|
|
226
|
-
{
|
|
227
|
-
...additionalSignParams,
|
|
228
|
-
expiryHeight: (() => {
|
|
229
|
-
const buf = Buffer.alloc(4);
|
|
230
|
-
buf.writeUInt32LE(global.expiryHeight);
|
|
231
|
-
return buf;
|
|
232
|
-
})(),
|
|
233
|
-
lockTime: global.lockTime,
|
|
234
|
-
},
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
const signedTx = ZcashTransaction.fromHex(signedTxHex, { allowUnknownOutputs: true });
|
|
238
|
-
const signedPczt = pczt.clone();
|
|
239
|
-
|
|
240
|
-
for (let i = 0; i < signedTx.inputsLength; i++) {
|
|
241
|
-
const signedInput = signedTx.getInput(i);
|
|
242
|
-
if (signedInput.script && signedInput.script.length > 0) {
|
|
243
|
-
const scriptParts = Script.decode(signedInput.script);
|
|
244
|
-
if (scriptParts.length >= 2) {
|
|
245
|
-
signedPczt.addSignature(i, scriptParts[1] as Uint8Array, scriptParts[0] as Uint8Array);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
return signedPczt;
|
|
251
|
-
},
|
|
252
203
|
signTransaction: async (tx: Transaction, inputUtxos: UTXOType[]) => {
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
204
|
+
const outputScriptHex = await getOutputScriptHex(tx);
|
|
205
|
+
return await runBtcOperation({
|
|
206
|
+
operation: (app) =>
|
|
207
|
+
signUTXOTransaction(
|
|
208
|
+
{ btcApp: app, chain, derivationPath, inputUtxos, outputScriptHex },
|
|
209
|
+
additionalSignParams,
|
|
210
|
+
),
|
|
211
|
+
requiredUserInteraction: LEDGER_USER_INTERACTION_REQUIRED.SignTransaction,
|
|
212
|
+
});
|
|
256
213
|
},
|
|
257
214
|
|
|
258
215
|
/**
|
|
@@ -260,90 +217,35 @@ const BaseLedgerUTXO = ({
|
|
|
260
217
|
* Each input can be signed with its own derivation path.
|
|
261
218
|
*/
|
|
262
219
|
signTransactionWithMultiplePaths: async (tx: Transaction, inputUtxos: UTXOType[], derivationPaths: string[]) => {
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
220
|
+
const outputScriptHex = await getOutputScriptHex(tx);
|
|
221
|
+
return await runBtcOperation({
|
|
222
|
+
operation: (app) =>
|
|
223
|
+
signUTXOTransactionWithMultiplePaths(
|
|
224
|
+
{ btcApp: app, chain, derivationPaths, inputUtxos, outputScriptHex },
|
|
225
|
+
additionalSignParams,
|
|
226
|
+
),
|
|
227
|
+
requiredUserInteraction: LEDGER_USER_INTERACTION_REQUIRED.SignTransaction,
|
|
228
|
+
});
|
|
269
229
|
},
|
|
270
230
|
};
|
|
271
231
|
};
|
|
272
232
|
};
|
|
273
233
|
|
|
274
|
-
function buildMinimalPrevTxHex(
|
|
275
|
-
input: { txid: Uint8Array; index: number; scriptPubkey: Uint8Array; value: bigint },
|
|
276
|
-
global: { txVersion: number; versionGroupId: number; expiryHeight: number; lockTime: number },
|
|
277
|
-
): string {
|
|
278
|
-
const parts: number[] = [];
|
|
279
|
-
|
|
280
|
-
const version = (global.txVersion | 0x80000000) >>> 0;
|
|
281
|
-
parts.push(version & 0xff, (version >> 8) & 0xff, (version >> 16) & 0xff, (version >> 24) & 0xff);
|
|
282
|
-
|
|
283
|
-
const vgid = global.versionGroupId;
|
|
284
|
-
parts.push(vgid & 0xff, (vgid >> 8) & 0xff, (vgid >> 16) & 0xff, (vgid >> 24) & 0xff);
|
|
285
|
-
|
|
286
|
-
parts.push(0);
|
|
287
|
-
|
|
288
|
-
const outputCount = input.index + 1;
|
|
289
|
-
if (outputCount < 0xfd) {
|
|
290
|
-
parts.push(outputCount);
|
|
291
|
-
} else {
|
|
292
|
-
parts.push(0xfd, outputCount & 0xff, (outputCount >> 8) & 0xff);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
for (let i = 0; i < input.index; i++) {
|
|
296
|
-
parts.push(0, 0, 0, 0, 0, 0, 0, 0);
|
|
297
|
-
parts.push(0);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
const value = input.value;
|
|
301
|
-
parts.push(
|
|
302
|
-
Number(value & 0xffn),
|
|
303
|
-
Number((value >> 8n) & 0xffn),
|
|
304
|
-
Number((value >> 16n) & 0xffn),
|
|
305
|
-
Number((value >> 24n) & 0xffn),
|
|
306
|
-
Number((value >> 32n) & 0xffn),
|
|
307
|
-
Number((value >> 40n) & 0xffn),
|
|
308
|
-
Number((value >> 48n) & 0xffn),
|
|
309
|
-
Number((value >> 56n) & 0xffn),
|
|
310
|
-
);
|
|
311
|
-
|
|
312
|
-
const script = input.scriptPubkey;
|
|
313
|
-
if (script.length < 0xfd) {
|
|
314
|
-
parts.push(script.length);
|
|
315
|
-
} else {
|
|
316
|
-
parts.push(0xfd, script.length & 0xff, (script.length >> 8) & 0xff);
|
|
317
|
-
}
|
|
318
|
-
for (const byte of script) {
|
|
319
|
-
parts.push(byte);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
parts.push(
|
|
323
|
-
global.lockTime & 0xff,
|
|
324
|
-
(global.lockTime >> 8) & 0xff,
|
|
325
|
-
(global.lockTime >> 16) & 0xff,
|
|
326
|
-
(global.lockTime >> 24) & 0xff,
|
|
327
|
-
);
|
|
328
|
-
parts.push(
|
|
329
|
-
global.expiryHeight & 0xff,
|
|
330
|
-
(global.expiryHeight >> 8) & 0xff,
|
|
331
|
-
(global.expiryHeight >> 16) & 0xff,
|
|
332
|
-
(global.expiryHeight >> 24) & 0xff,
|
|
333
|
-
);
|
|
334
|
-
parts.push(0, 0, 0, 0, 0, 0, 0, 0); // value balance
|
|
335
|
-
parts.push(0); // empty sapling spends
|
|
336
|
-
parts.push(0); // empty sapling outputs
|
|
337
|
-
parts.push(0); // empty joinsplits
|
|
338
|
-
|
|
339
|
-
return hex.encode(new Uint8Array(parts));
|
|
340
|
-
}
|
|
341
|
-
|
|
342
234
|
export const BitcoinLedger = BaseLedgerUTXO({ chain: "bitcoin" });
|
|
343
235
|
export const LitecoinLedger = BaseLedgerUTXO({ chain: "litecoin" });
|
|
344
236
|
|
|
237
|
+
// "abc" makes hw-app-btc sign with BIP143, which SIGHASH_ALL | SIGHASH_FORKID (0x41) requires, and "cashaddr" opens
|
|
238
|
+
// the transaction with HASH_INPUT_START P2 0x03 so the app shows the outputs as CashAddr, as the dApp does. Trusted
|
|
239
|
+
// inputs (useTrustedInputForSegwit covers every BIP143 transaction) let the app take each amount from a previous
|
|
240
|
+
// transaction it hashed itself; without them it warns about unverified inputs once per transaction. Ledger Live signs
|
|
241
|
+
// CashAddr recipients the same way, with trusted inputs from app 1.4.0.
|
|
345
242
|
export const BitcoinCashLedger = BaseLedgerUTXO({
|
|
346
|
-
additionalSignParams: {
|
|
243
|
+
additionalSignParams: {
|
|
244
|
+
additionals: ["abc", "cashaddr"],
|
|
245
|
+
segwit: false,
|
|
246
|
+
sigHashType: 0x41,
|
|
247
|
+
useTrustedInputForSegwit: true,
|
|
248
|
+
},
|
|
347
249
|
chain: "bitcoin-cash",
|
|
348
250
|
});
|
|
349
251
|
|
|
@@ -1,45 +1,61 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { UserInteractionRequired } from "@ledgerhq/device-management-kit";
|
|
2
|
+
import type Xrp from "@ledgerhq/hw-app-xrp";
|
|
2
3
|
import type Transport from "@ledgerhq/hw-transport";
|
|
3
4
|
import { Chain, type DerivationPathArray, derivationPathToString, NetworkDerivationPath } from "@swapkit/helpers";
|
|
4
5
|
import type { RippleTransaction } from "@swapkit/toolboxes/ripple";
|
|
5
|
-
import { encode } from "ripple-binary-codec";
|
|
6
6
|
import type { Payment } from "xrpl";
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
LEDGER_USER_INTERACTION_REQUIRED,
|
|
10
|
+
type LedgerJsClientParams,
|
|
11
|
+
normalizeLedgerJsClientParams,
|
|
12
|
+
runLedgerJsOperation,
|
|
13
|
+
} from "../helpers/ledgerJsDmkBridge";
|
|
8
14
|
|
|
9
15
|
const TF_FULLY_CANONICAL_SIG = 2147483648;
|
|
10
16
|
|
|
11
|
-
|
|
12
|
-
const cleaned: Record<string, any> = {};
|
|
13
|
-
for (const key in obj) {
|
|
14
|
-
if (obj[key] !== null && obj[key] !== undefined) {
|
|
15
|
-
cleaned[key] = obj[key];
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
return cleaned;
|
|
19
|
-
}
|
|
17
|
+
type XRPLedgerParams = LedgerJsClientParams<DerivationPathArray>;
|
|
20
18
|
|
|
21
|
-
function
|
|
22
|
-
return
|
|
19
|
+
function cleanTransactionObject(transaction: object): Record<string, unknown> {
|
|
20
|
+
return Object.fromEntries(Object.entries(transaction).filter(([, value]) => value !== null && value !== undefined));
|
|
23
21
|
}
|
|
24
22
|
|
|
25
|
-
export
|
|
23
|
+
export async function XRPLedger(paramsOrPath?: XRPLedgerParams | DerivationPathArray, transport?: Transport) {
|
|
24
|
+
const { derivationPath, ...connection } = normalizeLedgerJsClientParams({ paramsOrPath, transport });
|
|
26
25
|
const path = derivationPathToString(derivationPath || NetworkDerivationPath[Chain.Ripple]);
|
|
27
|
-
const transport = injectedTransport ?? (await getLedgerTransport());
|
|
28
|
-
const xrpInstance = establishConnection(transport);
|
|
29
26
|
|
|
30
|
-
|
|
27
|
+
async function runXrpOperation<Output>({
|
|
28
|
+
operation,
|
|
29
|
+
requiredUserInteraction,
|
|
30
|
+
}: {
|
|
31
|
+
operation: (app: Xrp) => Promise<Output>;
|
|
32
|
+
requiredUserInteraction?: UserInteractionRequired;
|
|
33
|
+
}) {
|
|
34
|
+
const XrpApp = (await import("@ledgerhq/hw-app-xrp")).default;
|
|
35
|
+
return runLedgerJsOperation({
|
|
36
|
+
appName: "XRP",
|
|
37
|
+
connection,
|
|
38
|
+
createApp: (ledgerTransport) => new XrpApp(ledgerTransport),
|
|
39
|
+
operation,
|
|
40
|
+
requiredUserInteraction,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const { address, publicKey } = await runXrpOperation({ operation: (app) => app.getAddress(path) });
|
|
31
45
|
|
|
32
46
|
async function signTransaction(transaction: Payment | RippleTransaction) {
|
|
33
|
-
const { hashes } = await import("xrpl");
|
|
34
|
-
const cleanedTxWithPubKey = cleanTransactionObject(transaction);
|
|
47
|
+
const [{ encode }, { hashes }] = await Promise.all([import("ripple-binary-codec"), import("xrpl")]);
|
|
35
48
|
const transactionJSON = {
|
|
36
|
-
...
|
|
49
|
+
...cleanTransactionObject(transaction),
|
|
37
50
|
Flags: transaction.Flags || TF_FULLY_CANONICAL_SIG,
|
|
38
51
|
SigningPubKey: publicKey.toUpperCase(),
|
|
39
52
|
};
|
|
40
53
|
|
|
41
54
|
const transactionToSignOnLedger = encode(transactionJSON);
|
|
42
|
-
const txnSignature = await
|
|
55
|
+
const txnSignature = await runXrpOperation({
|
|
56
|
+
operation: (app) => app.signTransaction(path, transactionToSignOnLedger),
|
|
57
|
+
requiredUserInteraction: LEDGER_USER_INTERACTION_REQUIRED.SignTransaction,
|
|
58
|
+
});
|
|
43
59
|
const tx_blob = encode({ ...transactionJSON, TxnSignature: txnSignature });
|
|
44
60
|
const hash = hashes.hashSignedTx(tx_blob);
|
|
45
61
|
|
|
@@ -47,4 +63,4 @@ export const XRPLedger = async (derivationPath?: DerivationPathArray, injectedTr
|
|
|
47
63
|
}
|
|
48
64
|
|
|
49
65
|
return { getAddress: () => address, signTransaction };
|
|
50
|
-
}
|
|
66
|
+
}
|