@metamask/eth-ledger-bridge-keyring 0.14.0 → 1.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 ADDED
@@ -0,0 +1,81 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [1.0.0]
10
+ ### Changed
11
+ - **BREAKING:** Separate the bridge from the keyring ([#156](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/156))
12
+ - The Ledger bridge is now a separate class (`LedgerIframeBridge`), which must be constructed separately from the keyring and passed in as a constructor argument.
13
+ - The bridge initialization has been moved from the keyring constructor to the keyring `init` method. The bridge is expected to be passed to the keyring uninitialized, and the keyring `init` method is expected to be called after keyring construction (before the keyring is used).
14
+ - The keyring constructor no longer accepts keyring state. Instead, any pre-existing keyring state should be passed to the `deserialize` method after construction.
15
+ - **BREAKING:** Export changed from default to named ([#174](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/174))
16
+ - The keyring is exported as `LedgerKeyring`
17
+ - Add TypeScript types ([#174](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/174))
18
+
19
+ ## [0.15.0]
20
+ ### Changed
21
+ - **BREAKING:** @ethereumjs/tx upgraded to major version 4, which includes a shift from storing numerical values as BNs to storing them as native BigInts. This is a breaking change for users of this keyring who access the values of the tx object, or that use those tx objects to interact with other libraries that depend on @ethereumsjs/tx versions under 4.0.0. ([#181](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/181))
22
+
23
+ ## [0.14.0]
24
+ ### Changed
25
+ - **BREAKING:** The minimum version of Node.js required for this package has been bumped to v14. ([#169](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/169))
26
+
27
+ ### Fixed
28
+ - Fix incorrect `v` for EIP-712 signatures and `personal_sign` ([#152](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/152))
29
+
30
+ ## [0.13.0]
31
+ ### Added
32
+ - hdk.publicKey and hdk.chainCode should not be updated when unlocking using hdPath for an account. ([#146](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/146))
33
+
34
+ ## [0.12.0]
35
+ ### Added
36
+ - Add a new `destroy` method which will remove the `message` event listener from window. ([#145](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/145))
37
+
38
+ ## [0.11.0]
39
+ ### Added
40
+ - Add a new `isConnected` method which allows determining if the device is last known to be connected. ([#131](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/131))
41
+
42
+ ### Changed
43
+ - Messaging now runs off of message IDs instead of assuming the response received is from the last message sent, which will not always been true. ([#132](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/132))
44
+
45
+ ## [0.10.0]
46
+ ### Added
47
+ - Add a new `attemptMakeApp` method which allows clients to attempt a creation of the Ledger transport for the purposes of detecting/catching potential connection errors. ([#126](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/126))
48
+
49
+ ## [0.9.0]
50
+ ### Changed
51
+ - `updateTransportMethod` no longer defaults its parameter to false, and now names the param sent with the `'ledger-update-transport'` message `transportType`. This better is to support the use of an enum, instead of a boolean, for specifying transport preferences. ([#114](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/114))
52
+
53
+ ## [0.8.0]
54
+ ### Added
55
+ - Allow ledger-bridge iframe to connect Ledger wia WebHID, when it is supported by the current browser ([#107](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/107))
56
+
57
+ ### Changed
58
+ - Reject with an Error object if unlocking is not successful ([#104](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/104))
59
+ - Ensure that logs of errors only have a single `Error:` string in the message ([#105](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/105))
60
+
61
+ ## [0.7.0]
62
+ ### Changed
63
+ - Remove unused `events` and `ethereumjs-tx` dependencies ([#101](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/101), [#102](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/102))
64
+ - Update eth-ledger-bridge-keyring to support EIP-1559 transactions ([#98](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/98), [#97](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/97), [#96](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/96))
65
+
66
+ ## [0.6.0]
67
+ ### Added
68
+ - Support new versions of ethereumjs/tx ([#68](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/68))
69
+
70
+ [Unreleased]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v1.0.0...HEAD
71
+ [1.0.0]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v0.15.0...v1.0.0
72
+ [0.15.0]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v0.14.0...v0.15.0
73
+ [0.14.0]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v0.13.0...v0.14.0
74
+ [0.13.0]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v0.12.0...v0.13.0
75
+ [0.12.0]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v0.11.0...v0.12.0
76
+ [0.11.0]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v0.10.0...v0.11.0
77
+ [0.10.0]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v0.9.0...v0.10.0
78
+ [0.9.0]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v0.8.0...v0.9.0
79
+ [0.8.0]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v0.7.0...v0.8.0
80
+ [0.7.0]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v0.6.0...v0.7.0
81
+ [0.6.0]: https://github.com/MetaMask/eth-ledger-bridge-keyring/releases/tag/v0.6.0
package/README.md CHANGED
@@ -1,5 +1,4 @@
1
- eth-ledger-bridge-keyring [![CircleCI](https://circleci.com/gh/MetaMask/eth-ledger-bridge-keyring.svg?style=svg)](https://circleci.com/gh/MetaMask/eth-ledger-bridge-keyring)
2
- ==================
1
+ # eth-ledger-bridge-keyring [![CircleCI](https://circleci.com/gh/MetaMask/eth-ledger-bridge-keyring.svg?style=svg)](https://circleci.com/gh/MetaMask/eth-ledger-bridge-keyring)
3
2
 
4
3
  An implementation of MetaMask's [Keyring interface](https://github.com/MetaMask/eth-simple-keyring#the-keyring-class-protocol), that uses a Ledger hardware wallet for all cryptographic operations.
5
4
 
@@ -16,17 +15,15 @@ device. However there are a number of differences:
16
15
 
17
16
  - Because extensions have limited access to browser features, there's no easy way to interact wth the Ledger Hardware wallet from the MetaMask extension. This library implements a workaround to those restrictions by injecting (on demand) an iframe to the background page of the extension, (which is hosted [here](https://metamask.github.io/eth-ledger-bridge-keyring/index.html).
18
17
 
19
- The iframe is allowed to interact with the Ledger device (since U2F requires SSL and the iframe is hosted under https) using the libraries from [LedgerJS](https://github.com/LedgerHQ/ledgerjs) *hw-app-eth* and *hw-transport-u2f* and establishes a two-way communication channel with the extension via postMessage.
18
+ The iframe is allowed to interact with the Ledger device (since U2F requires SSL and the iframe is hosted under https) using the libraries from [LedgerJS](https://github.com/LedgerHQ/ledgerjs) _hw-app-eth_ and _hw-transport-u2f_ and establishes a two-way communication channel with the extension via postMessage.
20
19
 
21
20
  The iframe code it's hosted in the same repo under the branch [gh-pages](https://github.com/MetaMask/eth-ledger-bridge-keyring/tree/gh-pages) and it's being served via github pages. In the future we might move it under the metamask.io domain.
22
21
 
23
- Usage
24
- -----
22
+ ## Usage
25
23
 
26
24
  In addition to all the known methods from the [Keyring class protocol](https://github.com/MetaMask/eth-simple-keyring#the-keyring-class-protocol),
27
25
  there are a few others:
28
26
 
29
-
30
27
  - **isUnlocked** : Returns true if we have the public key in memory, which allows to generate the list of accounts at any time
31
28
 
32
29
  - **unlock** : Connects to the Ledger device and exports the extended public key, which is later used to read the available ethereum addresses inside the Ledger account.
@@ -41,16 +38,12 @@ there are a few others:
41
38
 
42
39
  - **forgetDevice** : removes all the device info from memory so the next interaction with the keyring will prompt the user to connect the Ledger device and export the account information
43
40
 
44
- Testing
45
- -------
46
- Run the following command:
41
+ ## Testing and Linting
47
42
 
48
- ```bash
49
- yarn test
50
- ```
43
+ Run `yarn test` to run the tests once. To run tests on file changes, run `yarn test:watch`.
51
44
 
45
+ Run `yarn lint` to run the linter, or run `yarn lint:fix` to run the linter and fix any automatically fixable issues.
52
46
 
47
+ ## Attributions
53
48
 
54
- Attributions
55
- -------
56
49
  This code was inspired by [eth-ledger-keyring](https://github.com/jamespic/eth-ledger-keyring) and [eth-hd-keyring](https://github.com/MetaMask/eth-hd-keyring)
@@ -0,0 +1,3 @@
1
+ export * from './ledger-keyring';
2
+ export * from './ledger-iframe-bridge';
3
+ export * from './ledger-bridge';
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./ledger-keyring"), exports);
18
+ __exportStar(require("./ledger-iframe-bridge"), exports);
19
+ __exportStar(require("./ledger-bridge"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mDAAiC;AACjC,yDAAuC;AACvC,kDAAgC","sourcesContent":["export * from './ledger-keyring';\nexport * from './ledger-iframe-bridge';\nexport * from './ledger-bridge';\n"]}
@@ -0,0 +1,34 @@
1
+ import type LedgerHwAppEth from '@ledgerhq/hw-app-eth';
2
+ export declare type GetPublicKeyParams = {
3
+ hdPath: string;
4
+ };
5
+ export declare type GetPublicKeyResponse = Awaited<ReturnType<LedgerHwAppEth['getAddress']>> & {
6
+ chainCode: string;
7
+ };
8
+ export declare type LedgerSignTransactionParams = {
9
+ hdPath: string;
10
+ tx: string;
11
+ };
12
+ export declare type LedgerSignTransactionResponse = Awaited<ReturnType<LedgerHwAppEth['signTransaction']>>;
13
+ export declare type LedgerSignMessageParams = {
14
+ hdPath: string;
15
+ message: string;
16
+ };
17
+ export declare type LedgerSignMessageResponse = Awaited<ReturnType<LedgerHwAppEth['signPersonalMessage']>>;
18
+ export declare type LedgerSignTypedDataParams = {
19
+ hdPath: string;
20
+ domainSeparatorHex: string;
21
+ hashStructMessageHex: string;
22
+ };
23
+ export declare type LedgerSignTypedDataResponse = Awaited<ReturnType<LedgerHwAppEth['signEIP712HashedMessage']>>;
24
+ export interface LedgerBridge {
25
+ isDeviceConnected: boolean;
26
+ init(bridgeUrl: string): Promise<void>;
27
+ destroy(): Promise<void>;
28
+ attemptMakeApp(): Promise<boolean>;
29
+ updateTransportMethod(transportType: string): Promise<boolean>;
30
+ getPublicKey(params: GetPublicKeyParams): Promise<GetPublicKeyResponse>;
31
+ deviceSignTransaction(params: LedgerSignTransactionParams): Promise<LedgerSignTransactionResponse>;
32
+ deviceSignMessage(params: LedgerSignMessageParams): Promise<LedgerSignMessageResponse>;
33
+ deviceSignTypedData(params: LedgerSignTypedDataParams): Promise<LedgerSignTypedDataResponse>;
34
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=ledger-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger-bridge.js","sourceRoot":"","sources":["../src/ledger-bridge.ts"],"names":[],"mappings":"","sourcesContent":["import type LedgerHwAppEth from '@ledgerhq/hw-app-eth';\n\nexport type GetPublicKeyParams = { hdPath: string };\nexport type GetPublicKeyResponse = Awaited<\n ReturnType<LedgerHwAppEth['getAddress']>\n> & {\n chainCode: string;\n};\n\nexport type LedgerSignTransactionParams = { hdPath: string; tx: string };\nexport type LedgerSignTransactionResponse = Awaited<\n ReturnType<LedgerHwAppEth['signTransaction']>\n>;\n\nexport type LedgerSignMessageParams = { hdPath: string; message: string };\nexport type LedgerSignMessageResponse = Awaited<\n ReturnType<LedgerHwAppEth['signPersonalMessage']>\n>;\n\nexport type LedgerSignTypedDataParams = {\n hdPath: string;\n domainSeparatorHex: string;\n hashStructMessageHex: string;\n};\nexport type LedgerSignTypedDataResponse = Awaited<\n ReturnType<LedgerHwAppEth['signEIP712HashedMessage']>\n>;\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface LedgerBridge {\n isDeviceConnected: boolean;\n\n init(bridgeUrl: string): Promise<void>;\n\n destroy(): Promise<void>;\n\n attemptMakeApp(): Promise<boolean>;\n\n updateTransportMethod(transportType: string): Promise<boolean>;\n\n getPublicKey(params: GetPublicKeyParams): Promise<GetPublicKeyResponse>;\n\n deviceSignTransaction(\n params: LedgerSignTransactionParams,\n ): Promise<LedgerSignTransactionResponse>;\n\n deviceSignMessage(\n params: LedgerSignMessageParams,\n ): Promise<LedgerSignMessageResponse>;\n\n deviceSignTypedData(\n params: LedgerSignTypedDataParams,\n ): Promise<LedgerSignTypedDataResponse>;\n}\n"]}
@@ -0,0 +1,85 @@
1
+ import { GetPublicKeyParams, GetPublicKeyResponse, LedgerBridge, LedgerSignMessageParams, LedgerSignMessageResponse, LedgerSignTransactionParams, LedgerSignTransactionResponse, LedgerSignTypedDataParams, LedgerSignTypedDataResponse } from './ledger-bridge';
2
+ export declare enum IFrameMessageAction {
3
+ LedgerConnectionChange = "ledger-connection-change",
4
+ LedgerUnlock = "ledger-unlock",
5
+ LedgerMakeApp = "ledger-make-app",
6
+ LedgerUpdateTransport = "ledger-update-transport",
7
+ LedgerSignTransaction = "ledger-sign-transaction",
8
+ LedgerSignPersonalMessage = "ledger-sign-personal-message",
9
+ LedgerSignTypedData = "ledger-sign-typed-data"
10
+ }
11
+ declare type IFrameMessageResponse<TAction extends IFrameMessageAction> = {
12
+ action: TAction;
13
+ messageId: number;
14
+ } & ({
15
+ action: IFrameMessageAction.LedgerConnectionChange;
16
+ payload: {
17
+ connected: boolean;
18
+ };
19
+ } | ({
20
+ action: IFrameMessageAction.LedgerMakeApp;
21
+ } & ({
22
+ success: true;
23
+ } | {
24
+ success: false;
25
+ error?: unknown;
26
+ })) | {
27
+ action: IFrameMessageAction.LedgerUpdateTransport;
28
+ success: boolean;
29
+ } | ({
30
+ action: IFrameMessageAction.LedgerUnlock;
31
+ } & ({
32
+ success: true;
33
+ payload: GetPublicKeyResponse;
34
+ } | {
35
+ success: false;
36
+ payload: {
37
+ error: Error;
38
+ };
39
+ })) | ({
40
+ action: IFrameMessageAction.LedgerSignTransaction;
41
+ } & ({
42
+ success: true;
43
+ payload: LedgerSignTransactionResponse;
44
+ } | {
45
+ success: false;
46
+ payload: {
47
+ error: Error;
48
+ };
49
+ })) | ({
50
+ action: IFrameMessageAction.LedgerSignPersonalMessage | IFrameMessageAction.LedgerSignTypedData;
51
+ } & ({
52
+ success: true;
53
+ payload: LedgerSignMessageResponse | LedgerSignTypedDataResponse;
54
+ } | {
55
+ success: false;
56
+ payload: {
57
+ error: Error;
58
+ };
59
+ })));
60
+ export declare class LedgerIframeBridge implements LedgerBridge {
61
+ #private;
62
+ iframe?: HTMLIFrameElement;
63
+ iframeLoaded: boolean;
64
+ eventListener?: (eventMessage: {
65
+ origin: string;
66
+ data: IFrameMessageResponse<IFrameMessageAction>;
67
+ }) => void;
68
+ isDeviceConnected: boolean;
69
+ currentMessageId: number;
70
+ messageCallbacks: Record<number, (response: IFrameMessageResponse<IFrameMessageAction>) => void>;
71
+ delayedPromise?: {
72
+ resolve: (value: boolean) => void;
73
+ reject: (error: unknown) => void;
74
+ transportType: string;
75
+ };
76
+ init(bridgeUrl: string): Promise<void>;
77
+ destroy(): Promise<void>;
78
+ attemptMakeApp(): Promise<boolean>;
79
+ updateTransportMethod(transportType: string): Promise<boolean>;
80
+ getPublicKey(params: GetPublicKeyParams): Promise<GetPublicKeyResponse>;
81
+ deviceSignTransaction(params: LedgerSignTransactionParams): Promise<LedgerSignTransactionResponse>;
82
+ deviceSignMessage(params: LedgerSignMessageParams): Promise<LedgerSignMessageResponse>;
83
+ deviceSignTypedData(params: LedgerSignTypedDataParams): Promise<LedgerSignTypedDataResponse>;
84
+ }
85
+ export {};
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var _LedgerIframeBridge_instances, _LedgerIframeBridge_deviceActionMessage, _LedgerIframeBridge_setupIframe, _LedgerIframeBridge_getOrigin, _LedgerIframeBridge_eventListener, _LedgerIframeBridge_sendMessage;
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.LedgerIframeBridge = exports.IFrameMessageAction = void 0;
10
+ const LEDGER_IFRAME_ID = 'LEDGER-IFRAME';
11
+ var IFrameMessageAction;
12
+ (function (IFrameMessageAction) {
13
+ IFrameMessageAction["LedgerConnectionChange"] = "ledger-connection-change";
14
+ IFrameMessageAction["LedgerUnlock"] = "ledger-unlock";
15
+ IFrameMessageAction["LedgerMakeApp"] = "ledger-make-app";
16
+ IFrameMessageAction["LedgerUpdateTransport"] = "ledger-update-transport";
17
+ IFrameMessageAction["LedgerSignTransaction"] = "ledger-sign-transaction";
18
+ IFrameMessageAction["LedgerSignPersonalMessage"] = "ledger-sign-personal-message";
19
+ IFrameMessageAction["LedgerSignTypedData"] = "ledger-sign-typed-data";
20
+ })(IFrameMessageAction = exports.IFrameMessageAction || (exports.IFrameMessageAction = {}));
21
+ class LedgerIframeBridge {
22
+ constructor() {
23
+ _LedgerIframeBridge_instances.add(this);
24
+ this.iframeLoaded = false;
25
+ this.isDeviceConnected = false;
26
+ this.currentMessageId = 0;
27
+ this.messageCallbacks = {};
28
+ }
29
+ async init(bridgeUrl) {
30
+ __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_setupIframe).call(this, bridgeUrl);
31
+ this.eventListener = __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_eventListener).bind(this, bridgeUrl);
32
+ window.addEventListener('message', this.eventListener);
33
+ }
34
+ async destroy() {
35
+ if (this.eventListener) {
36
+ window.removeEventListener('message', this.eventListener);
37
+ }
38
+ }
39
+ async attemptMakeApp() {
40
+ return new Promise((resolve, reject) => {
41
+ __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_sendMessage).call(this, {
42
+ action: IFrameMessageAction.LedgerMakeApp,
43
+ }, (response) => {
44
+ if (response.success) {
45
+ resolve(true);
46
+ }
47
+ else {
48
+ reject(response.error);
49
+ }
50
+ });
51
+ });
52
+ }
53
+ async updateTransportMethod(transportType) {
54
+ return new Promise((resolve, reject) => {
55
+ // If the iframe isn't loaded yet, let's store the desired transportType value and
56
+ // optimistically return a successful promise
57
+ if (!this.iframeLoaded) {
58
+ this.delayedPromise = {
59
+ resolve,
60
+ reject,
61
+ transportType,
62
+ };
63
+ return;
64
+ }
65
+ __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_sendMessage).call(this, {
66
+ action: IFrameMessageAction.LedgerUpdateTransport,
67
+ params: { transportType },
68
+ }, ({ success }) => {
69
+ if (success) {
70
+ return resolve(true);
71
+ }
72
+ return reject(new Error('Ledger transport could not be updated'));
73
+ });
74
+ });
75
+ }
76
+ async getPublicKey(params) {
77
+ return __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_deviceActionMessage).call(this, IFrameMessageAction.LedgerUnlock, params);
78
+ }
79
+ async deviceSignTransaction(params) {
80
+ return __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_deviceActionMessage).call(this, IFrameMessageAction.LedgerSignTransaction, params);
81
+ }
82
+ async deviceSignMessage(params) {
83
+ return __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_deviceActionMessage).call(this, IFrameMessageAction.LedgerSignPersonalMessage, params);
84
+ }
85
+ async deviceSignTypedData(params) {
86
+ return __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_deviceActionMessage).call(this, IFrameMessageAction.LedgerSignTypedData, params);
87
+ }
88
+ }
89
+ exports.LedgerIframeBridge = LedgerIframeBridge;
90
+ _LedgerIframeBridge_instances = new WeakSet(), _LedgerIframeBridge_deviceActionMessage = async function _LedgerIframeBridge_deviceActionMessage(...[action, params]) {
91
+ return new Promise((resolve, reject) => {
92
+ __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_sendMessage).call(this, {
93
+ action,
94
+ params,
95
+ }, ({ success, payload }) => {
96
+ if (success) {
97
+ return resolve(payload);
98
+ }
99
+ return reject(payload.error);
100
+ });
101
+ });
102
+ }, _LedgerIframeBridge_setupIframe = function _LedgerIframeBridge_setupIframe(bridgeUrl) {
103
+ this.iframe = document.createElement('iframe');
104
+ this.iframe.src = bridgeUrl;
105
+ this.iframe.allow = `hid 'src'`;
106
+ this.iframe.onload = async () => {
107
+ // If the ledger live preference was set before the iframe is loaded,
108
+ // set it after the iframe has loaded
109
+ this.iframeLoaded = true;
110
+ if (this.delayedPromise) {
111
+ try {
112
+ const result = await this.updateTransportMethod(this.delayedPromise.transportType);
113
+ this.delayedPromise.resolve(result);
114
+ }
115
+ catch (error) {
116
+ this.delayedPromise.reject(error);
117
+ }
118
+ finally {
119
+ delete this.delayedPromise;
120
+ }
121
+ }
122
+ };
123
+ document.head.appendChild(this.iframe);
124
+ }, _LedgerIframeBridge_getOrigin = function _LedgerIframeBridge_getOrigin(bridgeUrl) {
125
+ const tmp = bridgeUrl.split('/');
126
+ tmp.splice(-1, 1);
127
+ return tmp.join('/');
128
+ }, _LedgerIframeBridge_eventListener = function _LedgerIframeBridge_eventListener(bridgeUrl, eventMessage) {
129
+ if (eventMessage.origin !== __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_getOrigin).call(this, bridgeUrl)) {
130
+ return;
131
+ }
132
+ if (eventMessage.data) {
133
+ const messageCallback = this.messageCallbacks[eventMessage.data.messageId];
134
+ if (messageCallback) {
135
+ messageCallback(eventMessage.data);
136
+ }
137
+ else if (eventMessage.data.action === IFrameMessageAction.LedgerConnectionChange) {
138
+ this.isDeviceConnected = eventMessage.data.payload.connected;
139
+ }
140
+ }
141
+ }, _LedgerIframeBridge_sendMessage = function _LedgerIframeBridge_sendMessage(message, callback) {
142
+ this.currentMessageId += 1;
143
+ const postMsg = Object.assign(Object.assign({}, message), { messageId: this.currentMessageId, target: LEDGER_IFRAME_ID });
144
+ this.messageCallbacks[this.currentMessageId] = callback;
145
+ if (!this.iframeLoaded || !this.iframe || !this.iframe.contentWindow) {
146
+ throw new Error('The iframe is not loaded yet');
147
+ }
148
+ this.iframe.contentWindow.postMessage(postMsg, '*');
149
+ };
150
+ //# sourceMappingURL=ledger-iframe-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger-iframe-bridge.js","sourceRoot":"","sources":["../src/ledger-iframe-bridge.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n GetPublicKeyParams,\n GetPublicKeyResponse,\n LedgerBridge,\n LedgerSignMessageParams,\n LedgerSignMessageResponse,\n LedgerSignTransactionParams,\n LedgerSignTransactionResponse,\n LedgerSignTypedDataParams,\n LedgerSignTypedDataResponse,\n} from './ledger-bridge';\n\nconst LEDGER_IFRAME_ID = 'LEDGER-IFRAME';\n\nexport enum IFrameMessageAction {\n LedgerConnectionChange = 'ledger-connection-change',\n LedgerUnlock = 'ledger-unlock',\n LedgerMakeApp = 'ledger-make-app',\n LedgerUpdateTransport = 'ledger-update-transport',\n LedgerSignTransaction = 'ledger-sign-transaction',\n LedgerSignPersonalMessage = 'ledger-sign-personal-message',\n LedgerSignTypedData = 'ledger-sign-typed-data',\n}\n\ntype IFrameMessageResponse<TAction extends IFrameMessageAction> = {\n action: TAction;\n messageId: number;\n} & (\n | {\n action: IFrameMessageAction.LedgerConnectionChange;\n payload: { connected: boolean };\n }\n | ({\n action: IFrameMessageAction.LedgerMakeApp;\n } & ({ success: true } | { success: false; error?: unknown }))\n | {\n action: IFrameMessageAction.LedgerUpdateTransport;\n success: boolean;\n }\n | ({\n action: IFrameMessageAction.LedgerUnlock;\n } & (\n | { success: true; payload: GetPublicKeyResponse }\n | { success: false; payload: { error: Error } }\n ))\n | ({\n action: IFrameMessageAction.LedgerSignTransaction;\n } & (\n | { success: true; payload: LedgerSignTransactionResponse }\n | { success: false; payload: { error: Error } }\n ))\n | ({\n action:\n | IFrameMessageAction.LedgerSignPersonalMessage\n | IFrameMessageAction.LedgerSignTypedData;\n } & (\n | {\n success: true;\n payload: LedgerSignMessageResponse | LedgerSignTypedDataResponse;\n }\n | { success: false; payload: { error: Error } }\n ))\n);\n\ntype IFrameMessage<TAction extends IFrameMessageAction> = {\n action: TAction;\n params?: Readonly<Record<string, unknown>>;\n};\n\ntype IFramePostMessage<TAction extends IFrameMessageAction> =\n IFrameMessage<TAction> & {\n messageId: number;\n target: typeof LEDGER_IFRAME_ID;\n };\n\nexport class LedgerIframeBridge implements LedgerBridge {\n iframe?: HTMLIFrameElement;\n\n iframeLoaded = false;\n\n eventListener?: (eventMessage: {\n origin: string;\n data: IFrameMessageResponse<IFrameMessageAction>;\n }) => void;\n\n isDeviceConnected = false;\n\n currentMessageId = 0;\n\n messageCallbacks: Record<\n number,\n (response: IFrameMessageResponse<IFrameMessageAction>) => void\n > = {};\n\n delayedPromise?: {\n resolve: (value: boolean) => void;\n reject: (error: unknown) => void;\n transportType: string;\n };\n\n async init(bridgeUrl: string) {\n this.#setupIframe(bridgeUrl);\n\n this.eventListener = this.#eventListener.bind(this, bridgeUrl);\n\n window.addEventListener('message', this.eventListener);\n }\n\n async destroy() {\n if (this.eventListener) {\n window.removeEventListener('message', this.eventListener);\n }\n }\n\n async attemptMakeApp(): Promise<boolean> {\n return new Promise((resolve, reject) => {\n this.#sendMessage(\n {\n action: IFrameMessageAction.LedgerMakeApp,\n },\n (response) => {\n if (response.success) {\n resolve(true);\n } else {\n reject(response.error);\n }\n },\n );\n });\n }\n\n async updateTransportMethod(transportType: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n // If the iframe isn't loaded yet, let's store the desired transportType value and\n // optimistically return a successful promise\n if (!this.iframeLoaded) {\n this.delayedPromise = {\n resolve,\n reject,\n transportType,\n };\n return;\n }\n\n this.#sendMessage(\n {\n action: IFrameMessageAction.LedgerUpdateTransport,\n params: { transportType },\n },\n ({ success }) => {\n if (success) {\n return resolve(true);\n }\n return reject(new Error('Ledger transport could not be updated'));\n },\n );\n });\n }\n\n async getPublicKey(\n params: GetPublicKeyParams,\n ): Promise<GetPublicKeyResponse> {\n return this.#deviceActionMessage(IFrameMessageAction.LedgerUnlock, params);\n }\n\n async deviceSignTransaction(\n params: LedgerSignTransactionParams,\n ): Promise<LedgerSignTransactionResponse> {\n return this.#deviceActionMessage(\n IFrameMessageAction.LedgerSignTransaction,\n params,\n );\n }\n\n async deviceSignMessage(\n params: LedgerSignMessageParams,\n ): Promise<LedgerSignMessageResponse> {\n return this.#deviceActionMessage(\n IFrameMessageAction.LedgerSignPersonalMessage,\n params,\n );\n }\n\n async deviceSignTypedData(\n params: LedgerSignTypedDataParams,\n ): Promise<LedgerSignTypedDataResponse> {\n return this.#deviceActionMessage(\n IFrameMessageAction.LedgerSignTypedData,\n params,\n );\n }\n\n async #deviceActionMessage(\n action: IFrameMessageAction.LedgerUnlock,\n params: GetPublicKeyParams,\n ): Promise<GetPublicKeyResponse>;\n\n async #deviceActionMessage(\n action: IFrameMessageAction.LedgerSignTransaction,\n params: LedgerSignTransactionParams,\n ): Promise<LedgerSignTransactionResponse>;\n\n async #deviceActionMessage(\n action: IFrameMessageAction.LedgerSignPersonalMessage,\n params: LedgerSignMessageParams,\n ): Promise<LedgerSignMessageResponse>;\n\n async #deviceActionMessage(\n action: IFrameMessageAction.LedgerSignTypedData,\n params: LedgerSignTypedDataParams,\n ): Promise<LedgerSignTypedDataResponse>;\n\n async #deviceActionMessage(\n ...[action, params]:\n | [IFrameMessageAction.LedgerUnlock, GetPublicKeyParams]\n | [IFrameMessageAction.LedgerSignTransaction, LedgerSignTransactionParams]\n | [IFrameMessageAction.LedgerSignPersonalMessage, LedgerSignMessageParams]\n | [IFrameMessageAction.LedgerSignTypedData, LedgerSignTypedDataParams]\n ) {\n return new Promise((resolve, reject) => {\n this.#sendMessage(\n {\n action,\n params,\n },\n ({ success, payload }) => {\n if (success) {\n return resolve(payload);\n }\n return reject(payload.error);\n },\n );\n });\n }\n\n #setupIframe(bridgeUrl: string) {\n this.iframe = document.createElement('iframe');\n this.iframe.src = bridgeUrl;\n this.iframe.allow = `hid 'src'`;\n this.iframe.onload = async () => {\n // If the ledger live preference was set before the iframe is loaded,\n // set it after the iframe has loaded\n this.iframeLoaded = true;\n if (this.delayedPromise) {\n try {\n const result = await this.updateTransportMethod(\n this.delayedPromise.transportType,\n );\n this.delayedPromise.resolve(result);\n } catch (error) {\n this.delayedPromise.reject(error);\n } finally {\n delete this.delayedPromise;\n }\n }\n };\n document.head.appendChild(this.iframe);\n }\n\n #getOrigin(bridgeUrl: string) {\n const tmp = bridgeUrl.split('/');\n tmp.splice(-1, 1);\n return tmp.join('/');\n }\n\n #eventListener(\n bridgeUrl: string,\n eventMessage: {\n origin: string;\n data: IFrameMessageResponse<IFrameMessageAction>;\n },\n ) {\n if (eventMessage.origin !== this.#getOrigin(bridgeUrl)) {\n return;\n }\n\n if (eventMessage.data) {\n const messageCallback =\n this.messageCallbacks[eventMessage.data.messageId];\n if (messageCallback) {\n messageCallback(eventMessage.data);\n } else if (\n eventMessage.data.action === IFrameMessageAction.LedgerConnectionChange\n ) {\n this.isDeviceConnected = eventMessage.data.payload.connected;\n }\n }\n }\n\n #sendMessage<TAction extends IFrameMessageAction>(\n message: IFrameMessage<TAction>,\n callback: (response: IFrameMessageResponse<TAction>) => void,\n ) {\n this.currentMessageId += 1;\n\n const postMsg: IFramePostMessage<TAction> = {\n ...message,\n messageId: this.currentMessageId,\n target: LEDGER_IFRAME_ID,\n };\n\n this.messageCallbacks[this.currentMessageId] = callback as (\n response: IFrameMessageResponse<IFrameMessageAction>,\n ) => void;\n\n if (!this.iframeLoaded || !this.iframe || !this.iframe.contentWindow) {\n throw new Error('The iframe is not loaded yet');\n }\n\n this.iframe.contentWindow.postMessage(postMsg, '*');\n }\n}\n"]}
@@ -0,0 +1,91 @@
1
+ /// <reference types="node" />
2
+ import { TypedTransaction } from '@ethereumjs/tx';
3
+ import * as sigUtil from 'eth-sig-util';
4
+ import type OldEthJsTransaction from 'ethereumjs-tx';
5
+ import { EventEmitter } from 'events';
6
+ import HDKey from 'hdkey';
7
+ import { LedgerBridge } from './ledger-bridge';
8
+ declare enum NetworkApiUrls {
9
+ Ropsten = "http://api-ropsten.etherscan.io",
10
+ Kovan = "http://api-kovan.etherscan.io",
11
+ Rinkeby = "https://api-rinkeby.etherscan.io",
12
+ Mainnet = "https://api.etherscan.io"
13
+ }
14
+ export declare type AccountDetails = {
15
+ index?: number;
16
+ bip44?: boolean;
17
+ hdPath?: string;
18
+ };
19
+ export declare type LedgerBridgeKeyringOptions = {
20
+ hdPath: string;
21
+ accounts: readonly string[];
22
+ accountDetails: Readonly<Record<string, AccountDetails>>;
23
+ accountIndexes: Readonly<Record<string, number>>;
24
+ bridgeUrl: string;
25
+ implementFullBIP44: boolean;
26
+ };
27
+ export declare class LedgerKeyring extends EventEmitter {
28
+ #private;
29
+ static type: string;
30
+ readonly type: string;
31
+ page: number;
32
+ perPage: number;
33
+ unlockedAccount: number;
34
+ accounts: readonly string[];
35
+ accountDetails: Record<string, AccountDetails>;
36
+ hdk: HDKey;
37
+ hdPath: string;
38
+ paths: Record<string, number>;
39
+ network: NetworkApiUrls;
40
+ implementFullBIP44: boolean;
41
+ bridgeUrl: string;
42
+ bridge: LedgerBridge;
43
+ constructor({ bridge }: {
44
+ bridge: LedgerBridge;
45
+ });
46
+ init(): Promise<void>;
47
+ destroy(): Promise<void>;
48
+ serialize(): Promise<{
49
+ hdPath: string;
50
+ accounts: readonly string[];
51
+ accountDetails: Record<string, AccountDetails>;
52
+ bridgeUrl: string;
53
+ implementFullBIP44: boolean;
54
+ }>;
55
+ deserialize(opts?: Partial<LedgerBridgeKeyringOptions>): Promise<void>;
56
+ isUnlocked(): boolean;
57
+ isConnected(): boolean;
58
+ setAccountToUnlock(index: number | string): void;
59
+ setHdPath(hdPath: string): void;
60
+ unlock(hdPath?: string, updateHdk?: boolean): Promise<string>;
61
+ addAccounts(amount?: number): Promise<string[]>;
62
+ getFirstPage(): Promise<{
63
+ address: string;
64
+ balance: number | null;
65
+ index: number;
66
+ }[]>;
67
+ getNextPage(): Promise<{
68
+ address: string;
69
+ balance: number | null;
70
+ index: number;
71
+ }[]>;
72
+ getPreviousPage(): Promise<{
73
+ address: string;
74
+ balance: number | null;
75
+ index: number;
76
+ }[]>;
77
+ getAccounts(): Promise<string[]>;
78
+ removeAccount(address: string): void;
79
+ attemptMakeApp(): Promise<boolean>;
80
+ updateTransportMethod(transportType: string): Promise<boolean>;
81
+ signTransaction(address: string, tx: TypedTransaction | OldEthJsTransaction): Promise<TypedTransaction | OldEthJsTransaction>;
82
+ signMessage(withAccount: string, data: string): Promise<string>;
83
+ signPersonalMessage(withAccount: string, message: string): Promise<string>;
84
+ unlockAccountByAddress(address: string): Promise<string | undefined>;
85
+ signTypedData(withAccount: string, data: sigUtil.EIP712TypedData, options?: {
86
+ version?: string;
87
+ }): Promise<string>;
88
+ exportAccount(): void;
89
+ forgetDevice(): void;
90
+ }
91
+ export {};