@shapeshiftoss/hdwallet-keplr 1.23.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/src/keplr.ts ADDED
@@ -0,0 +1,372 @@
1
+ import { Window as KeplrWindow } from "@keplr-wallet/types";
2
+ import { ChainReference } from "@shapeshiftoss/caip";
3
+ import * as core from "@shapeshiftoss/hdwallet-core";
4
+ import isObject from "lodash/isObject";
5
+
6
+ import * as cosmos from "./cosmos";
7
+ import * as osmosis from "./osmosis";
8
+
9
+ declare global {
10
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
11
+ interface Window extends KeplrWindow {}
12
+ }
13
+
14
+ class KeplrTransport extends core.Transport {
15
+ public async getDeviceID() {
16
+ return "keplr:0";
17
+ }
18
+
19
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
20
+ public call(...args: any[]): Promise<void> {
21
+ return Promise.resolve();
22
+ }
23
+ }
24
+
25
+ export function isKeplr(wallet: core.HDWallet): wallet is KeplrHDWallet {
26
+ return isObject(wallet) && (wallet as any)._isKeplr;
27
+ }
28
+
29
+ export class KeplrHDWalletInfo implements core.HDWalletInfo, core.CosmosWalletInfo, core.OsmosisWalletInfo {
30
+ readonly _supportsCosmosInfo = true;
31
+ readonly _supportsOsmosisInfo = true;
32
+
33
+ public getVendor(): string {
34
+ return "Keplr";
35
+ }
36
+
37
+ public hasOnDevicePinEntry(): boolean {
38
+ return false;
39
+ }
40
+
41
+ public hasOnDevicePassphrase(): boolean {
42
+ return false;
43
+ }
44
+
45
+ public hasOnDeviceDisplay(): boolean {
46
+ return true;
47
+ }
48
+
49
+ public hasOnDeviceRecovery(): boolean {
50
+ return false;
51
+ }
52
+
53
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
54
+ public hasNativeShapeShift(srcCoin: core.Coin, dstCoin: core.Coin): boolean {
55
+ return false;
56
+ }
57
+
58
+ public supportsOfflineSigning(): boolean {
59
+ return true;
60
+ }
61
+
62
+ public supportsBroadcast(): boolean {
63
+ return true;
64
+ }
65
+
66
+ public describePath(msg: core.DescribePath): core.PathDescription {
67
+ switch (msg.coin) {
68
+ case "Atom":
69
+ return cosmos.cosmosDescribePath(msg.path);
70
+ case "Osmo":
71
+ return osmosis.osmosisDescribePath(msg.path);
72
+ default:
73
+ throw new Error("Unsupported path");
74
+ }
75
+ }
76
+
77
+ public async cosmosSupportsNetwork(chainId = 118): Promise<boolean> {
78
+ return chainId === 118;
79
+ }
80
+
81
+ public async cosmosSupportsSecureTransfer(): Promise<boolean> {
82
+ return false;
83
+ }
84
+
85
+ public cosmosSupportsNativeShapeShift(): boolean {
86
+ return false;
87
+ }
88
+
89
+ public cosmosGetAccountPaths(msg: core.CosmosGetAccountPaths): Array<core.CosmosAccountPath> {
90
+ return cosmos.cosmosGetAccountPaths(msg);
91
+ }
92
+
93
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
94
+ public cosmosNextAccountPath(msg: core.CosmosAccountPath): core.CosmosAccountPath | undefined {
95
+ // TODO: What do we do here?
96
+ return undefined;
97
+ }
98
+
99
+ public async osmosisSupportsNetwork(chainId = 1): Promise<boolean> {
100
+ return chainId === 1;
101
+ }
102
+
103
+ public async osmosisSupportsSecureTransfer(): Promise<boolean> {
104
+ return false;
105
+ }
106
+
107
+ public osmosisSupportsNativeShapeShift(): boolean {
108
+ return false;
109
+ }
110
+
111
+ public osmosisGetAccountPaths(msg: core.OsmosisGetAccountPaths): Array<core.OsmosisAccountPath> {
112
+ return osmosis.osmosisGetAccountPaths(msg);
113
+ }
114
+
115
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
116
+ public osmosisNextAccountPath(msg: core.OsmosisAccountPath): core.OsmosisAccountPath | undefined {
117
+ return undefined;
118
+ }
119
+ }
120
+
121
+ export class KeplrHDWallet implements core.HDWallet, core.CosmosWallet, core.OsmosisWallet {
122
+ readonly _isKeplr = true;
123
+ readonly _supportsCosmos = true;
124
+ readonly _supportsCosmosInfo = true;
125
+ readonly _supportsOsmosis = true;
126
+ readonly _supportsOsmosisInfo = true;
127
+
128
+ transport: core.Transport = new KeplrTransport(new core.Keyring());
129
+ info: KeplrHDWalletInfo & core.HDWalletInfo;
130
+
131
+ initialized = false;
132
+ provider: any = {};
133
+ supportedNetworks: ChainReference[] = [ChainReference.CosmosHubMainnet, ChainReference.OsmosisMainnet];
134
+
135
+ constructor() {
136
+ this.info = new KeplrHDWalletInfo();
137
+ }
138
+
139
+ async getFeatures(): Promise<Record<string, any>> {
140
+ return {};
141
+ }
142
+
143
+ public async isLocked(): Promise<boolean> {
144
+ return this.provider.isLocked();
145
+ }
146
+
147
+ public getVendor(): string {
148
+ return "Keplr";
149
+ }
150
+
151
+ public getModel(): Promise<string> {
152
+ return Promise.resolve("Keplr");
153
+ }
154
+
155
+ public getLabel(): Promise<string> {
156
+ return Promise.resolve("Keplr");
157
+ }
158
+
159
+ public async initialize(networks: Array<ChainReference> = []): Promise<void> {
160
+ try {
161
+ if (!window.keplr) {
162
+ throw new Error("Keplr extension not installed.");
163
+ }
164
+ this.provider = window.keplr;
165
+
166
+ /** Initialize Keplr Wallet with all supported chains by default
167
+ * or the subset of supported chains passed in the call to initialize() */
168
+ await this.provider.enable(networks.length ? networks : this.supportedNetworks);
169
+ return Promise.resolve();
170
+ } catch (error) {
171
+ /**
172
+ * @todo Use logger instead of console.error()
173
+ */
174
+ console.error(error);
175
+ throw new Error("Error initializing Keplr");
176
+ }
177
+ }
178
+
179
+ public hasOnDevicePinEntry(): boolean {
180
+ return this.info.hasOnDevicePinEntry();
181
+ }
182
+
183
+ public hasOnDevicePassphrase(): boolean {
184
+ return this.info.hasOnDevicePassphrase();
185
+ }
186
+
187
+ public hasOnDeviceDisplay(): boolean {
188
+ return this.info.hasOnDeviceDisplay();
189
+ }
190
+
191
+ public hasOnDeviceRecovery(): boolean {
192
+ return this.info.hasOnDeviceRecovery();
193
+ }
194
+
195
+ public hasNativeShapeShift(srcCoin: core.Coin, dstCoin: core.Coin): boolean {
196
+ return this.info.hasNativeShapeShift(srcCoin, dstCoin);
197
+ }
198
+
199
+ public supportsOfflineSigning(): boolean {
200
+ return true;
201
+ }
202
+
203
+ public supportsBroadcast(): boolean {
204
+ return true;
205
+ }
206
+
207
+ public async clearSession(): Promise<void> {
208
+ // TODO: Can we lock Keplr from here?
209
+ }
210
+
211
+ public ping(msg: core.Ping): Promise<core.Pong> {
212
+ // no ping function for Keplr, so just returning Core.Pong
213
+ return Promise.resolve({ msg: msg.msg });
214
+ }
215
+
216
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
217
+ public sendPin(pin: string): Promise<void> {
218
+ // no concept of pin in Keplr
219
+ return Promise.resolve();
220
+ }
221
+
222
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
223
+ public sendPassphrase(passphrase: string): Promise<void> {
224
+ // cannot send passphrase to Keplr. Could show the widget?
225
+ return Promise.resolve();
226
+ }
227
+
228
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
229
+ public sendCharacter(character: string): Promise<void> {
230
+ // no concept of sendCharacter in Keplr
231
+ return Promise.resolve();
232
+ }
233
+
234
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
235
+ public sendWord(word: string): Promise<void> {
236
+ // no concept of sendWord in Keplr
237
+ return Promise.resolve();
238
+ }
239
+
240
+ public cancel(): Promise<void> {
241
+ // no concept of cancel in Keplr
242
+ return Promise.resolve();
243
+ }
244
+
245
+ public wipe(): Promise<void> {
246
+ return Promise.resolve();
247
+ }
248
+
249
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
250
+ public reset(msg: core.ResetDevice): Promise<void> {
251
+ return Promise.resolve();
252
+ }
253
+
254
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
255
+ public recover(msg: core.RecoverDevice): Promise<void> {
256
+ // no concept of recover in Keplr
257
+ return Promise.resolve();
258
+ }
259
+
260
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
261
+ public loadDevice(msg: core.LoadDevice): Promise<void> {
262
+ /**
263
+ * @todo: Does Keplr allow this to be done programatically?
264
+ */
265
+ return Promise.resolve();
266
+ }
267
+
268
+ public describePath(msg: core.DescribePath): core.PathDescription {
269
+ return this.info.describePath(msg);
270
+ }
271
+
272
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
273
+ public async getPublicKeys(
274
+ msg: Array<core.GetPublicKey>,
275
+ chainId: ChainReference = ChainReference.CosmosHubMainnet
276
+ ): Promise<Array<core.PublicKey | null>> {
277
+ if (!this.supportedNetworks.includes(chainId)) {
278
+ throw new Error(`Unsupported chainId: ${chainId}`);
279
+ }
280
+ const keys: Array<core.PublicKey | null> = [];
281
+ await this.provider.enable(chainId);
282
+ const offlineSigner = this.provider.getOfflineSigner(chainId);
283
+ keys.push({ xpub: Buffer.from((await offlineSigner.getAccounts())[0].pubkey).toString() });
284
+ return keys;
285
+ }
286
+
287
+ public async isInitialized(): Promise<boolean> {
288
+ return this.initialized;
289
+ }
290
+
291
+ public disconnect(): Promise<void> {
292
+ return Promise.resolve();
293
+ }
294
+
295
+ public async cosmosSupportsNetwork(chainId = 118): Promise<boolean> {
296
+ return chainId === 118;
297
+ }
298
+
299
+ public async cosmosSupportsSecureTransfer(): Promise<boolean> {
300
+ return false;
301
+ }
302
+
303
+ public cosmosSupportsNativeShapeShift(): boolean {
304
+ return false;
305
+ }
306
+
307
+ public cosmosGetAccountPaths(msg: core.CosmosGetAccountPaths): Array<core.CosmosAccountPath> {
308
+ return cosmos.cosmosGetAccountPaths(msg);
309
+ }
310
+
311
+ public cosmosNextAccountPath(msg: core.CosmosAccountPath): core.CosmosAccountPath | undefined {
312
+ return this.info.cosmosNextAccountPath(msg);
313
+ }
314
+
315
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
316
+ public async cosmosGetAddress(): Promise<string | null> {
317
+ return (await cosmos.cosmosGetAddress(this.provider)) || null;
318
+ }
319
+
320
+ public async cosmosSignTx(msg: core.CosmosSignTx): Promise<core.CosmosSignedTx | null> {
321
+ return cosmos.cosmosSignTx(this.provider, msg);
322
+ }
323
+
324
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
325
+ public async cosmosSendTx(msg: core.CosmosSignTx): Promise<string | null> {
326
+ /** Broadcast from Keplr is currently unimplemented */
327
+ return null;
328
+ }
329
+
330
+ public async osmosisSupportsNetwork(chainId = 118): Promise<boolean> {
331
+ return chainId === 118;
332
+ }
333
+
334
+ public async osmosisSupportsSecureTransfer(): Promise<boolean> {
335
+ return false;
336
+ }
337
+
338
+ public osmosisSupportsNativeShapeShift(): boolean {
339
+ return false;
340
+ }
341
+
342
+ public osmosisGetAccountPaths(msg: core.OsmosisGetAccountPaths): Array<core.OsmosisAccountPath> {
343
+ return osmosis.osmosisGetAccountPaths(msg);
344
+ }
345
+
346
+ public osmosisNextAccountPath(msg: core.OsmosisAccountPath): core.OsmosisAccountPath | undefined {
347
+ return this.info.osmosisNextAccountPath(msg);
348
+ }
349
+
350
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
351
+ public async osmosisGetAddress(): Promise<string | null> {
352
+ return (await osmosis.osmosisGetAddress(this.provider)) || null;
353
+ }
354
+
355
+ public async osmosisSignTx(msg: core.OsmosisSignTx): Promise<core.OsmosisSignedTx | null> {
356
+ return osmosis.osmosisSignTx(this.provider, msg);
357
+ }
358
+
359
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
360
+ public async osmosisSendTx(msg: core.OsmosisSignTx): Promise<string | null> {
361
+ /** Broadcast from Keplr is currently unimplemented */
362
+ return null;
363
+ }
364
+
365
+ public async getDeviceID(): Promise<string> {
366
+ return "keplr:" + (await this.cosmosGetAddress());
367
+ }
368
+
369
+ public async getFirmwareVersion(): Promise<string> {
370
+ return "keplr";
371
+ }
372
+ }
package/src/osmosis.ts ADDED
@@ -0,0 +1,74 @@
1
+ import { ChainReference } from "@shapeshiftoss/caip";
2
+ import * as core from "@shapeshiftoss/hdwallet-core";
3
+ import {
4
+ OsmosisAccountPath,
5
+ OsmosisGetAccountPaths,
6
+ OsmosisSignedTx,
7
+ OsmosisSignTx,
8
+ slip44ByCoin,
9
+ } from "@shapeshiftoss/hdwallet-core";
10
+ import { sign } from "@shapeshiftoss/proto-tx-builder";
11
+
12
+ export function osmosisDescribePath(path: core.BIP32Path): core.PathDescription {
13
+ const pathStr = core.addressNListToBIP32(path);
14
+ const unknown: core.PathDescription = {
15
+ verbose: pathStr,
16
+ coin: "Osmo",
17
+ isKnown: false,
18
+ };
19
+
20
+ if (path.length != 5) {
21
+ return unknown;
22
+ }
23
+
24
+ if (path[0] != 0x80000000 + 44) {
25
+ return unknown;
26
+ }
27
+
28
+ if (path[1] != 0x80000000 + slip44ByCoin("Osmo")) {
29
+ return unknown;
30
+ }
31
+
32
+ if ((path[2] & 0x80000000) >>> 0 !== 0x80000000) {
33
+ return unknown;
34
+ }
35
+
36
+ if (path[3] !== 0 || path[4] !== 0) {
37
+ return unknown;
38
+ }
39
+
40
+ const index = path[2] & 0x7fffffff;
41
+ return {
42
+ verbose: `Osmosis Account #${index}`,
43
+ accountIdx: index,
44
+ wholeAccount: true,
45
+ coin: "Osmo",
46
+ isKnown: true,
47
+ isPrefork: false,
48
+ };
49
+ }
50
+
51
+ export function osmosisGetAccountPaths(msg: OsmosisGetAccountPaths): Array<OsmosisAccountPath> {
52
+ return [
53
+ {
54
+ addressNList: [0x80000000 + 44, 0x80000000 + slip44ByCoin("Osmo"), 0x80000000 + msg.accountIdx, 0, 0],
55
+ },
56
+ ];
57
+ }
58
+
59
+ export async function osmosisGetAddress(provider: any): Promise<string | undefined> {
60
+ const offlineSigner = provider.getOfflineSigner(ChainReference.OsmosisMainnet);
61
+ const osmosisAddress = (await offlineSigner?.getAccounts())?.[0].address;
62
+ return osmosisAddress;
63
+ }
64
+
65
+ export async function osmosisSignTx(provider: any, msg: OsmosisSignTx): Promise<OsmosisSignedTx> {
66
+ const offlineSigner = provider.getOfflineSigner(ChainReference.OsmosisMainnet);
67
+ const output = await sign(msg.tx, offlineSigner, msg.sequence, msg.account_number, msg.chain_id);
68
+ return output;
69
+ }
70
+
71
+ /**
72
+ * @todo: Add support for sign/verify message see documentation at:
73
+ * https://github.com/chainapsis/keplr-wallet/blob/fbbc0b6d8eb4859a1663988d1bd90f07c9b74708/docs/api/README.md
74
+ */
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "outDir": "dist"
6
+ },
7
+ "include": ["src/**/*"],
8
+ "exclude": ["node_modules", "dist"],
9
+ "references": [{ "path": "../hdwallet-core" }]
10
+ }