mirror of
https://github.com/pezkuwichain/pezkuwi-ui.git
synced 2026-05-31 11:01:03 +00:00
Split Ledger (& transports) into package (#399)
* Split Ledger (& transports) into package * Fix browser/node resolution * Bump
This commit is contained in:
@@ -11,34 +11,21 @@
|
||||
],
|
||||
"contributors": [],
|
||||
"license": "Apache-2.0",
|
||||
"browser": {
|
||||
"./ledger/transportsNode": "./ledger/transportsEmpty"
|
||||
},
|
||||
"react-native": {
|
||||
"./ledger/transportsNode": "./ledger/transportsEmpty",
|
||||
"./ledger/transportsWeb": "./ledger/transportsEmpty"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@ledgerhq/hw-transport-webusb": "^5.28.0",
|
||||
"@polkadot/keyring": "^4.0.2-8",
|
||||
"@polkadot/ledger": "^0.62.2-4",
|
||||
"@polkadot/ui-settings": "0.62.2-4",
|
||||
"@polkadot/util": "^4.0.2-8",
|
||||
"@zondax/ledger-polkadot": "^0.11.0",
|
||||
"mkdirp": "^1.0.4",
|
||||
"rxjs": "^6.6.3",
|
||||
"store": "^2.0.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@polkadot/types": "^2.6.2-4",
|
||||
"@types/ledgerhq__hw-transport-node-hid": "^4.22.2",
|
||||
"@types/ledgerhq__hw-transport-webusb": "^4.70.1",
|
||||
"@types/mkdirp": "^1.0.1",
|
||||
"@types/store": "^2.0.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@ledgerhq/hw-transport-node-hid": "^5.28.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@polkadot/keyring": "*",
|
||||
"@polkadot/ui-settings": "*",
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// Copyright 2017-2020 @polkadot/ui-keyring authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { detectPackage } from '@polkadot/util';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
detectPackage(require('./package.json'), typeof __dirname !== 'undefined' && __dirname);
|
||||
@@ -1,17 +1,12 @@
|
||||
// Copyright 2017-2020 @polkadot/ui-keyring authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { detectPackage } from '@polkadot/util';
|
||||
import './detectPackage';
|
||||
|
||||
import keyring, { Keyring } from './Keyring';
|
||||
import Ledger from './ledger';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
detectPackage(require('./package.json'), typeof __dirname !== 'undefined' && __dirname);
|
||||
export { default as Ledger } from '@polkadot/ledger';
|
||||
|
||||
export default keyring;
|
||||
|
||||
export {
|
||||
Keyring,
|
||||
Ledger
|
||||
};
|
||||
export { Keyring };
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
// Copyright 2017-2020 @polkadot/ui-keyring authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import Transport from '@ledgerhq/hw-transport';
|
||||
import { AccountOptions, LedgerAddress, LedgerSignature, LedgerTypes, LedgerVersion } from './types';
|
||||
|
||||
import { ResponseBase, SubstrateApp, newKusamaApp, newPolkadotApp } from '@zondax/ledger-polkadot';
|
||||
import { assert, bufferToU8a, u8aToBuffer, u8aToHex } from '@polkadot/util';
|
||||
|
||||
import allNode from './transportsNode';
|
||||
import allWeb from './transportsWeb';
|
||||
|
||||
export const LEDGER_DEFAULT_ACCOUNT = 0x80000000;
|
||||
|
||||
export const LEDGER_DEFAULT_CHANGE = 0x80000000;
|
||||
|
||||
export const LEDGER_DEFAULT_INDEX = 0x80000000;
|
||||
|
||||
const SUCCESS_CODE = 0x9000;
|
||||
|
||||
const transports = allNode.concat(allWeb);
|
||||
|
||||
const APPS: Record<string, (transport: Transport) => SubstrateApp> = {
|
||||
kusama: newKusamaApp,
|
||||
polkadot: newPolkadotApp
|
||||
};
|
||||
|
||||
type Chain = keyof typeof APPS;
|
||||
|
||||
// A very basic wrapper for a ledger app -
|
||||
// - it connects automatically, creating an app as required
|
||||
// - Promises return errors (instead of wrapper errors)
|
||||
export default class Ledger {
|
||||
#app: SubstrateApp | null = null;
|
||||
|
||||
#chain: Chain;
|
||||
|
||||
#transport: LedgerTypes;
|
||||
|
||||
constructor (transport: LedgerTypes, chain: Chain) {
|
||||
// u2f is deprecated
|
||||
assert(['hid', 'webusb'].includes(transport), `Unsupported transport ${transport}`);
|
||||
assert(Object.keys(APPS).includes(chain), `Unsupported chain ${chain}`);
|
||||
|
||||
this.#chain = chain;
|
||||
this.#transport = transport;
|
||||
}
|
||||
|
||||
public async getAddress (confirm = false, accountOffset = 0, addressOffset = 0, { account = LEDGER_DEFAULT_ACCOUNT, addressIndex = LEDGER_DEFAULT_INDEX, change = LEDGER_DEFAULT_CHANGE }: Partial<AccountOptions> = {}): Promise<LedgerAddress> {
|
||||
return this.#withApp(async (app: SubstrateApp): Promise<LedgerAddress> => {
|
||||
const { address, pubKey } = await this.#wrapError(app.getAddress(account + accountOffset, change, addressIndex + addressOffset, confirm));
|
||||
|
||||
return {
|
||||
address,
|
||||
publicKey: `0x${pubKey}`
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public async getVersion (): Promise<LedgerVersion> {
|
||||
return this.#withApp(async (app: SubstrateApp): Promise<LedgerVersion> => {
|
||||
const { device_locked: isLocked, major, minor, patch, test_mode: isTestMode } = await this.#wrapError(app.getVersion());
|
||||
|
||||
return {
|
||||
isLocked,
|
||||
isTestMode,
|
||||
version: [major, minor, patch]
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public async sign (message: Uint8Array, accountOffset = 0, addressOffset = 0, { account = LEDGER_DEFAULT_ACCOUNT, addressIndex = LEDGER_DEFAULT_INDEX, change = LEDGER_DEFAULT_CHANGE }: Partial<AccountOptions> = {}): Promise<LedgerSignature> {
|
||||
return this.#withApp(async (app: SubstrateApp): Promise<LedgerSignature> => {
|
||||
const buffer = u8aToBuffer(message);
|
||||
const { signature } = await this.#wrapError(app.sign(account + accountOffset, change, addressIndex + addressOffset, buffer));
|
||||
|
||||
return {
|
||||
signature: u8aToHex(bufferToU8a(signature))
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
#getApp = async (): Promise<SubstrateApp> => {
|
||||
if (!this.#app) {
|
||||
const def = transports.find(({ type }) => type === this.#transport);
|
||||
|
||||
assert(def, `Unable to find a transport for ${this.#transport}`);
|
||||
|
||||
const transport = await def.create();
|
||||
|
||||
this.#app = APPS[this.#chain](transport);
|
||||
}
|
||||
|
||||
return this.#app;
|
||||
};
|
||||
|
||||
#withApp = async <T> (fn: (app: SubstrateApp) => Promise<T>): Promise<T> => {
|
||||
try {
|
||||
const app = await this.#getApp();
|
||||
|
||||
return await fn(app);
|
||||
} catch (error) {
|
||||
this.#app = null;
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
#wrapError = async <T extends ResponseBase> (promise: Promise<T>): Promise<T> => {
|
||||
const result = await promise;
|
||||
|
||||
assert(result.return_code === SUCCESS_CODE, result.error_message);
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
// Copyright 2017-2020 @polkadot/ui-keyring authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { TransportDef } from './types';
|
||||
|
||||
const transports: TransportDef[] = [];
|
||||
|
||||
export default transports;
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2017-2020 @polkadot/ui-keyring authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { TransportDef } from './types';
|
||||
|
||||
import Transport from '@ledgerhq/hw-transport';
|
||||
import LedgerHid from '@ledgerhq/hw-transport-node-hid';
|
||||
|
||||
const transports: TransportDef[] = [
|
||||
{
|
||||
create: (): Promise<Transport> =>
|
||||
LedgerHid.create(),
|
||||
type: 'hid'
|
||||
}
|
||||
];
|
||||
|
||||
export default transports;
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright 2017-2020 @polkadot/ui-keyring authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { TransportDef } from './types';
|
||||
|
||||
import Transport from '@ledgerhq/hw-transport';
|
||||
import LedgerWebUSB from '@ledgerhq/hw-transport-webusb';
|
||||
|
||||
const transports: TransportDef[] = [
|
||||
// deprecated
|
||||
// import LedgerU2F from '@ledgerhq/hw-transport-u2f';
|
||||
// {
|
||||
// create: (): Promise<Transport> =>
|
||||
// LedgerU2F.create(),
|
||||
// type: 'u2f'
|
||||
// },
|
||||
{
|
||||
create: (): Promise<Transport> =>
|
||||
LedgerWebUSB.create(),
|
||||
type: 'webusb'
|
||||
}
|
||||
];
|
||||
|
||||
export default transports;
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright 2017-2020 @polkadot/ui-keyring authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import Transport from '@ledgerhq/hw-transport';
|
||||
|
||||
export type LedgerTypes = 'hid' | 'u2f' | 'webusb';
|
||||
|
||||
export interface AccountOptions {
|
||||
account: number;
|
||||
addressIndex: number;
|
||||
change: number;
|
||||
}
|
||||
|
||||
export interface LedgerAddress {
|
||||
address: string;
|
||||
publicKey: string;
|
||||
}
|
||||
|
||||
export interface LedgerSignature {
|
||||
signature: string;
|
||||
}
|
||||
|
||||
export interface LedgerVersion {
|
||||
isLocked: boolean;
|
||||
isTestMode: boolean;
|
||||
version: [number, number, number];
|
||||
}
|
||||
|
||||
export interface TransportDef {
|
||||
create (): Promise<Transport>;
|
||||
type: LedgerTypes;
|
||||
}
|
||||
Reference in New Issue
Block a user