@sidhujag/sysweb3-keyring 1.0.628 → 2.0.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/CHANGELOG.md +22 -0
- package/README.md +66 -0
- package/cjs/hardware-wallet-manager.js +302 -128
- package/cjs/hardware-wallet-manager.js.map +1 -1
- package/cjs/keyring-core.js +93 -0
- package/cjs/keyring-core.js.map +1 -1
- package/cjs/keyring-manager.js +9 -3
- package/cjs/keyring-manager.js.map +1 -1
- package/cjs/ledger/bitcoin_client/lib/appClient.js.map +1 -1
- package/cjs/ledger/host-types.js +10 -0
- package/cjs/ledger/host-types.js.map +1 -0
- package/cjs/ledger/index.js +243 -447
- package/cjs/ledger/index.js.map +1 -1
- package/cjs/ledger/prepare-psbt.js +177 -0
- package/cjs/ledger/prepare-psbt.js.map +1 -0
- package/cjs/software-hd-account.js +23 -0
- package/cjs/software-hd-account.js.map +1 -0
- package/cjs/software.js +16 -0
- package/cjs/software.js.map +1 -1
- package/cjs/transactions/ethereum.js +55 -10
- package/cjs/transactions/ethereum.js.map +1 -1
- package/cjs/transactions/hardware-psbt.js +36 -44
- package/cjs/transactions/hardware-psbt.js.map +1 -1
- package/cjs/transactions/prepared-evm.js +196 -0
- package/cjs/transactions/prepared-evm.js.map +1 -0
- package/cjs/trezor/connect.js +243 -0
- package/cjs/trezor/connect.js.map +1 -0
- package/cjs/trezor/index.js +96 -58
- package/cjs/trezor/index.js.map +1 -1
- package/cjs/trezor/witness.js +25 -0
- package/cjs/trezor/witness.js.map +1 -0
- package/cjs/utils/psbt-account-scope.js +5 -3
- package/cjs/utils/psbt-account-scope.js.map +1 -1
- package/esm/errorUtils.js +72 -0
- package/esm/errorUtils.js.map +1 -0
- package/esm/ethers-v6.js +207 -0
- package/esm/ethers-v6.js.map +1 -0
- package/esm/hardware-wallet-manager.js +643 -0
- package/esm/hardware-wallet-manager.js.map +1 -0
- package/esm/ledger/bitcoin_client/lib/appClient.js +279 -0
- package/esm/ledger/bitcoin_client/lib/appClient.js.map +1 -0
- package/esm/ledger/bitcoin_client/lib/bip32.js +49 -0
- package/esm/ledger/bitcoin_client/lib/bip32.js.map +1 -0
- package/esm/ledger/bitcoin_client/lib/buffertools.js +119 -0
- package/esm/ledger/bitcoin_client/lib/buffertools.js.map +1 -0
- package/esm/ledger/bitcoin_client/lib/clientCommands.js +269 -0
- package/esm/ledger/bitcoin_client/lib/clientCommands.js.map +1 -0
- package/esm/ledger/bitcoin_client/lib/merkelizedPsbt.js +50 -0
- package/esm/ledger/bitcoin_client/lib/merkelizedPsbt.js.map +1 -0
- package/esm/ledger/bitcoin_client/lib/merkle.js +111 -0
- package/esm/ledger/bitcoin_client/lib/merkle.js.map +1 -0
- package/esm/ledger/bitcoin_client/lib/merkleMap.js +42 -0
- package/esm/ledger/bitcoin_client/lib/merkleMap.js.map +1 -0
- package/esm/ledger/bitcoin_client/lib/policy.js +68 -0
- package/esm/ledger/bitcoin_client/lib/policy.js.map +1 -0
- package/esm/ledger/bitcoin_client/lib/psbtv2.js +645 -0
- package/esm/ledger/bitcoin_client/lib/psbtv2.js.map +1 -0
- package/esm/ledger/bitcoin_client/lib/varint.js +108 -0
- package/esm/ledger/bitcoin_client/lib/varint.js.map +1 -0
- package/esm/ledger/consts.js +4 -0
- package/esm/ledger/consts.js.map +1 -0
- package/esm/ledger/dmk-evm.js +258 -0
- package/esm/ledger/dmk-evm.js.map +1 -0
- package/esm/ledger/dmk-session.js +264 -0
- package/esm/ledger/dmk-session.js.map +1 -0
- package/esm/ledger/dmk-utxo.js +279 -0
- package/esm/ledger/dmk-utxo.js.map +1 -0
- package/esm/ledger/host-types.js +5 -0
- package/esm/ledger/host-types.js.map +1 -0
- package/esm/ledger/index.js +268 -0
- package/esm/ledger/index.js.map +1 -0
- package/esm/ledger/prepare-psbt.js +141 -0
- package/esm/ledger/prepare-psbt.js.map +1 -0
- package/esm/ledger/types.js +2 -0
- package/esm/ledger/types.js.map +1 -0
- package/esm/ledger-host.js +36 -0
- package/esm/ledger-host.js.map +1 -0
- package/esm/private-records.js +153 -0
- package/esm/private-records.js.map +1 -0
- package/esm/providers.js +588 -0
- package/esm/providers.js.map +1 -0
- package/esm/signers.js +28 -0
- package/esm/signers.js.map +1 -0
- package/esm/trezor/connect.js +206 -0
- package/esm/trezor/connect.js.map +1 -0
- package/esm/trezor/index.js +876 -0
- package/esm/trezor/index.js.map +1 -0
- package/esm/trezor/witness.js +21 -0
- package/esm/trezor/witness.js.map +1 -0
- package/esm/types.js +17 -0
- package/esm/types.js.map +1 -0
- package/esm/utils/derivation-paths.js +109 -0
- package/esm/utils/derivation-paths.js.map +1 -0
- package/esm/utils/psbt-account-scope.js +310 -0
- package/esm/utils/psbt-account-scope.js.map +1 -0
- package/package.json +21 -8
- package/types/hardware-wallet-manager.d.ts +12 -19
- package/types/keyring-core.d.ts +6 -0
- package/types/keyring-manager.d.ts +2 -1
- package/types/ledger/bitcoin_client/lib/appClient.d.ts +6 -3
- package/types/ledger/dmk-evm.d.ts +8 -0
- package/types/ledger/dmk-session.d.ts +60 -0
- package/types/ledger/dmk-utxo.d.ts +26 -0
- package/types/ledger/host-types.d.ts +131 -0
- package/types/ledger/index.d.ts +21 -58
- package/types/ledger/prepare-psbt.d.ts +3 -0
- package/types/ledger/types.d.ts +3 -0
- package/types/ledger-host.d.ts +7 -0
- package/types/software-hd-account.d.ts +16 -0
- package/types/software.d.ts +16 -0
- package/types/transactions/ethereum.d.ts +1 -1
- package/types/transactions/prepared-evm.d.ts +53 -0
- package/types/trezor/connect.d.ts +42 -0
- package/types/trezor/index.d.ts +22 -4
- package/types/trezor/witness.d.ts +3 -0
- package/types/utils/psbt-account-scope.d.ts +1 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { SignTypedDataVersion, TypedDataUtils } from '@metamask/eth-sig-util';
|
|
2
|
+
import { computeAddress, getAddress, hashMessage, recoverAddress, Signature, Transaction, } from 'ethers';
|
|
3
|
+
import { ConnectionStatus, HardwareWalletType, } from '../hardware-wallet-manager';
|
|
4
|
+
import { ledgerCancelledError, ledgerHostError } from './host-types';
|
|
5
|
+
const invalidRequest = () => ledgerHostError('LEDGER_INVALID_REQUEST', 'Invalid Ledger signing request');
|
|
6
|
+
const invalidSignature = () => ledgerHostError('LEDGER_INVALID_SIGNATURE', 'Ledger returned an invalid signature for this request');
|
|
7
|
+
const accountIndex = (value) => {
|
|
8
|
+
if (!Number.isSafeInteger(value) || value < 0 || value > 0x7fffffff)
|
|
9
|
+
throw invalidRequest();
|
|
10
|
+
return value;
|
|
11
|
+
};
|
|
12
|
+
const hexBytes = (value) => {
|
|
13
|
+
if (typeof value !== 'string' || !/^(?:0x)?(?:[0-9a-f]{2})*$/i.test(value))
|
|
14
|
+
throw invalidRequest();
|
|
15
|
+
return Uint8Array.from(Buffer.from(value.replace(/^0x/i, ''), 'hex'));
|
|
16
|
+
};
|
|
17
|
+
const approvedAddress = (value) => {
|
|
18
|
+
try {
|
|
19
|
+
return getAddress(value);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
throw invalidRequest();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const checkedSignature = (value, digest, expected) => {
|
|
26
|
+
try {
|
|
27
|
+
let signature;
|
|
28
|
+
if (typeof value === 'string') {
|
|
29
|
+
if (!/^0x[0-9a-f]{130}$/i.test(value))
|
|
30
|
+
throw invalidSignature();
|
|
31
|
+
signature = Signature.from(value);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
if (!value ||
|
|
35
|
+
!/^[0-9a-f]{64}$/i.test(value.r) ||
|
|
36
|
+
!/^[0-9a-f]{64}$/i.test(value.s) ||
|
|
37
|
+
!/^[0-9a-f]+$/i.test(value.v))
|
|
38
|
+
throw invalidSignature();
|
|
39
|
+
const v = Number.parseInt(value.v, 16);
|
|
40
|
+
if (!Number.isSafeInteger(v) || v < 0)
|
|
41
|
+
throw invalidSignature();
|
|
42
|
+
signature = Signature.from({ r: `0x${value.r}`, s: `0x${value.s}`, v });
|
|
43
|
+
}
|
|
44
|
+
if (recoverAddress(digest, signature) !== expected)
|
|
45
|
+
throw invalidSignature();
|
|
46
|
+
return signature;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
throw invalidSignature();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
// Detach the approved typed data before connection or host code can await/mutate it.
|
|
53
|
+
const copyTypedData = (value, seen = new WeakSet(), depth = 0) => {
|
|
54
|
+
if (depth > 64)
|
|
55
|
+
throw invalidRequest();
|
|
56
|
+
if (value === null || typeof value === 'string' || typeof value === 'boolean')
|
|
57
|
+
return value;
|
|
58
|
+
if (typeof value === 'bigint')
|
|
59
|
+
return value.toString();
|
|
60
|
+
if (typeof value === 'number') {
|
|
61
|
+
if (!Number.isFinite(value))
|
|
62
|
+
throw invalidRequest();
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
if (value instanceof Uint8Array)
|
|
66
|
+
return `0x${Buffer.from(value).toString('hex')}`;
|
|
67
|
+
if (!value || typeof value !== 'object' || seen.has(value))
|
|
68
|
+
throw invalidRequest();
|
|
69
|
+
const array = Array.isArray(value);
|
|
70
|
+
const prototype = Object.getPrototypeOf(value);
|
|
71
|
+
if (!array && prototype !== Object.prototype && prototype !== null)
|
|
72
|
+
throw invalidRequest();
|
|
73
|
+
seen.add(value);
|
|
74
|
+
try {
|
|
75
|
+
const result = array ? [] : Object.create(null);
|
|
76
|
+
for (const key of Object.keys(value)) {
|
|
77
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
78
|
+
if (!('value' in descriptor))
|
|
79
|
+
throw invalidRequest();
|
|
80
|
+
if (descriptor.value !== undefined)
|
|
81
|
+
result[key] = copyTypedData(descriptor.value, seen, depth + 1);
|
|
82
|
+
}
|
|
83
|
+
return Object.freeze(result);
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
seen.delete(value);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
/** Small authority-side facade. Device SDKs belong exclusively in ledger-host. */
|
|
90
|
+
export class LedgerKeyring {
|
|
91
|
+
// Retain the first constructor position for existing shared-manager callers.
|
|
92
|
+
// A manager alone cannot grant a new device capability.
|
|
93
|
+
constructor(sharedHardwareWalletManager, host) {
|
|
94
|
+
this.sharedHardwareWalletManager = sharedHardwareWalletManager;
|
|
95
|
+
this.host = host;
|
|
96
|
+
this.generation = 0;
|
|
97
|
+
this.ensureConnection = async () => this.run(async () => undefined);
|
|
98
|
+
this.verifyUtxoAddress = (accountIndex, currency, slip44) => this.run((host) => host.utxo.getAddress({
|
|
99
|
+
accountIndex,
|
|
100
|
+
currency,
|
|
101
|
+
slip44,
|
|
102
|
+
checkOnDevice: true,
|
|
103
|
+
}));
|
|
104
|
+
this.signUtxoMessage = (request) => {
|
|
105
|
+
const approved = Object.freeze({
|
|
106
|
+
currency: request.currency,
|
|
107
|
+
slip44: request.slip44,
|
|
108
|
+
accountIndex: request.accountIndex,
|
|
109
|
+
message: request.message,
|
|
110
|
+
addressIndex: request.addressIndex,
|
|
111
|
+
change: request.change,
|
|
112
|
+
accountXpub: request.accountXpub,
|
|
113
|
+
});
|
|
114
|
+
return this.run((host) => host.utxo.signMessage(approved));
|
|
115
|
+
};
|
|
116
|
+
this.signPsbt = (request) => {
|
|
117
|
+
const approved = Object.freeze({
|
|
118
|
+
currency: request.currency,
|
|
119
|
+
slip44: request.slip44,
|
|
120
|
+
accountIndex: request.accountIndex,
|
|
121
|
+
accountXpub: request.accountXpub,
|
|
122
|
+
psbtBase64: request.psbtBase64,
|
|
123
|
+
});
|
|
124
|
+
return this.run((host) => host.utxo.signPsbt(approved));
|
|
125
|
+
};
|
|
126
|
+
this.evm = {
|
|
127
|
+
getEvmAddressAndPubKey: async (request) => {
|
|
128
|
+
const approved = { accountIndex: accountIndex(request.accountIndex) };
|
|
129
|
+
return this.run(async (host, assertCurrent) => {
|
|
130
|
+
const result = await host.evm.getAddress(approved);
|
|
131
|
+
assertCurrent();
|
|
132
|
+
try {
|
|
133
|
+
const address = getAddress(result.address);
|
|
134
|
+
const publicKey = result.publicKey.replace(/^0x/i, '');
|
|
135
|
+
if (computeAddress(`0x${publicKey}`) !== address)
|
|
136
|
+
throw invalidRequest();
|
|
137
|
+
return { address, publicKey };
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
throw ledgerHostError('LEDGER_INVALID_RESPONSE', 'Ledger returned an invalid address or public key');
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
},
|
|
144
|
+
signEVMTransaction: async (request) => {
|
|
145
|
+
const index = accountIndex(request.accountIndex);
|
|
146
|
+
const expected = approvedAddress(request.expectedAddress);
|
|
147
|
+
let transaction;
|
|
148
|
+
try {
|
|
149
|
+
transaction = Transaction.from(`0x${Buffer.from(hexBytes(request.rawTx)).toString('hex')}`);
|
|
150
|
+
if (transaction.signature || transaction.chainId <= 0n)
|
|
151
|
+
throw invalidRequest();
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
throw invalidRequest();
|
|
155
|
+
}
|
|
156
|
+
const approved = {
|
|
157
|
+
accountIndex: index,
|
|
158
|
+
expectedAddress: expected,
|
|
159
|
+
unsignedTxHex: transaction.unsignedSerialized.replace(/^0x/, ''),
|
|
160
|
+
};
|
|
161
|
+
const digest = transaction.unsignedHash;
|
|
162
|
+
return this.run(async (host, assertCurrent) => {
|
|
163
|
+
const result = await host.evm.signTransaction(approved);
|
|
164
|
+
assertCurrent();
|
|
165
|
+
const signature = checkedSignature(result, digest, expected);
|
|
166
|
+
if (signature.legacyChainId !== null &&
|
|
167
|
+
signature.legacyChainId !== transaction.chainId)
|
|
168
|
+
throw invalidSignature();
|
|
169
|
+
return {
|
|
170
|
+
r: signature.r.slice(2),
|
|
171
|
+
s: signature.s.slice(2),
|
|
172
|
+
v: signature.v.toString(16),
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
},
|
|
176
|
+
signPersonalMessage: async (request) => {
|
|
177
|
+
const expected = approvedAddress(request.expectedAddress);
|
|
178
|
+
const messageHex = Buffer.from(hexBytes(request.message)).toString('hex');
|
|
179
|
+
const digest = hashMessage(hexBytes(messageHex));
|
|
180
|
+
const approved = {
|
|
181
|
+
accountIndex: accountIndex(request.accountIndex),
|
|
182
|
+
expectedAddress: expected,
|
|
183
|
+
messageHex,
|
|
184
|
+
};
|
|
185
|
+
return this.run(async (host) => checkedSignature(await host.evm.signPersonalMessage(approved), digest, expected).serialized);
|
|
186
|
+
},
|
|
187
|
+
signTypedData: async (request) => {
|
|
188
|
+
const { version } = request;
|
|
189
|
+
if (version !== SignTypedDataVersion.V3 &&
|
|
190
|
+
version !== SignTypedDataVersion.V4)
|
|
191
|
+
throw invalidRequest();
|
|
192
|
+
const expected = approvedAddress(request.expectedAddress);
|
|
193
|
+
const index = accountIndex(request.accountIndex);
|
|
194
|
+
let data, digest;
|
|
195
|
+
try {
|
|
196
|
+
data = copyTypedData(request.data);
|
|
197
|
+
digest = `0x${TypedDataUtils.eip712Hash(data, version).toString('hex')}`;
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
throw invalidRequest();
|
|
201
|
+
}
|
|
202
|
+
const approved = {
|
|
203
|
+
accountIndex: index,
|
|
204
|
+
expectedAddress: expected,
|
|
205
|
+
data,
|
|
206
|
+
version,
|
|
207
|
+
};
|
|
208
|
+
return this.run(async (host) => checkedSignature(await host.evm.signTypedData(approved), digest, expected).serialized);
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
this.utxo = {
|
|
212
|
+
getUtxoAddress: ({ coin, index, slip44 }) => this.run((host) => host.utxo.getAddress({ currency: coin, accountIndex: index, slip44 })),
|
|
213
|
+
getXpub: ({ coin, index, slip44 }) => this.run((host) => host.utxo.getXpub({
|
|
214
|
+
currency: coin,
|
|
215
|
+
accountIndex: index,
|
|
216
|
+
slip44,
|
|
217
|
+
// Import must remain available for paths the device classifies as
|
|
218
|
+
// unusual. Ask for its confirmation once, without retrying denial.
|
|
219
|
+
checkOnDevice: true,
|
|
220
|
+
})),
|
|
221
|
+
verifyUtxoAddress: this.verifyUtxoAddress,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
requireHost() {
|
|
225
|
+
if (!this.host)
|
|
226
|
+
throw ledgerHostError('HARDWARE_SIGNER_UNAVAILABLE', 'Ledger requires an authorized device host');
|
|
227
|
+
return this.host;
|
|
228
|
+
}
|
|
229
|
+
async run(operation) {
|
|
230
|
+
const generation = this.generation;
|
|
231
|
+
const host = this.requireHost();
|
|
232
|
+
// A visible platform host owns discovery, permission and device selection.
|
|
233
|
+
if (!host.getStatus().connected)
|
|
234
|
+
await host.connect({ useGrantedDevices: true });
|
|
235
|
+
const assertCurrent = () => {
|
|
236
|
+
if (generation !== this.generation)
|
|
237
|
+
throw ledgerCancelledError();
|
|
238
|
+
};
|
|
239
|
+
assertCurrent();
|
|
240
|
+
try {
|
|
241
|
+
const result = await operation(host, assertCurrent);
|
|
242
|
+
assertCurrent();
|
|
243
|
+
return result;
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
assertCurrent();
|
|
247
|
+
throw error;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
getStatus() {
|
|
251
|
+
const connected = this.host?.getStatus().connected === true;
|
|
252
|
+
return {
|
|
253
|
+
type: HardwareWalletType.LEDGER,
|
|
254
|
+
connected,
|
|
255
|
+
status: connected
|
|
256
|
+
? ConnectionStatus.CONNECTED
|
|
257
|
+
: ConnectionStatus.DISCONNECTED,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
async destroy() {
|
|
261
|
+
// Revoke pending responses synchronously, before platform teardown awaits.
|
|
262
|
+
this.generation++;
|
|
263
|
+
const cleanup = this.sharedHardwareWalletManager?.destroy();
|
|
264
|
+
const disconnect = this.host?.disconnect();
|
|
265
|
+
await Promise.all([cleanup, disconnect]);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ledger/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import * as syscoinjs from 'syscoinjs-lib';
|
|
3
|
+
import { getAccountDerivationPath } from '../utils/derivation-paths';
|
|
4
|
+
import { parsePsbtAccountXpub } from '../utils/psbt-account-scope';
|
|
5
|
+
const Transaction = syscoinjs.utils.bitcoinjs.Transaction;
|
|
6
|
+
/** Enrich public PSBT metadata only. Callers must also enforce account scope. */
|
|
7
|
+
export function prepareLedgerPsbt(psbt, accountXpub, accountId, currency, slip44, fingerprint) {
|
|
8
|
+
if (!/^[0-9a-fA-F]{8}$/.test(fingerprint))
|
|
9
|
+
throw new Error('Invalid Ledger master fingerprint');
|
|
10
|
+
const accountNode = parsePsbtAccountXpub(accountXpub);
|
|
11
|
+
// Enhance each input with bip32Derivation
|
|
12
|
+
const missingInputDerivations = [];
|
|
13
|
+
for (let i = 0; i < psbt.inputCount; i++) {
|
|
14
|
+
const dataInput = psbt.data.inputs[i];
|
|
15
|
+
// External inputs are already authorized by their final scripts. Do
|
|
16
|
+
// not invent wallet derivations or ask the device to sign them again.
|
|
17
|
+
if (dataInput.finalScriptSig || dataInput.finalScriptWitness)
|
|
18
|
+
continue;
|
|
19
|
+
// Skip if already has bip32Derivation
|
|
20
|
+
if (dataInput.bip32Derivation && dataInput.bip32Derivation.length > 0) {
|
|
21
|
+
// Scope validation has already limited these hints to the approved account.
|
|
22
|
+
for (const derivation of dataInput.bip32Derivation)
|
|
23
|
+
derivation.masterFingerprint = Buffer.from(fingerprint, 'hex');
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
// Ensure witnessUtxo is present if nonWitnessUtxo exists
|
|
27
|
+
if (!dataInput.witnessUtxo && dataInput.nonWitnessUtxo) {
|
|
28
|
+
const txBuffer = dataInput.nonWitnessUtxo;
|
|
29
|
+
const tx = Transaction.fromBuffer(txBuffer);
|
|
30
|
+
const vout = psbt.txInputs[i].index;
|
|
31
|
+
if (tx.outs[vout]) {
|
|
32
|
+
dataInput.witnessUtxo = {
|
|
33
|
+
script: tx.outs[vout].script,
|
|
34
|
+
value: tx.outs[vout].value,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Extract path from unknownKeyVals by searching for the key, not using hardcoded index
|
|
39
|
+
let pathFromInput = null;
|
|
40
|
+
if (dataInput.unknownKeyVals && dataInput.unknownKeyVals.length > 0) {
|
|
41
|
+
for (const kv of dataInput.unknownKeyVals) {
|
|
42
|
+
const keyStr = Buffer.from(kv.key).toString();
|
|
43
|
+
if (keyStr === 'path') {
|
|
44
|
+
pathFromInput = Buffer.from(kv.value).toString();
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
let bip32Derivation = null;
|
|
50
|
+
if (pathFromInput) {
|
|
51
|
+
const fullPath = pathFromInput;
|
|
52
|
+
const accountPath = getAccountDerivationPath(currency, slip44, accountId);
|
|
53
|
+
const relativePath = fullPath.replace(accountPath, '').replace(/^\//, '');
|
|
54
|
+
const derivationTokens = relativePath.split('/').filter((t) => t);
|
|
55
|
+
const derivedAccount = derivationTokens.reduce((acc, token) => {
|
|
56
|
+
const index = parseInt(token);
|
|
57
|
+
if (isNaN(index)) {
|
|
58
|
+
return acc;
|
|
59
|
+
}
|
|
60
|
+
return acc.derive(index);
|
|
61
|
+
}, accountNode);
|
|
62
|
+
const rawPubkey = derivedAccount.publicKey;
|
|
63
|
+
const pubkeyBuf = Buffer.isBuffer(rawPubkey)
|
|
64
|
+
? rawPubkey
|
|
65
|
+
: Buffer.from(rawPubkey);
|
|
66
|
+
if (pubkeyBuf && pubkeyBuf.length === 33) {
|
|
67
|
+
// Add the bip32Derivation that Ledger needs
|
|
68
|
+
bip32Derivation = {
|
|
69
|
+
masterFingerprint: Buffer.from(fingerprint, 'hex'),
|
|
70
|
+
path: fullPath,
|
|
71
|
+
pubkey: pubkeyBuf,
|
|
72
|
+
};
|
|
73
|
+
psbt.updateInput(i, {
|
|
74
|
+
bip32Derivation: [bip32Derivation],
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Check the updated PSBT state (avoid stale local references)
|
|
79
|
+
const updatedInput = psbt.data.inputs[i];
|
|
80
|
+
if (!updatedInput.bip32Derivation ||
|
|
81
|
+
updatedInput.bip32Derivation.length === 0) {
|
|
82
|
+
missingInputDerivations.push(i);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Enhance each output with bip32Derivation when it's a change/output owned by the wallet
|
|
86
|
+
for (let i = 0; i < psbt.data.outputs.length; i++) {
|
|
87
|
+
const dataOutput = psbt.data.outputs[i];
|
|
88
|
+
// Skip if derivation already present
|
|
89
|
+
if (dataOutput.bip32Derivation && dataOutput.bip32Derivation.length > 0) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
// Extract path from unknownKeyVals by searching for the key 'path'
|
|
93
|
+
let pathFromOutput = null;
|
|
94
|
+
if (dataOutput.unknownKeyVals && dataOutput.unknownKeyVals.length > 0) {
|
|
95
|
+
for (const kv of dataOutput.unknownKeyVals) {
|
|
96
|
+
const keyStr = Buffer.from(kv.key).toString();
|
|
97
|
+
if (keyStr === 'path') {
|
|
98
|
+
pathFromOutput = Buffer.from(kv.value).toString();
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (pathFromOutput) {
|
|
104
|
+
let bip32Derivation = null;
|
|
105
|
+
const fullPath = pathFromOutput;
|
|
106
|
+
const accountPath = getAccountDerivationPath(currency, slip44, accountId);
|
|
107
|
+
const relativePath = fullPath.replace(accountPath, '').replace(/^\//, '');
|
|
108
|
+
const derivationTokens = relativePath.split('/').filter((t) => t);
|
|
109
|
+
const derivedAccount = derivationTokens.reduce((acc, token) => {
|
|
110
|
+
const index = parseInt(token);
|
|
111
|
+
if (isNaN(index)) {
|
|
112
|
+
return acc;
|
|
113
|
+
}
|
|
114
|
+
return acc.derive(index);
|
|
115
|
+
}, accountNode);
|
|
116
|
+
const rawOutPubkey = derivedAccount.publicKey;
|
|
117
|
+
const outPubkeyBuf = Buffer.isBuffer(rawOutPubkey)
|
|
118
|
+
? rawOutPubkey
|
|
119
|
+
: Buffer.from(rawOutPubkey);
|
|
120
|
+
if (outPubkeyBuf && outPubkeyBuf.length === 33) {
|
|
121
|
+
bip32Derivation = {
|
|
122
|
+
masterFingerprint: Buffer.from(fingerprint, 'hex'),
|
|
123
|
+
path: fullPath,
|
|
124
|
+
pubkey: outPubkeyBuf,
|
|
125
|
+
};
|
|
126
|
+
psbt.updateOutput(i, {
|
|
127
|
+
bip32Derivation: [bip32Derivation],
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
// Outputs without valid derivation are allowed (external recipients)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// If any wallet-owned inputs/outputs are missing bip32Derivation, fail early with a clear error
|
|
134
|
+
if (missingInputDerivations.length > 0) {
|
|
135
|
+
const parts = [];
|
|
136
|
+
parts.push(`inputs [${missingInputDerivations.join(', ')}]`);
|
|
137
|
+
throw new Error(`convertToLedgerFormat: Missing bip32Derivation for ${parts.join(' and ')}. Ensure PSBT includes a 'path' unknownKeyVal or BIP32_DERIVATION for wallet-owned entries.`);
|
|
138
|
+
}
|
|
139
|
+
return psbt;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=prepare-psbt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepare-psbt.js","sourceRoot":"","sources":["../../../src/ledger/prepare-psbt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/ledger/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Heavy browser host entry. Do not import from the wallet worker or software entry. */
|
|
2
|
+
import { DeviceManagementKitBuilder, } from '@ledgerhq/device-management-kit';
|
|
3
|
+
import { webHidTransportFactory } from '@ledgerhq/device-transport-kit-web-hid';
|
|
4
|
+
import { createLedgerEvmAdapter } from './ledger/dmk-evm';
|
|
5
|
+
import { LedgerDmkSession } from './ledger/dmk-session';
|
|
6
|
+
import { createLedgerUtxoAdapter } from './ledger/dmk-utxo';
|
|
7
|
+
import { ledgerHostError } from './ledger/host-types';
|
|
8
|
+
export function createLedgerDmkHost(config = {}) {
|
|
9
|
+
const candidate = config.dmk ??
|
|
10
|
+
new DeviceManagementKitBuilder()
|
|
11
|
+
.addTransport(webHidTransportFactory)
|
|
12
|
+
.build();
|
|
13
|
+
for (const method of [
|
|
14
|
+
'connect',
|
|
15
|
+
'disconnect',
|
|
16
|
+
'executeDeviceAction',
|
|
17
|
+
'startDiscovering',
|
|
18
|
+
'listenToAvailableDevices',
|
|
19
|
+
'getDeviceSessionState',
|
|
20
|
+
]) {
|
|
21
|
+
if (typeof candidate[method] !== 'function')
|
|
22
|
+
throw ledgerHostError('LEDGER_INVALID_HOST', 'Invalid Ledger device manager');
|
|
23
|
+
}
|
|
24
|
+
// Keep upstream exports-only types out of this public declaration. A trusted
|
|
25
|
+
// platform supplies its concrete DMK here; dapps cannot select this object.
|
|
26
|
+
const dmk = candidate;
|
|
27
|
+
const session = new LedgerDmkSession(dmk);
|
|
28
|
+
return {
|
|
29
|
+
connect: (request, options) => session.connect(request, options),
|
|
30
|
+
disconnect: () => session.disconnect(),
|
|
31
|
+
getStatus: () => session.getStatus(),
|
|
32
|
+
evm: createLedgerEvmAdapter(session, config),
|
|
33
|
+
utxo: createLedgerUtxoAdapter(session),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=ledger-host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger-host.js","sourceRoot":"","sources":["../../src/ledger-host.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,OAAO,EACL,0BAA0B,GAE3B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAEhF,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAStD,MAAM,UAAU,mBAAmB,CACjC,SAA8B,EAAE;IAEhC,MAAM,SAAS,GACb,MAAM,CAAC,GAAG;QACV,IAAI,0BAA0B,EAAE;aAC7B,YAAY,CAAC,sBAAsB,CAAC;aACpC,KAAK,EAAE,CAAC;IACb,KAAK,MAAM,MAAM,IAAI;QACnB,SAAS;QACT,YAAY;QACZ,qBAAqB;QACrB,kBAAkB;QAClB,0BAA0B;QAC1B,uBAAuB;KACxB,EAAE,CAAC;QACF,IAAI,OAAQ,SAAqC,CAAC,MAAM,CAAC,KAAK,UAAU;YACtE,MAAM,eAAe,CACnB,qBAAqB,EACrB,+BAA+B,CAChC,CAAC;IACN,CAAC;IACD,6EAA6E;IAC7E,4EAA4E;IAC5E,MAAM,GAAG,GAAG,SAAgC,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAC1C,OAAO;QACL,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC;QAChE,UAAU,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE;QACtC,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE;QACpC,GAAG,EAAE,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC;QAC5C,IAAI,EAAE,uBAAuB,CAAC,OAAO,CAAC;KACvC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
export const MAX_PRIVATE_RECORD_BYTES = 64 * 1024;
|
|
2
|
+
export const MAX_PRIVATE_RECORD_LABEL_BYTES = 128;
|
|
3
|
+
const NAMESPACE = 'sysweb3/private-record/v1';
|
|
4
|
+
const NONCE_BYTES = 12;
|
|
5
|
+
const TAG_BYTES = 16;
|
|
6
|
+
const encoder = new TextEncoder();
|
|
7
|
+
const LABEL_START = /^[A-Za-z0-9]/;
|
|
8
|
+
const INVALID_LABEL_CHARACTER = /[^A-Za-z0-9._:/-]/;
|
|
9
|
+
const PROFILE = /^0x[0-9a-f]{64}$/;
|
|
10
|
+
const BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
|
11
|
+
// Views passed to WebCrypto are owned, non-shared copies. This cast supports
|
|
12
|
+
// DOM typings both before and after generic ArrayBufferLike typed arrays.
|
|
13
|
+
const bufferSource = (bytes) => bytes;
|
|
14
|
+
function cryptoProvider() {
|
|
15
|
+
if (!globalThis.crypto?.subtle || !globalThis.crypto.getRandomValues) {
|
|
16
|
+
throw new Error('Private record cryptography unavailable');
|
|
17
|
+
}
|
|
18
|
+
return globalThis.crypto;
|
|
19
|
+
}
|
|
20
|
+
function label(value) {
|
|
21
|
+
if (typeof value !== 'string' ||
|
|
22
|
+
value.length > MAX_PRIVATE_RECORD_LABEL_BYTES ||
|
|
23
|
+
!LABEL_START.test(value) ||
|
|
24
|
+
INVALID_LABEL_CHARACTER.test(value)) {
|
|
25
|
+
throw new Error('Invalid private record context');
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
function encodeBase64(bytes) {
|
|
30
|
+
return Buffer.from(bytes).toString('base64');
|
|
31
|
+
}
|
|
32
|
+
function decodeBase64(value, min, max) {
|
|
33
|
+
if (typeof value !== 'string' ||
|
|
34
|
+
value.length > 4 * Math.ceil(max / 3) ||
|
|
35
|
+
!BASE64.test(value)) {
|
|
36
|
+
throw new Error('Invalid private record envelope');
|
|
37
|
+
}
|
|
38
|
+
const bytes = new Uint8Array(Buffer.from(value, 'base64'));
|
|
39
|
+
if (bytes.length < min ||
|
|
40
|
+
bytes.length > max ||
|
|
41
|
+
encodeBase64(bytes) !== value) {
|
|
42
|
+
throw new Error('Invalid private record envelope');
|
|
43
|
+
}
|
|
44
|
+
return bytes;
|
|
45
|
+
}
|
|
46
|
+
async function importRoot(secret, guard) {
|
|
47
|
+
const key = await cryptoProvider().subtle.importKey('raw', bufferSource(secret), 'HKDF', false, ['deriveBits', 'deriveKey']);
|
|
48
|
+
guard();
|
|
49
|
+
return key;
|
|
50
|
+
}
|
|
51
|
+
async function profileId(key, guard) {
|
|
52
|
+
const bits = await cryptoProvider().subtle.deriveBits({
|
|
53
|
+
name: 'HKDF',
|
|
54
|
+
hash: 'SHA-256',
|
|
55
|
+
salt: bufferSource(encoder.encode(NAMESPACE)),
|
|
56
|
+
info: bufferSource(encoder.encode(JSON.stringify([NAMESPACE, 'profile-id']))),
|
|
57
|
+
}, key, 256);
|
|
58
|
+
guard();
|
|
59
|
+
return `0x${Buffer.from(bits).toString('hex')}`;
|
|
60
|
+
}
|
|
61
|
+
async function domainKey(key, domain, guard) {
|
|
62
|
+
const derived = await cryptoProvider().subtle.deriveKey({
|
|
63
|
+
name: 'HKDF',
|
|
64
|
+
hash: 'SHA-256',
|
|
65
|
+
salt: bufferSource(encoder.encode(NAMESPACE)),
|
|
66
|
+
info: bufferSource(encoder.encode(JSON.stringify([NAMESPACE, 'encryption-key', domain]))),
|
|
67
|
+
}, key, { name: 'AES-GCM', length: 256 }, false, ['encrypt', 'decrypt']);
|
|
68
|
+
guard();
|
|
69
|
+
return derived;
|
|
70
|
+
}
|
|
71
|
+
function additionalData(domain, recordId, profile) {
|
|
72
|
+
return encoder.encode(JSON.stringify([NAMESPACE, 1, domain, recordId, profile]));
|
|
73
|
+
}
|
|
74
|
+
// Internal helpers accept ephemeral bytes and never access wallet storage.
|
|
75
|
+
// Only the envelope types and limits are exported from the package entrypoint.
|
|
76
|
+
export async function privateRecordProfileId(secret, guard) {
|
|
77
|
+
return profileId(await importRoot(secret, guard), guard);
|
|
78
|
+
}
|
|
79
|
+
export async function encryptPrivateRecordBytes(secret, params, guard) {
|
|
80
|
+
const domain = label(params.domain);
|
|
81
|
+
const recordId = label(params.recordId);
|
|
82
|
+
if (!(params.plaintext instanceof Uint8Array) ||
|
|
83
|
+
params.plaintext.length > MAX_PRIVATE_RECORD_BYTES) {
|
|
84
|
+
throw new Error('Invalid private record size');
|
|
85
|
+
}
|
|
86
|
+
// Own the input before the first await; caller mutations cannot change it.
|
|
87
|
+
const plaintext = new Uint8Array(params.plaintext);
|
|
88
|
+
try {
|
|
89
|
+
const key = await importRoot(secret, guard);
|
|
90
|
+
const profile = await profileId(key, guard);
|
|
91
|
+
const aesKey = await domainKey(key, domain, guard);
|
|
92
|
+
const nonce = cryptoProvider().getRandomValues(new Uint8Array(NONCE_BYTES));
|
|
93
|
+
const encrypted = await cryptoProvider().subtle.encrypt({
|
|
94
|
+
name: 'AES-GCM',
|
|
95
|
+
iv: bufferSource(nonce),
|
|
96
|
+
tagLength: 128,
|
|
97
|
+
additionalData: bufferSource(additionalData(domain, recordId, profile)),
|
|
98
|
+
}, aesKey, bufferSource(plaintext));
|
|
99
|
+
guard();
|
|
100
|
+
return {
|
|
101
|
+
version: 1,
|
|
102
|
+
domain,
|
|
103
|
+
recordId,
|
|
104
|
+
profileId: profile,
|
|
105
|
+
nonce: encodeBase64(nonce),
|
|
106
|
+
ciphertext: encodeBase64(new Uint8Array(encrypted)),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
plaintext.fill(0);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
export async function decryptPrivateRecordBytes(secret, params, guard) {
|
|
114
|
+
const domain = label(params.domain);
|
|
115
|
+
const recordId = label(params.recordId);
|
|
116
|
+
// Copy primitive fields before awaiting. No caller-owned object is retained.
|
|
117
|
+
const envelope = params.envelope && { ...params.envelope };
|
|
118
|
+
if (!envelope ||
|
|
119
|
+
Object.keys(envelope).length !== 6 ||
|
|
120
|
+
envelope.version !== 1 ||
|
|
121
|
+
envelope.domain !== domain ||
|
|
122
|
+
envelope.recordId !== recordId ||
|
|
123
|
+
typeof envelope.profileId !== 'string' ||
|
|
124
|
+
envelope.profileId.length !== 66 ||
|
|
125
|
+
!PROFILE.test(envelope.profileId)) {
|
|
126
|
+
throw new Error('Invalid private record envelope');
|
|
127
|
+
}
|
|
128
|
+
const nonce = decodeBase64(envelope.nonce, NONCE_BYTES, NONCE_BYTES);
|
|
129
|
+
const ciphertext = decodeBase64(envelope.ciphertext, TAG_BYTES, MAX_PRIVATE_RECORD_BYTES + TAG_BYTES);
|
|
130
|
+
const key = await importRoot(secret, guard);
|
|
131
|
+
const profile = await profileId(key, guard);
|
|
132
|
+
if (profile !== envelope.profileId) {
|
|
133
|
+
throw new Error('Private record profile mismatch');
|
|
134
|
+
}
|
|
135
|
+
const aesKey = await domainKey(key, domain, guard);
|
|
136
|
+
let plaintext;
|
|
137
|
+
try {
|
|
138
|
+
plaintext = new Uint8Array(await cryptoProvider().subtle.decrypt({
|
|
139
|
+
name: 'AES-GCM',
|
|
140
|
+
iv: bufferSource(nonce),
|
|
141
|
+
tagLength: 128,
|
|
142
|
+
additionalData: bufferSource(additionalData(domain, recordId, profile)),
|
|
143
|
+
}, aesKey, bufferSource(ciphertext)));
|
|
144
|
+
guard();
|
|
145
|
+
return plaintext;
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
plaintext?.fill(0);
|
|
149
|
+
guard();
|
|
150
|
+
throw new Error('Private record authentication failed');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=private-records.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"private-records.js","sourceRoot":"","sources":["../../src/private-records.ts"],"names":[],"mappings":"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"}
|