@metamask-previews/eth-ledger-bridge-keyring 4.1.1-672cc7b
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 +183 -0
- package/LICENSE +15 -0
- package/README.md +49 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/ledger-bridge.d.ts +44 -0
- package/dist/ledger-bridge.js +3 -0
- package/dist/ledger-bridge.js.map +1 -0
- package/dist/ledger-hw-app.d.ts +12 -0
- package/dist/ledger-hw-app.js +59 -0
- package/dist/ledger-hw-app.js.map +1 -0
- package/dist/ledger-iframe-bridge.d.ts +83 -0
- package/dist/ledger-iframe-bridge.js +174 -0
- package/dist/ledger-iframe-bridge.js.map +1 -0
- package/dist/ledger-keyring.d.ts +94 -0
- package/dist/ledger-keyring.js +526 -0
- package/dist/ledger-keyring.js.map +1 -0
- package/dist/ledger-mobile-bridge.d.ts +106 -0
- package/dist/ledger-mobile-bridge.js +173 -0
- package/dist/ledger-mobile-bridge.js.map +1 -0
- package/dist/ledger-transport-middleware.d.ts +39 -0
- package/dist/ledger-transport-middleware.js +64 -0
- package/dist/ledger-transport-middleware.js.map +1 -0
- package/dist/type.d.ts +5 -0
- package/dist/type.js +3 -0
- package/dist/type.js.map +1 -0
- package/package.json +88 -0
|
@@ -0,0 +1,174 @@
|
|
|
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 __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
8
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
11
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
12
|
+
};
|
|
13
|
+
var _LedgerIframeBridge_instances, _LedgerIframeBridge_opts, _LedgerIframeBridge_deviceActionMessage, _LedgerIframeBridge_setupIframe, _LedgerIframeBridge_getOrigin, _LedgerIframeBridge_eventListener, _LedgerIframeBridge_sendMessage, _LedgerIframeBridge_validateConfiguration;
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.LedgerIframeBridge = exports.IFrameMessageAction = void 0;
|
|
16
|
+
const LEDGER_IFRAME_ID = 'LEDGER-IFRAME';
|
|
17
|
+
var IFrameMessageAction;
|
|
18
|
+
(function (IFrameMessageAction) {
|
|
19
|
+
IFrameMessageAction["LedgerConnectionChange"] = "ledger-connection-change";
|
|
20
|
+
IFrameMessageAction["LedgerUnlock"] = "ledger-unlock";
|
|
21
|
+
IFrameMessageAction["LedgerMakeApp"] = "ledger-make-app";
|
|
22
|
+
IFrameMessageAction["LedgerUpdateTransport"] = "ledger-update-transport";
|
|
23
|
+
IFrameMessageAction["LedgerSignTransaction"] = "ledger-sign-transaction";
|
|
24
|
+
IFrameMessageAction["LedgerSignPersonalMessage"] = "ledger-sign-personal-message";
|
|
25
|
+
IFrameMessageAction["LedgerSignTypedData"] = "ledger-sign-typed-data";
|
|
26
|
+
})(IFrameMessageAction = exports.IFrameMessageAction || (exports.IFrameMessageAction = {}));
|
|
27
|
+
class LedgerIframeBridge {
|
|
28
|
+
constructor(opts = {
|
|
29
|
+
bridgeUrl: 'https://metamask.github.io/eth-ledger-bridge-keyring',
|
|
30
|
+
}) {
|
|
31
|
+
_LedgerIframeBridge_instances.add(this);
|
|
32
|
+
this.iframeLoaded = false;
|
|
33
|
+
_LedgerIframeBridge_opts.set(this, void 0);
|
|
34
|
+
this.isDeviceConnected = false;
|
|
35
|
+
this.currentMessageId = 0;
|
|
36
|
+
this.messageCallbacks = {};
|
|
37
|
+
__classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_validateConfiguration).call(this, opts);
|
|
38
|
+
__classPrivateFieldSet(this, _LedgerIframeBridge_opts, {
|
|
39
|
+
bridgeUrl: opts?.bridgeUrl,
|
|
40
|
+
}, "f");
|
|
41
|
+
}
|
|
42
|
+
async init() {
|
|
43
|
+
await __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_setupIframe).call(this, __classPrivateFieldGet(this, _LedgerIframeBridge_opts, "f").bridgeUrl);
|
|
44
|
+
this.eventListener = __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_eventListener).bind(this, __classPrivateFieldGet(this, _LedgerIframeBridge_opts, "f").bridgeUrl);
|
|
45
|
+
window.addEventListener('message', this.eventListener);
|
|
46
|
+
}
|
|
47
|
+
async destroy() {
|
|
48
|
+
if (this.eventListener) {
|
|
49
|
+
window.removeEventListener('message', this.eventListener);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async getOptions() {
|
|
53
|
+
return __classPrivateFieldGet(this, _LedgerIframeBridge_opts, "f");
|
|
54
|
+
}
|
|
55
|
+
async setOptions(opts) {
|
|
56
|
+
__classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_validateConfiguration).call(this, opts);
|
|
57
|
+
if (__classPrivateFieldGet(this, _LedgerIframeBridge_opts, "f")?.bridgeUrl !== opts.bridgeUrl) {
|
|
58
|
+
__classPrivateFieldGet(this, _LedgerIframeBridge_opts, "f").bridgeUrl = opts.bridgeUrl;
|
|
59
|
+
await this.destroy();
|
|
60
|
+
await this.init();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async attemptMakeApp() {
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
__classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_sendMessage).call(this, {
|
|
66
|
+
action: IFrameMessageAction.LedgerMakeApp,
|
|
67
|
+
}, (response) => {
|
|
68
|
+
if ('success' in response && response.success) {
|
|
69
|
+
resolve(true);
|
|
70
|
+
}
|
|
71
|
+
else if ('error' in response) {
|
|
72
|
+
reject(response.error);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
reject(new Error('Unknown error occurred'));
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
async updateTransportMethod(transportType) {
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
// If the iframe isn't loaded yet, let's store the desired transportType value and
|
|
83
|
+
// optimistically return a successful promise
|
|
84
|
+
if (!this.iframeLoaded) {
|
|
85
|
+
throw new Error('The iframe is not loaded yet');
|
|
86
|
+
}
|
|
87
|
+
__classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_sendMessage).call(this, {
|
|
88
|
+
action: IFrameMessageAction.LedgerUpdateTransport,
|
|
89
|
+
params: { transportType },
|
|
90
|
+
}, (response) => {
|
|
91
|
+
if ('success' in response && response.success) {
|
|
92
|
+
return resolve(true);
|
|
93
|
+
}
|
|
94
|
+
return reject(new Error('Ledger transport could not be updated'));
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
async getPublicKey(params) {
|
|
99
|
+
return __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_deviceActionMessage).call(this, IFrameMessageAction.LedgerUnlock, params);
|
|
100
|
+
}
|
|
101
|
+
async deviceSignTransaction(params) {
|
|
102
|
+
return __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_deviceActionMessage).call(this, IFrameMessageAction.LedgerSignTransaction, params);
|
|
103
|
+
}
|
|
104
|
+
async deviceSignMessage(params) {
|
|
105
|
+
return __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_deviceActionMessage).call(this, IFrameMessageAction.LedgerSignPersonalMessage, params);
|
|
106
|
+
}
|
|
107
|
+
async deviceSignTypedData(params) {
|
|
108
|
+
return __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_deviceActionMessage).call(this, IFrameMessageAction.LedgerSignTypedData, params);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
exports.LedgerIframeBridge = LedgerIframeBridge;
|
|
112
|
+
_LedgerIframeBridge_opts = new WeakMap(), _LedgerIframeBridge_instances = new WeakSet(), _LedgerIframeBridge_deviceActionMessage = async function _LedgerIframeBridge_deviceActionMessage(...[action, params]) {
|
|
113
|
+
return new Promise((resolve, reject) => {
|
|
114
|
+
__classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_sendMessage).call(this, {
|
|
115
|
+
action,
|
|
116
|
+
params,
|
|
117
|
+
}, (response) => {
|
|
118
|
+
if ('payload' in response && response.payload) {
|
|
119
|
+
if ('success' in response && response.success) {
|
|
120
|
+
return resolve(response.payload);
|
|
121
|
+
}
|
|
122
|
+
if ('error' in response.payload) {
|
|
123
|
+
return reject(response.payload.error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return reject(new Error('Unknown error occurred'));
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
}, _LedgerIframeBridge_setupIframe = async function _LedgerIframeBridge_setupIframe(bridgeUrl) {
|
|
130
|
+
return new Promise((resolve) => {
|
|
131
|
+
this.iframe = document.createElement('iframe');
|
|
132
|
+
this.iframe.src = bridgeUrl;
|
|
133
|
+
this.iframe.allow = `hid 'src'`;
|
|
134
|
+
this.iframe.onload = async () => {
|
|
135
|
+
this.iframeLoaded = true;
|
|
136
|
+
resolve();
|
|
137
|
+
};
|
|
138
|
+
document.head.appendChild(this.iframe);
|
|
139
|
+
});
|
|
140
|
+
}, _LedgerIframeBridge_getOrigin = function _LedgerIframeBridge_getOrigin(bridgeUrl) {
|
|
141
|
+
const tmp = bridgeUrl.split('/');
|
|
142
|
+
tmp.splice(-1, 1);
|
|
143
|
+
return tmp.join('/');
|
|
144
|
+
}, _LedgerIframeBridge_eventListener = function _LedgerIframeBridge_eventListener(bridgeUrl, eventMessage) {
|
|
145
|
+
if (eventMessage.origin !== __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_getOrigin).call(this, bridgeUrl)) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (eventMessage.data) {
|
|
149
|
+
const messageCallback = this.messageCallbacks[eventMessage.data.messageId];
|
|
150
|
+
if (messageCallback) {
|
|
151
|
+
messageCallback(eventMessage.data);
|
|
152
|
+
}
|
|
153
|
+
else if (eventMessage.data.action === IFrameMessageAction.LedgerConnectionChange) {
|
|
154
|
+
this.isDeviceConnected = eventMessage.data.payload.connected;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}, _LedgerIframeBridge_sendMessage = function _LedgerIframeBridge_sendMessage(message, callback) {
|
|
158
|
+
this.currentMessageId += 1;
|
|
159
|
+
const postMsg = {
|
|
160
|
+
...message,
|
|
161
|
+
messageId: this.currentMessageId,
|
|
162
|
+
target: LEDGER_IFRAME_ID,
|
|
163
|
+
};
|
|
164
|
+
this.messageCallbacks[this.currentMessageId] = callback;
|
|
165
|
+
if (!this.iframeLoaded || !this.iframe || !this.iframe.contentWindow) {
|
|
166
|
+
throw new Error('The iframe is not loaded yet');
|
|
167
|
+
}
|
|
168
|
+
this.iframe.contentWindow.postMessage(postMsg, '*');
|
|
169
|
+
}, _LedgerIframeBridge_validateConfiguration = function _LedgerIframeBridge_validateConfiguration(opts) {
|
|
170
|
+
if (typeof opts.bridgeUrl !== 'string' || opts.bridgeUrl.length === 0) {
|
|
171
|
+
throw new Error('bridgeURL is not a valid URL');
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
//# 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 IFrameMessageResponseStub<\n SuccessResult extends Record<string, unknown>,\n FailureResult = Error,\n> = {\n messageId: number;\n} & (\n | { success: true; payload: SuccessResult }\n | { success: false; payload: { error: FailureResult } }\n);\n\ntype LedgerConnectionChangeActionResponse = {\n messageId: number;\n action: IFrameMessageAction.LedgerConnectionChange;\n payload: { connected: boolean };\n};\n\ntype LedgerMakeAppActionResponse = {\n messageId: number;\n action: IFrameMessageAction.LedgerMakeApp;\n} & ({ success: true } | { success: false; error?: unknown });\n\ntype LedgerUpdateTransportActionResponse = {\n messageId: number;\n action: IFrameMessageAction.LedgerUpdateTransport;\n success: boolean;\n};\n\ntype LedgerUnlockActionResponse = {\n action: IFrameMessageAction.LedgerUnlock;\n} & IFrameMessageResponseStub<GetPublicKeyResponse>;\n\ntype LedgerSignTransactionActionResponse = {\n action: IFrameMessageAction.LedgerSignTransaction;\n} & IFrameMessageResponseStub<LedgerSignTransactionResponse>;\n\ntype LedgerSignPersonalMessageActionResponse = {\n action: IFrameMessageAction.LedgerSignPersonalMessage;\n} & IFrameMessageResponseStub<LedgerSignMessageResponse>;\n\ntype LedgerSignTypedDataActionResponse = {\n action: IFrameMessageAction.LedgerSignTypedData;\n} & IFrameMessageResponseStub<LedgerSignTypedDataResponse>;\n\nexport type IFrameMessageResponse =\n | LedgerConnectionChangeActionResponse\n | LedgerMakeAppActionResponse\n | LedgerUpdateTransportActionResponse\n | LedgerUnlockActionResponse\n | LedgerSignTransactionActionResponse\n | LedgerSignPersonalMessageActionResponse\n | LedgerSignTypedDataActionResponse;\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 type LedgerIframeBridgeOptions = {\n bridgeUrl: string;\n};\n\nexport class LedgerIframeBridge\n implements LedgerBridge<LedgerIframeBridgeOptions>\n{\n iframe?: HTMLIFrameElement;\n\n iframeLoaded = false;\n\n #opts: LedgerIframeBridgeOptions;\n\n eventListener?: (eventMessage: {\n origin: string;\n data: IFrameMessageResponse;\n }) => void;\n\n isDeviceConnected = false;\n\n currentMessageId = 0;\n\n messageCallbacks: Record<number, (response: IFrameMessageResponse) => void> =\n {};\n\n constructor(\n opts: LedgerIframeBridgeOptions = {\n bridgeUrl: 'https://metamask.github.io/eth-ledger-bridge-keyring',\n },\n ) {\n this.#validateConfiguration(opts);\n this.#opts = {\n bridgeUrl: opts?.bridgeUrl,\n };\n }\n\n async init() {\n await this.#setupIframe(this.#opts.bridgeUrl);\n\n this.eventListener = this.#eventListener.bind(this, this.#opts.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 getOptions(): Promise<LedgerIframeBridgeOptions> {\n return this.#opts;\n }\n\n async setOptions(opts: LedgerIframeBridgeOptions): Promise<void> {\n this.#validateConfiguration(opts);\n if (this.#opts?.bridgeUrl !== opts.bridgeUrl) {\n this.#opts.bridgeUrl = opts.bridgeUrl;\n await this.destroy();\n await this.init();\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 ('success' in response && response.success) {\n resolve(true);\n } else if ('error' in response) {\n reject(response.error);\n } else {\n reject(new Error('Unknown error occurred'));\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 throw new Error('The iframe is not loaded yet');\n }\n\n this.#sendMessage(\n {\n action: IFrameMessageAction.LedgerUpdateTransport,\n params: { transportType },\n },\n (response) => {\n if ('success' in response && response.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 (response) => {\n if ('payload' in response && response.payload) {\n if ('success' in response && response.success) {\n return resolve(response.payload);\n }\n if ('error' in response.payload) {\n return reject(response.payload.error);\n }\n }\n return reject(new Error('Unknown error occurred'));\n },\n );\n });\n }\n\n async #setupIframe(bridgeUrl: string): Promise<void> {\n return new Promise((resolve) => {\n this.iframe = document.createElement('iframe');\n this.iframe.src = bridgeUrl;\n this.iframe.allow = `hid 'src'`;\n this.iframe.onload = async () => {\n this.iframeLoaded = true;\n resolve();\n };\n document.head.appendChild(this.iframe);\n });\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;\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) => 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;\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 #validateConfiguration(opts: LedgerIframeBridgeOptions): void {\n if (typeof opts.bridgeUrl !== 'string' || opts.bridgeUrl.length === 0) {\n throw new Error('bridgeURL is not a valid URL');\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { TypedTransaction } from '@ethereumjs/tx';
|
|
3
|
+
import type { MessageTypes, TypedMessage } from '@metamask/eth-sig-util';
|
|
4
|
+
import type OldEthJsTransaction from 'ethereumjs-tx';
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
import HDKey from 'hdkey';
|
|
7
|
+
import { LedgerBridge, LedgerBridgeOptions } from './ledger-bridge';
|
|
8
|
+
declare enum NetworkApiUrls {
|
|
9
|
+
Ropsten = "https://api-ropsten.etherscan.io",
|
|
10
|
+
Kovan = "https://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
|
+
deviceId: string;
|
|
23
|
+
accountDetails: Readonly<Record<string, AccountDetails>>;
|
|
24
|
+
accountIndexes: Readonly<Record<string, number>>;
|
|
25
|
+
implementFullBIP44: boolean;
|
|
26
|
+
};
|
|
27
|
+
export declare class LedgerKeyring extends EventEmitter {
|
|
28
|
+
#private;
|
|
29
|
+
static type: string;
|
|
30
|
+
deviceId: string;
|
|
31
|
+
readonly type: string;
|
|
32
|
+
page: number;
|
|
33
|
+
perPage: number;
|
|
34
|
+
unlockedAccount: number;
|
|
35
|
+
accounts: readonly string[];
|
|
36
|
+
accountDetails: Record<string, AccountDetails>;
|
|
37
|
+
hdk: HDKey;
|
|
38
|
+
hdPath: string;
|
|
39
|
+
paths: Record<string, number>;
|
|
40
|
+
network: NetworkApiUrls;
|
|
41
|
+
implementFullBIP44: boolean;
|
|
42
|
+
bridge: LedgerBridge<LedgerBridgeOptions>;
|
|
43
|
+
constructor({ bridge }: {
|
|
44
|
+
bridge: LedgerBridge<LedgerBridgeOptions>;
|
|
45
|
+
});
|
|
46
|
+
init(): Promise<void>;
|
|
47
|
+
destroy(): Promise<void>;
|
|
48
|
+
serialize(): Promise<{
|
|
49
|
+
hdPath: string;
|
|
50
|
+
accounts: readonly string[];
|
|
51
|
+
deviceId: string;
|
|
52
|
+
accountDetails: Record<string, AccountDetails>;
|
|
53
|
+
implementFullBIP44: boolean;
|
|
54
|
+
}>;
|
|
55
|
+
deserialize(opts?: Partial<LedgerBridgeKeyringOptions>): Promise<void>;
|
|
56
|
+
setDeviceId(deviceId: string): void;
|
|
57
|
+
getDeviceId(): string;
|
|
58
|
+
isUnlocked(): boolean;
|
|
59
|
+
isConnected(): boolean;
|
|
60
|
+
setAccountToUnlock(index: number): void;
|
|
61
|
+
setHdPath(hdPath: string): void;
|
|
62
|
+
unlock(hdPath?: string, updateHdk?: boolean): Promise<string>;
|
|
63
|
+
addAccounts(amount?: number): Promise<string[]>;
|
|
64
|
+
getName(): string;
|
|
65
|
+
getFirstPage(): Promise<{
|
|
66
|
+
address: string;
|
|
67
|
+
balance: number | null;
|
|
68
|
+
index: number;
|
|
69
|
+
}[]>;
|
|
70
|
+
getNextPage(): Promise<{
|
|
71
|
+
address: string;
|
|
72
|
+
balance: number | null;
|
|
73
|
+
index: number;
|
|
74
|
+
}[]>;
|
|
75
|
+
getPreviousPage(): Promise<{
|
|
76
|
+
address: string;
|
|
77
|
+
balance: number | null;
|
|
78
|
+
index: number;
|
|
79
|
+
}[]>;
|
|
80
|
+
getAccounts(): Promise<string[]>;
|
|
81
|
+
removeAccount(address: string): void;
|
|
82
|
+
attemptMakeApp(): Promise<boolean>;
|
|
83
|
+
updateTransportMethod(transportType: string): Promise<boolean>;
|
|
84
|
+
signTransaction(address: string, tx: TypedTransaction | OldEthJsTransaction): Promise<TypedTransaction | OldEthJsTransaction>;
|
|
85
|
+
signMessage(withAccount: string, data: string): Promise<string>;
|
|
86
|
+
signPersonalMessage(withAccount: string, message: string): Promise<string>;
|
|
87
|
+
unlockAccountByAddress(address: string): Promise<string | undefined>;
|
|
88
|
+
signTypedData<T extends MessageTypes>(withAccount: string, data: TypedMessage<T>, options?: {
|
|
89
|
+
version?: string;
|
|
90
|
+
}): Promise<string>;
|
|
91
|
+
exportAccount(): void;
|
|
92
|
+
forgetDevice(): void;
|
|
93
|
+
}
|
|
94
|
+
export {};
|