From 7e6997ed9ccae6c16d7782d75badcaa88d319845 Mon Sep 17 00:00:00 2001 From: kata Date: Fri, 18 Dec 2020 20:28:38 +0800 Subject: [PATCH 1/7] chore: enable hardware wallet menu --- .../src/components/WalletSetting/index.tsx | 9 +++---- .../neuron-wallet/src/controllers/app/menu.ts | 27 +++++++++---------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/packages/neuron-ui/src/components/WalletSetting/index.tsx b/packages/neuron-ui/src/components/WalletSetting/index.tsx index c612d5357f..c8730305ab 100644 --- a/packages/neuron-ui/src/components/WalletSetting/index.tsx +++ b/packages/neuron-ui/src/components/WalletSetting/index.tsx @@ -43,16 +43,13 @@ const buttons = [ url: RoutePath.ImportKeystore, icon: , }, -] - -if (process.env.NODE_ENV === 'development') { - buttons.push({ + { label: 'wizard.hardware-wallet', ariaLabel: 'import from hardware wallet', url: RoutePath.ImportHardware, icon: , - }) -} + }, +] const WalletSetting = ({ wallet: { id: currentID = '' }, diff --git a/packages/neuron-wallet/src/controllers/app/menu.ts b/packages/neuron-wallet/src/controllers/app/menu.ts index 643e0a1402..ac54b542fe 100644 --- a/packages/neuron-wallet/src/controllers/app/menu.ts +++ b/packages/neuron-wallet/src/controllers/app/menu.ts @@ -82,12 +82,12 @@ const navigateTo = (url: string) => { } } -// const importHardware = (url: string) => { -// const window = BrowserWindow.getFocusedWindow() -// if (window) { -// CommandSubject.next({ winID: window.id, type: 'import-hardware', payload: url, dispatchToUI: true }) -// } -// } +const importHardware = (url: string) => { + const window = BrowserWindow.getFocusedWindow() + if (window) { + CommandSubject.next({ winID: window.id, type: 'import-hardware', payload: url, dispatchToUI: true }) + } +} const loadTransaction = (url: string, json: OfflineSignJSON, filePath: string) => { const window = BrowserWindow.getFocusedWindow() @@ -208,14 +208,13 @@ const updateApplicationMenu = (mainWindow: BrowserWindow | null) => { } } }, - // COMMENT OUT UNTIL ledger app is approved - // { - // id: 'import-with-hardware', - // label: t('application-menu.wallet.import-hardware'), - // click: () => { - // importHardware(URL.ImportHardware) - // } - // } + { + id: 'import-with-hardware', + label: t('application-menu.wallet.import-hardware'), + click: () => { + importHardware(URL.ImportHardware) + } + } ], }, separator, From 5afe21a82efaa71dd333af6b8f214b1052714648 Mon Sep 17 00:00:00 2001 From: kata Date: Fri, 18 Dec 2020 10:57:40 +0800 Subject: [PATCH 2/7] chore: rename HardwareService.getPublicKey to #getExtendedPublicKey --- packages/neuron-wallet/src/controllers/api.ts | 2 +- packages/neuron-wallet/src/controllers/hardware.ts | 2 +- packages/neuron-wallet/tests/controllers/hardware.test.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/neuron-wallet/src/controllers/api.ts b/packages/neuron-wallet/src/controllers/api.ts index a27ef56ad5..b9aa806bc7 100644 --- a/packages/neuron-wallet/src/controllers/api.ts +++ b/packages/neuron-wallet/src/controllers/api.ts @@ -463,7 +463,7 @@ export default class ApiController { }) handle('get-device-public-key', async () => { - return this.hardwareController.getPublicKey() + return this.hardwareController.getExtendedPublicKey() }) handle('create-hardware-wallet', async (_, params: ExtendedPublicKey & { walletName: string }) => { diff --git a/packages/neuron-wallet/src/controllers/hardware.ts b/packages/neuron-wallet/src/controllers/hardware.ts index f6268d4614..6f00d562bc 100644 --- a/packages/neuron-wallet/src/controllers/hardware.ts +++ b/packages/neuron-wallet/src/controllers/hardware.ts @@ -45,7 +45,7 @@ export default class HardwareController { } } - public async getPublicKey (): Promise> { + public async getExtendedPublicKey (): Promise> { const device = HardwareWalletService.getInstance().getCurrent()! const pubkey = await device.getExtendedPublicKey() diff --git a/packages/neuron-wallet/tests/controllers/hardware.test.ts b/packages/neuron-wallet/tests/controllers/hardware.test.ts index 4dc8962fe6..ce8aa20342 100644 --- a/packages/neuron-wallet/tests/controllers/hardware.test.ts +++ b/packages/neuron-wallet/tests/controllers/hardware.test.ts @@ -37,7 +37,7 @@ describe('hardware controller', () => { }) it('#getPublicKey', async () => { - const { result } = await hardwareControler.getPublicKey() + const { result } = await hardwareControler.getExtendedPublicKey() expect(result!.publicKey).toBe(LedgerCkbApp.publicKey) expect(result!.chainCode).toBe(LedgerCkbApp.chainCode) }) From edd215f468c8b44dca738c9cc175e331c0211bb4 Mon Sep 17 00:00:00 2001 From: kata Date: Fri, 18 Dec 2020 17:57:52 +0800 Subject: [PATCH 3/7] chore: upgrade hw-app-ckb to 0.1.2 --- package.json | 2 +- packages/neuron-wallet/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c3885c466f..d385557152 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "packages/*" ], "scripts": { - "bootstrap": "yarn policies set-version 1.19.2 && npx cross-env LUMOS_NODE_RUNTIME=electron LUMOS_NODE_RUNTIME_VERSION=9.0.2 lerna bootstrap && lerna link", + "bootstrap": "npx cross-env LUMOS_NODE_RUNTIME=electron LUMOS_NODE_RUNTIME_VERSION=9.0.2 lerna bootstrap && lerna link", "start:ui": "cd packages/neuron-ui && yarn run start", "start:wallet": "cd packages/neuron-wallet && yarn run start:dev", "start": "concurrently \"cross-env BROWSER=none yarn run start:ui\" \"wait-on http://localhost:3000 && yarn run start:wallet\"", diff --git a/packages/neuron-wallet/package.json b/packages/neuron-wallet/package.json index b7c0bd0d7c..01540c45aa 100644 --- a/packages/neuron-wallet/package.json +++ b/packages/neuron-wallet/package.json @@ -50,7 +50,7 @@ "electron-updater": "4.2.0", "electron-window-state": "5.0.3", "elliptic": "6.5.3", - "hw-app-ckb": "0.1.1", + "hw-app-ckb": "0.1.2", "i18next": "17.0.13", "leveldown": "5.4.1", "levelup": "4.3.2", From f42e714d41a75797293a30c44f431a593ef5681e Mon Sep 17 00:00:00 2001 From: kata Date: Fri, 18 Dec 2020 19:46:25 +0800 Subject: [PATCH 4/7] feat: verify hardware address --- .../components/ImportHardware/confirming.tsx | 4 +- .../src/components/Receive/index.tsx | 30 ++- .../VerifyHardwareAddress/index.tsx | 233 ++++++++++++++++++ .../VerifyHardwareAddress/verify-error.tsx | 32 +++ .../verifyHardwareAddress.module.scss | 185 ++++++++++++++ packages/neuron-ui/src/locales/en.json | 26 +- packages/neuron-ui/src/locales/zh-tw.json | 21 +- packages/neuron-ui/src/locales/zh.json | 19 ++ .../neuron-ui/src/services/remote/hardware.ts | 9 +- .../src/services/remote/remoteApiWrapper.ts | 1 + packages/neuron-wallet/src/controllers/api.ts | 6 +- .../neuron-wallet/src/controllers/hardware.ts | 14 +- .../src/services/hardware/common.ts | 6 + .../src/services/hardware/hardware.ts | 3 +- .../src/services/hardware/ledger.ts | 8 + .../tests/controllers/hardware.test.ts | 7 + packages/neuron-wallet/tests/mock/hardware.ts | 10 + 17 files changed, 600 insertions(+), 14 deletions(-) create mode 100644 packages/neuron-ui/src/components/VerifyHardwareAddress/index.tsx create mode 100644 packages/neuron-ui/src/components/VerifyHardwareAddress/verify-error.tsx create mode 100644 packages/neuron-ui/src/components/VerifyHardwareAddress/verifyHardwareAddress.module.scss diff --git a/packages/neuron-ui/src/components/ImportHardware/confirming.tsx b/packages/neuron-ui/src/components/ImportHardware/confirming.tsx index 3c78ddca56..b7d42b655c 100644 --- a/packages/neuron-ui/src/components/ImportHardware/confirming.tsx +++ b/packages/neuron-ui/src/components/ImportHardware/confirming.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next' import { RouteComponentProps } from 'react-router-dom' import Button from 'widgets/Button' import { ReactComponent as PendingIcon } from 'widgets/Icons/Pending.svg' -import { getDevicePublickey } from 'services/remote' +import { getDeviceExtendedPublickey } from 'services/remote' import { isSuccessResponse, useDidMount } from 'utils' import { RoutePath, LocationState } from './common' @@ -17,7 +17,7 @@ const Confirming = ({ history, location }: RouteComponentProps<{}, {}, LocationS }, [history, entryPath]) useDidMount(() => { - getDevicePublickey().then(res => { + getDeviceExtendedPublickey().then(res => { if (isSuccessResponse(res)) { history.push({ pathname: entryPath + RoutePath.NameWallet, diff --git a/packages/neuron-ui/src/components/Receive/index.tsx b/packages/neuron-ui/src/components/Receive/index.tsx index 2af32d5596..75194c5e6e 100644 --- a/packages/neuron-ui/src/components/Receive/index.tsx +++ b/packages/neuron-ui/src/components/Receive/index.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useMemo } from 'react' +import React, { useCallback, useMemo, useState } from 'react' import { useRouteMatch, useHistory } from 'react-router-dom' import { useTranslation } from 'react-i18next' import Button from 'widgets/Button' @@ -6,18 +6,19 @@ import QRCode from 'widgets/QRCode' import CopyZone from 'widgets/CopyZone' import { RoutePath } from 'utils' import { useState as useGlobalState, useDispatch } from 'states' +import VerifyHardwareAddress from 'components/VerifyHardwareAddress' import styles from './receive.module.scss' const Receive = () => { - const { - wallet: { addresses = [] }, - } = useGlobalState() + const { wallet } = useGlobalState() const dispatch = useDispatch() const [t] = useTranslation() const { params: { address }, } = useRouteMatch() const history = useHistory() + const [displayVerifyDialog, setDisplayVerifyDialog] = useState(false) + const { addresses } = wallet const isSingleAddress = addresses.length === 1 const accountAddress = useMemo(() => { @@ -31,6 +32,10 @@ const Receive = () => { history.push(RoutePath.Addresses) }, [history]) + const onVerifyAddressClick = useCallback(() => { + setDisplayVerifyDialog(true) + }, []) + if (!accountAddress) { return
{t('receive.address-not-found')}
} @@ -58,6 +63,23 @@ const Receive = () => { onClick={onAddressBookClick} /> )} + {isSingleAddress && ( + + ) : ( + + )} + + + + ) + + if (error) { + container = + } + + return ( + + {container} + + ) +} + +VerifyHardwareAddress.displayName = 'VerifyHardwareAddress' + +export default VerifyHardwareAddress diff --git a/packages/neuron-ui/src/components/VerifyHardwareAddress/verify-error.tsx b/packages/neuron-ui/src/components/VerifyHardwareAddress/verify-error.tsx new file mode 100644 index 0000000000..948396d9c0 --- /dev/null +++ b/packages/neuron-ui/src/components/VerifyHardwareAddress/verify-error.tsx @@ -0,0 +1,32 @@ +import React from 'react' +import { useTranslation } from 'react-i18next' +import Button from 'widgets/Button' +import { ReactComponent as FailedInfo } from 'widgets/Icons/FailedInfo.svg' +import { errorFormatter } from 'utils' +import CopyZone from 'widgets/CopyZone' + +import styles from './verifyHardwareAddress.module.scss' + +const VerifyError = ({ error, onCancel }: { error: string; onCancel: () => void }) => { + const [t] = useTranslation() + const errorMsg = errorFormatter(error, t) + return ( +
+
+ + + +
+ {errorMsg} +
+
+
+
+
+ ) +} + +VerifyError.displayName = 'VerifyError' + +export default VerifyError diff --git a/packages/neuron-ui/src/components/VerifyHardwareAddress/verifyHardwareAddress.module.scss b/packages/neuron-ui/src/components/VerifyHardwareAddress/verifyHardwareAddress.module.scss new file mode 100644 index 0000000000..5136ad4e9e --- /dev/null +++ b/packages/neuron-ui/src/components/VerifyHardwareAddress/verifyHardwareAddress.module.scss @@ -0,0 +1,185 @@ +@import '../../styles/mixin.scss'; + +.dialog { + @include dialog-container; + padding: 30px 50px; + min-height: 225px; + height: 240px; + width: 600px; + + .container { + display: flex; + flex-direction: column; + height: 100%; + + .action { + @extend .main; + text-align: center; + .message { + margin-top: 26px; + font-weight: bold; + } + + +.footer { + justify-content: center; + } + + svg { + width: 56px; + height: 56px; + } + + .rotating { + svg { + animation: rotating 3s linear infinite; + } + } + } + + .main { + flex: 1; + tr { + td { + font-size: 14px; + svg { + width: 14px; + height: 14px; + margin-right: 4px; + position: relative; + top: 2px; + } + } + .first { + padding-right: 30px; + } + } + } + } + + &::backdrop { + @include overlay; + } + + .footer { + @include dialog-footer; + flex-shrink: 0; + + button { + margin-left: 10px; + } + + .left { + button { + margin: 0; + } + } + + .right { + display: flex; + flex: 1; + justify-content: flex-end; + } + } +} + +.table { + overflow: auto; +} + +.hd { + max-width: 700px; + width: 700px; + max-height: 400px; + height: 400px; +} + +.sign { + table { + border-collapse: collapse; + } + + thead { + border-bottom: 1px solid #e3e3e3; + } + + tbody tr:hover { + background-color: #f5f5f5; + } + + td { + height: 1.75rem; + word-wrap: none; + word-break: keep-all; + & > div { + text-overflow: ellipsis; + overflow: hidden; + width: 100%; + font-size: 13px; + } + } + + span, + td, + th { + font-size: 0.875rem; + letter-spacing: 0.5px; + padding: 0; + } + + th, + td { + &:first-of-type { + padding-left: 10px; + width: 80px; + } + + &:last-of-type { + padding-right: 10px; + width: 336px; + text-align: right; + } + } +} + +.active { + background-color: #eeeeee; +} + +.signed { + color: #888888; +} + +.tabs { + width: 100%; + display: flex; + margin-top: 15px; + flex-direction: row; + + button { + flex: 1; + cursor: pointer; + font-family: 'SourceCodePro-Regular', 'SourceHanSansCN-Regular', monospace; + font-size: 14px; + border: none; + background: none; + height: 30px; + + &.active { + font-weight: bold; + border-bottom: 4px solid #3cc68a; + } + } +} + +.warning { + color: #d03a3a; +} + +.title { + font-size: 1.125rem; + line-height: 1.375rem; + font-weight: bold; + letter-spacing: 0.9px; + margin: 0; + margin-bottom: 26px; +} diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index fbadfadbd1..8361dc8a1f 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -58,12 +58,12 @@ }, "hardware-sign": { "cancel": "Cancel", - "title": "Sign via hardware walllet", + "title": "Sign via hardware wallet", "device": "Device:", "status": { "label": "Status:", "connect": "Connected, ready for signing.", - "user-input": "Connected, waiting for user input...", + "user-input": "Connected, waiting for confirmation on device...", "disconnect": "Disconnected, please check your connection." }, "inputs": "Inputs(signing {{index}} of {{length}})", @@ -74,6 +74,25 @@ "rescan": "Rescan" } }, + "hardware-verify-address": { + "title": "Verify address via hardware wallet", + "device": "Device:", + "address": "Address:", + "verified": "Verified", + "invalid": "Invalid", + "status": { + "label": "Status:", + "connect": "Connected, ready for verifying.", + "user-input": "Connected, waiting for confirmation on device...", + "disconnect": "Disconnected, please check your connection." + }, + "actions": { + "close": "Close", + "rescan": "Rescan", + "copy-address": "Copy Address", + "verify": "Verify" + } + }, "offline-sign": { "title": "Offline Sign", "json-file": "JSON file:", @@ -200,7 +219,8 @@ "address-not-found": "Address not found", "prompt": "Neuron picks a new receiving address for better privacy. Please go to the Address Book if you want to use a previously used receiving address.", "address-qrcode": "Address QR Code", - "address": "{{network}} Address" + "address": "{{network}} Address", + "verify-address": "Verify Address" }, "history": { "meta": "Meta", diff --git a/packages/neuron-ui/src/locales/zh-tw.json b/packages/neuron-ui/src/locales/zh-tw.json index d58dfbe791..784a971179 100644 --- a/packages/neuron-ui/src/locales/zh-tw.json +++ b/packages/neuron-ui/src/locales/zh-tw.json @@ -62,11 +62,30 @@ "disconnect": "未連接,請檢查設備連接。" }, "actions": { - "close": "关闭", + "close": "關閉", "success": "交易成功", "rescan": "再次檢測" } }, + "hardware-verify-address": { + "title": "使用硬件錢包進行地址驗證", + "device": "設備:", + "address": "地址:", + "verified": "驗證通過", + "invalid": "地址不正確", + "status": { + "label": "狀態:", + "connect": "已連接", + "user-input": "已連接,等待確認...", + "disconnect": "未連接,請檢查設備連接。" + }, + "actions": { + "close": "關閉", + "rescan": "再次檢測", + "copy-address": "复制地址", + "verify": "驗證" + } + }, "offline-sign": { "title": "離線簽名", "json-file": "JSON 檔案:", diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index bb71cf775c..f07a7aab50 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -67,6 +67,25 @@ "rescan": "再次检测" } }, + "hardware-verify-address": { + "title": "使用硬件钱包进行地址验证", + "device": "设备:", + "address": "地址:", + "verified": "验证通过", + "invalid": "地址不正确", + "status": { + "label": "状态:", + "connect": "已连接", + "user-input": "已连接,等待确认...", + "disconnect": "未连接,请检查设备连接。" + }, + "actions": { + "close": "关闭", + "rescan": "再次检测", + "copy-address": "复制地址", + "verify": "验证" + } + }, "offline-sign": { "title": "离线签名", "json-file": "JSON 文件:", diff --git a/packages/neuron-ui/src/services/remote/hardware.ts b/packages/neuron-ui/src/services/remote/hardware.ts index 153c27dfb9..da01bae6d0 100644 --- a/packages/neuron-ui/src/services/remote/hardware.ts +++ b/packages/neuron-ui/src/services/remote/hardware.ts @@ -21,13 +21,20 @@ export interface ExtendedPublicKey { chainCode: string } +export interface PublicKey { + publicKey: string + lockArg: string + address: string +} + export type Descriptor = string export type Version = string export const getDevices = remoteApi('detect-device') export const getDeviceCkbAppVersion = remoteApi('get-device-ckb-app-version') export const getDeviceFirmwareVersion = remoteApi('get-device-firmware-version') -export const getDevicePublickey = remoteApi('get-device-public-key') +export const getDeviceExtendedPublickey = remoteApi('get-device-extended-public-key') +export const getDevicePublicKey = remoteApi('get-device-public-key') export const connectDevice = remoteApi('connect-device') export const createHardwareWallet = remoteApi( 'create-hardware-wallet' diff --git a/packages/neuron-ui/src/services/remote/remoteApiWrapper.ts b/packages/neuron-ui/src/services/remote/remoteApiWrapper.ts index bebc226d42..9944b7f502 100644 --- a/packages/neuron-ui/src/services/remote/remoteApiWrapper.ts +++ b/packages/neuron-ui/src/services/remote/remoteApiWrapper.ts @@ -107,6 +107,7 @@ type Action = | 'get-device-ckb-app-version' | 'get-device-firmware-version' | 'get-device-public-key' + | 'get-device-extended-public-key' | 'connect-device' | 'create-hardware-wallet' // offline-signature diff --git a/packages/neuron-wallet/src/controllers/api.ts b/packages/neuron-wallet/src/controllers/api.ts index b9aa806bc7..8bab05afcb 100644 --- a/packages/neuron-wallet/src/controllers/api.ts +++ b/packages/neuron-wallet/src/controllers/api.ts @@ -462,10 +462,14 @@ export default class ApiController { return this.hardwareController.getFirmwareVersion() }) - handle('get-device-public-key', async () => { + handle('get-device-extended-public-key', async () => { return this.hardwareController.getExtendedPublicKey() }) + handle('get-device-public-key', async () => { + return this.hardwareController.getPublicKey() + }) + handle('create-hardware-wallet', async (_, params: ExtendedPublicKey & { walletName: string }) => { return await this.walletsController.importHardwareWallet(params) }) diff --git a/packages/neuron-wallet/src/controllers/hardware.ts b/packages/neuron-wallet/src/controllers/hardware.ts index 6f00d562bc..c1e9c4e9a1 100644 --- a/packages/neuron-wallet/src/controllers/hardware.ts +++ b/packages/neuron-wallet/src/controllers/hardware.ts @@ -1,7 +1,8 @@ -import { DeviceInfo, ExtendedPublicKey } from "services/hardware/common"; +import { DeviceInfo, ExtendedPublicKey, PublicKey } from "services/hardware/common"; import { ResponseCode } from "utils/const" import HardwareWalletService from "services/hardware"; import { connectDeviceFailed } from "exceptions"; +import { AccountExtendedPublicKey } from "models/keys/key"; export default class HardwareController { public async connectDevice (deviceInfo: DeviceInfo): Promise> { @@ -54,4 +55,15 @@ export default class HardwareController { result: pubkey, } } + + public async getPublicKey (): Promise> { + const device = HardwareWalletService.getInstance().getCurrent()! + const defaultPath = AccountExtendedPublicKey.ckbAccountPath + const pubkey = await device.getPublicKey(defaultPath) + + return { + status: ResponseCode.Success, + result: pubkey, + } + } } diff --git a/packages/neuron-wallet/src/services/hardware/common.ts b/packages/neuron-wallet/src/services/hardware/common.ts index c2a11a021a..57cf637f8f 100644 --- a/packages/neuron-wallet/src/services/hardware/common.ts +++ b/packages/neuron-wallet/src/services/hardware/common.ts @@ -22,3 +22,9 @@ export interface ExtendedPublicKey { publicKey: string chainCode: string } + +export interface PublicKey { + publicKey: string + lockArg: string + address: string +} diff --git a/packages/neuron-wallet/src/services/hardware/hardware.ts b/packages/neuron-wallet/src/services/hardware/hardware.ts index c16dc85a58..0623620cdc 100644 --- a/packages/neuron-wallet/src/services/hardware/hardware.ts +++ b/packages/neuron-wallet/src/services/hardware/hardware.ts @@ -6,7 +6,7 @@ import TransactionSender from 'services/transaction-sender' import MultiSign from 'models/multi-sign' import WalletService from 'services/wallets' import DeviceSignIndexSubject from 'models/subjects/device-sign-index-subject' -import type { DeviceInfo, ExtendedPublicKey } from './common' +import type { DeviceInfo, ExtendedPublicKey, PublicKey } from './common' import { AccountExtendedPublicKey } from 'models/keys/key' export abstract class Hardware { @@ -113,6 +113,7 @@ export abstract class Hardware { return tx } + public abstract getPublicKey(path: string): Promise public abstract getExtendedPublicKey(): Promise public abstract connect(hardwareInfo?: DeviceInfo): Promise public abstract signMessage(path: string, messageHex: string): Promise diff --git a/packages/neuron-wallet/src/services/hardware/ledger.ts b/packages/neuron-wallet/src/services/hardware/ledger.ts index 25cc216960..e46183728f 100644 --- a/packages/neuron-wallet/src/services/hardware/ledger.ts +++ b/packages/neuron-wallet/src/services/hardware/ledger.ts @@ -12,6 +12,7 @@ import NodeService from 'services/node' import Address, { AddressType } from 'models/keys/address' import HexUtils from 'utils/hex' import logger from 'utils/logger' +import NetworksService from 'services/networks' export default class Ledger extends Hardware { private ledgerCKB: LedgerCKB | null = null @@ -94,6 +95,13 @@ export default class Ledger extends Hardware { return version } + async getPublicKey (path: string) { + const networkService = NetworksService.getInstance() + const isTestnet = !networkService.isMainnet() + const result = await this.ledgerCKB!.getWalletPublicKey(path === Address.pathForReceiving(0) ? this.defaultPath : path, isTestnet) + return result + } + public static async findDevices () { const devices = await Promise.all([ Ledger.searchDevices(HID.listen, false), diff --git a/packages/neuron-wallet/tests/controllers/hardware.test.ts b/packages/neuron-wallet/tests/controllers/hardware.test.ts index ce8aa20342..d87435d05a 100644 --- a/packages/neuron-wallet/tests/controllers/hardware.test.ts +++ b/packages/neuron-wallet/tests/controllers/hardware.test.ts @@ -37,6 +37,13 @@ describe('hardware controller', () => { }) it('#getPublicKey', async () => { + const { result } = await hardwareControler.getPublicKey() + expect(result!.publicKey).toBe(LedgerCkbApp.publicKey) + expect(result!.lockArg).toBe(LedgerCkbApp.lockArg) + expect(result!.address).toBe(LedgerCkbApp.address) + }) + + it('#getExtendedPublicKey', async () => { const { result } = await hardwareControler.getExtendedPublicKey() expect(result!.publicKey).toBe(LedgerCkbApp.publicKey) expect(result!.chainCode).toBe(LedgerCkbApp.chainCode) diff --git a/packages/neuron-wallet/tests/mock/hardware.ts b/packages/neuron-wallet/tests/mock/hardware.ts index dd64285ddc..166feaf459 100644 --- a/packages/neuron-wallet/tests/mock/hardware.ts +++ b/packages/neuron-wallet/tests/mock/hardware.ts @@ -84,6 +84,16 @@ export class LedgerCkbApp { public static publicKey = 'publicKey' public static chainCode = 'chain_code' public static version = '0.4.0' + public static lockArg = 'args' + public static address = 'address' + + async getWalletPublicKey () { + return { + publicKey: LedgerCkbApp.publicKey, + lockArg: LedgerCkbApp.lockArg, + address: LedgerCkbApp.address + } + } async getWalletExtendedPublicKey () { return { From 070adfdb4f28c7b7c6d43ab0b790e8b997b6dba6 Mon Sep 17 00:00:00 2001 From: kata Date: Sat, 19 Dec 2020 11:57:31 +0800 Subject: [PATCH 5/7] chore: upgrade sqlite to 5 to update pipeline to use node 14 and install libudev-dev for ubuntu --- azure-pipelines.yml | 24 +++++++++++++++--------- packages/neuron-wallet/package.json | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 190e0cbdd7..05c27db908 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -26,8 +26,8 @@ stages: vmImage: 'macos-10.14' strategy: matrix: - node_12_x: - node_version: 12.x + node_14_x: + node_version: 14.x steps: - task: NodeTool@0 inputs: @@ -47,13 +47,16 @@ stages: vmImage: 'ubuntu-18.04' strategy: matrix: - node_12_x: - node_version: 12.x + node_14_x: + node_version: 14.x steps: - task: NodeTool@0 inputs: versionSpec: $(node_version) displayName: 'Install Node.js' + - script: | + sudo apt-get install -y libudev-dev + displayName: Install libudev - script: | yarn global add lerna yarn bootstrap @@ -71,8 +74,8 @@ stages: vmImage: 'vs2017-win2016' strategy: matrix: - node_12_x: - node_version: 12.x + node_14_x: + node_version: 14.x steps: - task: NodeTool@0 inputs: @@ -101,7 +104,7 @@ stages: steps: - task: NodeTool@0 inputs: - versionSpec: 12.x + versionSpec: 14.x displayName: 'Install Node.js' - script: | yarn global add lerna @@ -131,8 +134,11 @@ stages: steps: - task: NodeTool@0 inputs: - versionSpec: 12.x + versionSpec: 14.x displayName: 'Install Node.js' + - script: | + sudo apt-get install -y libudev-dev + displayName: Install libudev - script: | yarn global add lerna yarn bootstrap @@ -152,7 +158,7 @@ stages: steps: - task: NodeTool@0 inputs: - versionSpec: 12.x + versionSpec: 14.x displayName: 'Install Node.js' - script: yarn global add lerna displayName: 'Install lerna' diff --git a/packages/neuron-wallet/package.json b/packages/neuron-wallet/package.json index 01540c45aa..12fc1af6ab 100644 --- a/packages/neuron-wallet/package.json +++ b/packages/neuron-wallet/package.json @@ -57,7 +57,7 @@ "reflect-metadata": "0.1.13", "rxjs": "6.5.3", "sha3": "2.0.7", - "sqlite3": "4.1.1", + "sqlite3": "5.0.0", "subleveldown": "^4.1.4", "typeorm": "0.2.20", "uuid": "3.3.3" From 516d6aadbbf7c76dc6ba9ee688b5f0f7470726a3 Mon Sep 17 00:00:00 2001 From: kata Date: Sat, 19 Dec 2020 14:58:17 +0800 Subject: [PATCH 6/7] fix: add locales for verify-address --- packages/neuron-ui/src/locales/zh-tw.json | 3 ++- packages/neuron-ui/src/locales/zh.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/neuron-ui/src/locales/zh-tw.json b/packages/neuron-ui/src/locales/zh-tw.json index 784a971179..8db3d4101e 100644 --- a/packages/neuron-ui/src/locales/zh-tw.json +++ b/packages/neuron-ui/src/locales/zh-tw.json @@ -212,7 +212,8 @@ "address-not-found": "未找到地址", "prompt": "為了保護隱私,Neuron 會自動選擇一個新收款地址。如果您想使用舊的收款地址,請訪問地址簿頁面。", "address-qrcode": "地址二維碼", - "address": "{{network}} 地址" + "address": "{{network}} 地址", + "verify-address": "驗證地址" }, "history": { "meta": "元信息", diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index f07a7aab50..50e966c815 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -212,7 +212,8 @@ "address-not-found": "未找到地址", "prompt": "为了保护隐私,Neuron 会自动选择一个新收款地址。如果您想使用旧的收款地址,请访问地址簿页面。", "address-qrcode": "地址二维码", - "address": "{{network}} 地址" + "address": "{{network}} 地址", + "verify-address": "验证地址" }, "history": { "meta": "元信息", From 77a8012de91b62288364c7db889ed0bf9923649e Mon Sep 17 00:00:00 2001 From: kellyshang Date: Sat, 19 Dec 2020 15:57:17 +0800 Subject: [PATCH 7/7] chore: bump version to v0.35.0-rc1, and update the CHANGELOG.md --- CHANGELOG.md | 12 ++++++++++++ lerna.json | 2 +- package.json | 2 +- packages/neuron-ui/package.json | 2 +- packages/neuron-wallet/package.json | 4 ++-- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8aef31da7e..84574240e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +# 0.35.0-rc1 (2020-12-19) + +This is a release candidate to preview the changes in the next official release and may not be stable. Welcome any questions or suggestions. + +[CKB v0.35.1](https://github.com/nervosnetwork/ckb/releases/tag/v0.35.1) was released on Sept. 14th, 2020. This version of CKB node is now bundled and preconfigured in Neuron. + +### New features + +* Enable hardware wallet of Ledger. +* Support address verification on hardware wallet device. + + # 0.34.0 (2020-12-16) [CKB v0.35.1](https://github.com/nervosnetwork/ckb/releases/tag/v0.35.1) was released on Sept. 14th, 2020. This version of CKB node is now bundled and preconfigured in Neuron. diff --git a/lerna.json b/lerna.json index 06451e9d1a..995ae7790e 100644 --- a/lerna.json +++ b/lerna.json @@ -2,7 +2,7 @@ "packages": [ "packages/*" ], - "version": "0.34.0", + "version": "0.35.0-rc1", "npmClient": "yarn", "useWorkspaces": true } diff --git a/package.json b/package.json index d385557152..7fc703dfa3 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "neuron", "productName": "Neuron", "description": "CKB Neuron Wallet", - "version": "0.34.0", + "version": "0.35.0-rc1", "private": true, "author": { "name": "Nervos Core Dev", diff --git a/packages/neuron-ui/package.json b/packages/neuron-ui/package.json index d05aa7bbc6..9e0e148e86 100644 --- a/packages/neuron-ui/package.json +++ b/packages/neuron-ui/package.json @@ -1,6 +1,6 @@ { "name": "neuron-ui", - "version": "0.34.0", + "version": "0.35.0-rc1", "private": true, "author": { "name": "Nervos Core Dev", diff --git a/packages/neuron-wallet/package.json b/packages/neuron-wallet/package.json index 12fc1af6ab..dee34a9f97 100644 --- a/packages/neuron-wallet/package.json +++ b/packages/neuron-wallet/package.json @@ -3,7 +3,7 @@ "productName": "Neuron", "description": "CKB Neuron Wallet", "homepage": "https://www.nervos.org/", - "version": "0.34.0", + "version": "0.35.0-rc1", "private": true, "author": { "name": "Nervos Core Dev", @@ -85,7 +85,7 @@ "electron-notarize": "0.2.1", "jest-when": "2.7.2", "lint-staged": "9.2.5", - "neuron-ui": "0.34.0", + "neuron-ui": "0.35.0-rc1", "rimraf": "3.0.0", "ttypescript": "1.5.10" }