From 7d0a82b3b8fb99e7b4c891db4c5a28e257561a7e Mon Sep 17 00:00:00 2001 From: Tom Wang Date: Tue, 14 May 2024 22:45:26 +0800 Subject: [PATCH 1/7] refactor: replace models/keys/mnemonic with lumos hd --- .../neuron-wallet/src/controllers/wallets.ts | 5 +- .../src/database/address/meta.ts | 2 +- .../chain/entities/hd-public-key-info.ts | 2 +- packages/neuron-wallet/src/models/address.ts | 2 +- .../neuron-wallet/src/models/keys/address.ts | 10 +- .../src/models/keys/hd-public-key-info.ts | 3 +- packages/neuron-wallet/src/models/keys/key.ts | 23 +- .../src/models/keys/mnemonic/index.ts | 150 -- .../src/models/keys/mnemonic/word-list.ts | 2050 ----------------- .../neuron-wallet/src/services/addresses.ts | 5 +- .../src/services/hardware/common.ts | 2 +- .../src/services/hardware/ledger.ts | 3 +- .../neuron-wallet/src/services/wallets.ts | 3 +- .../full-synchronizer.test.ts | 2 +- .../indexer-cache-service.intg.test.ts | 2 +- .../tests/block-sync-renderer/queue.test.ts | 2 +- .../block-sync-renderer/synchronizer.test.ts | 2 +- .../tests/database/address/meta.test.ts | 2 +- packages/neuron-wallet/tests/mock/hardware.ts | 2 +- .../tests/models/asset-account-info.test.ts | 2 +- .../tests/models/keys/address.test.ts | 3 +- .../models/keys/hd-public-key-info.test.ts | 2 +- .../tests/models/keys/key.test.ts | 16 +- .../tests/models/keys/mnemonic/fixtures.json | 147 -- .../tests/models/keys/mnemonic/index.test.ts | 26 - .../tests/services/address.test.ts | 2 +- .../services/asset-account-service.test.ts | 2 +- .../tests/services/tx-wallet.test.ts | 2 +- .../services/tx/transaction-sender.test.ts | 2 +- .../tests/services/wallets.test.ts | 2 +- .../public-key-info.fixture.ts | 2 +- 31 files changed, 41 insertions(+), 2439 deletions(-) delete mode 100644 packages/neuron-wallet/src/models/keys/mnemonic/index.ts delete mode 100644 packages/neuron-wallet/src/models/keys/mnemonic/word-list.ts delete mode 100644 packages/neuron-wallet/tests/models/keys/mnemonic/fixtures.json delete mode 100644 packages/neuron-wallet/tests/models/keys/mnemonic/index.test.ts diff --git a/packages/neuron-wallet/src/controllers/wallets.ts b/packages/neuron-wallet/src/controllers/wallets.ts index 08203144c7..ad5b3fef6a 100644 --- a/packages/neuron-wallet/src/controllers/wallets.ts +++ b/packages/neuron-wallet/src/controllers/wallets.ts @@ -5,8 +5,9 @@ import WalletsService, { Wallet, WalletProperties, FileKeystoreWallet } from '.. import NetworksService from '../services/networks' import Keystore from '../models/keys/keystore' import Keychain from '../models/keys/keychain' -import { validateMnemonic, mnemonicToSeedSync } from '../models/keys/mnemonic' -import { AccountExtendedPublicKey, ExtendedPrivateKey, generateMnemonic } from '../models/keys/key' +import { validateMnemonic, mnemonicToSeedSync } from '@ckb-lumos/hd/lib/mnemonic' +import { AccountExtendedPublicKey, ExtendedPrivateKey } from '../models/keys/key' +import { generateMnemonic } from '@ckb-lumos/hd/lib/mnemonic' import CommandSubject from '../models/subjects/command' import { ResponseCode } from '../utils/const' import { diff --git a/packages/neuron-wallet/src/database/address/meta.ts b/packages/neuron-wallet/src/database/address/meta.ts index 3fd8f99abc..36de7a34f3 100644 --- a/packages/neuron-wallet/src/database/address/meta.ts +++ b/packages/neuron-wallet/src/database/address/meta.ts @@ -1,6 +1,6 @@ import { bytes } from '@ckb-lumos/codec' import { Address, AddressVersion } from '../../models/address' -import { AddressType } from '../../models/keys/address' +import { AddressType } from '@ckb-lumos/hd' import Script from '../../models/chain/script' import SystemScriptInfo from '../../models/system-script-info' import AssetAccountInfo from '../../models/asset-account-info' diff --git a/packages/neuron-wallet/src/database/chain/entities/hd-public-key-info.ts b/packages/neuron-wallet/src/database/chain/entities/hd-public-key-info.ts index e06e3d5632..e5fa061106 100644 --- a/packages/neuron-wallet/src/database/chain/entities/hd-public-key-info.ts +++ b/packages/neuron-wallet/src/database/chain/entities/hd-public-key-info.ts @@ -1,6 +1,6 @@ import { Entity, Column, PrimaryGeneratedColumn, Index, CreateDateColumn } from 'typeorm' import HdPublicKeyInfoModel from '../../../models/keys/hd-public-key-info' -import { AddressType } from '../../../models/keys/address' +import { AddressType } from '@ckb-lumos/hd' @Entity() export default class HdPublicKeyInfo { diff --git a/packages/neuron-wallet/src/models/address.ts b/packages/neuron-wallet/src/models/address.ts index 7b3940cb95..f8827a1c78 100644 --- a/packages/neuron-wallet/src/models/address.ts +++ b/packages/neuron-wallet/src/models/address.ts @@ -1,4 +1,4 @@ -import { AddressType } from '../models/keys/address' +import { AddressType } from '@ckb-lumos/hd' export enum AddressVersion { Testnet = 'testnet', diff --git a/packages/neuron-wallet/src/models/keys/address.ts b/packages/neuron-wallet/src/models/keys/address.ts index 3e460284d9..61a5e2482c 100644 --- a/packages/neuron-wallet/src/models/keys/address.ts +++ b/packages/neuron-wallet/src/models/keys/address.ts @@ -1,11 +1,11 @@ import { scriptToAddress } from '../../utils/scriptAndAddress' import { AccountExtendedPublicKey } from './key' import { systemScripts } from '../../utils/systemScripts' -import hd from '@ckb-lumos/hd' +import { key, AddressType } from '@ckb-lumos/hd' -export enum AddressType { - Receiving = 0, // External chain - Change = 1, // Internal chain +export enum DefaultAddressNumber { + Receiving = 20, + Change = 10, } export const publicKeyToAddress = (publicKey: string, isMainnet = false) => { @@ -14,7 +14,7 @@ export const publicKeyToAddress = (publicKey: string, isMainnet = false) => { { codeHash: systemScripts.SECP256K1_BLAKE160.CODE_HASH, hashType: systemScripts.SECP256K1_BLAKE160.HASH_TYPE, - args: hd.key.publicKeyToBlake160(pubkey), + args: key.publicKeyToBlake160(pubkey), }, isMainnet ) diff --git a/packages/neuron-wallet/src/models/keys/hd-public-key-info.ts b/packages/neuron-wallet/src/models/keys/hd-public-key-info.ts index d8f8a7f4e3..49bc9845d2 100644 --- a/packages/neuron-wallet/src/models/keys/hd-public-key-info.ts +++ b/packages/neuron-wallet/src/models/keys/hd-public-key-info.ts @@ -1,7 +1,8 @@ import { scriptToAddress } from '../../utils/scriptAndAddress' import SystemScriptInfo from '../../models/system-script-info' import NetworksService from '../../services/networks' -import Address, { AddressType } from './address' +import { AddressType } from '@ckb-lumos/hd' +import Address from './address' export default class HdPublicKeyInfoModel { public walletId: string diff --git a/packages/neuron-wallet/src/models/keys/key.ts b/packages/neuron-wallet/src/models/keys/key.ts index 5e5ae9c939..b1a9c7e173 100644 --- a/packages/neuron-wallet/src/models/keys/key.ts +++ b/packages/neuron-wallet/src/models/keys/key.ts @@ -1,8 +1,6 @@ -import crypto from 'crypto' - -import Address, { AddressType } from './address' +import { AddressType } from '@ckb-lumos/hd' +import Address from './address' import Keychain, { privateToPublic } from './keychain' -import { entropyToMnemonic } from './mnemonic' export interface PathAndPrivateKey { path: string @@ -95,20 +93,3 @@ export class ExtendedPrivateKey { return new ExtendedPrivateKey(serialized.slice(0, 64), serialized.slice(64)) } } - -export enum DefaultAddressNumber { - Receiving = 20, - Change = 10, -} - -export interface Addresses { - receiving: Address[] - change: Address[] -} - -// Generate 12 words mnemonic code -export const generateMnemonic = () => { - const entropySize = 16 - const entropy = crypto.randomBytes(entropySize).toString('hex') - return entropyToMnemonic(entropy) -} diff --git a/packages/neuron-wallet/src/models/keys/mnemonic/index.ts b/packages/neuron-wallet/src/models/keys/mnemonic/index.ts deleted file mode 100644 index a84ed544c2..0000000000 --- a/packages/neuron-wallet/src/models/keys/mnemonic/index.ts +++ /dev/null @@ -1,150 +0,0 @@ -import crypto from 'crypto' -import wordList from './word-list' - -const RADIX = 2048 -const PBKDF2_ROUNDS = 2048 -const KEY_LEN = 64 -const MIN_ENTROPY_SIZE = 16 -const MAX_ENTROPY_SIZE = 32 -const MIN_WORDS_SIZE = 12 -const MAX_WORDS_SIZE = 24 - -const INVALID_MNEMONIC = `Invalid mnemonic` -const INVALID_CHECKSUM = `Invalid checksum` -const ENTROPY_NOT_DIVISIBLE = `Entropy should be divisible by 4` -const ENTROPY_TOO_LONG = `Entropy should be shorter than ${MAX_ENTROPY_SIZE + 1}` -const ENTROPY_TOO_SHORT = `Entropy should be longer than ${MIN_ENTROPY_SIZE - 1}` -const WORDS_TOO_LONG = `Words should be shorter than ${MAX_WORDS_SIZE + 1}` -const WORDS_TOO_SHORT = `Words should be longer than ${MIN_WORDS_SIZE - 1}` - -if (wordList.length !== RADIX) { - throw new Error(`Word list should have ${RADIX} words, but ${wordList.length} received in fact`) -} - -const bytesToBinary = (bytes: Buffer): string => { - return bytes.reduce((binary, byte) => { - return binary + byte.toString(2).padStart(8, '0') - }, '') -} - -const deriveChecksumBits = (entropyBuffer: Buffer): string => { - const ENT = entropyBuffer.length * 8 - const CS = ENT / 32 - const hash = crypto.createHash('sha256').update(entropyBuffer).digest() - return bytesToBinary(hash).slice(0, CS) -} - -const salt = (password = '') => { - return `mnemonic${password}` -} - -export const mnemonicToSeedSync = (mnemonic: string = '', password: string = '') => { - const mnemonicBuffer = Buffer.from(mnemonic.normalize('NFKD'), 'utf8') - const saltBuffer = Buffer.from(salt(password.normalize('NFKD')), 'utf8') - return crypto.pbkdf2Sync(mnemonicBuffer, saltBuffer, PBKDF2_ROUNDS, KEY_LEN, 'sha512') -} - -export function mnemonicToSeed(mnemonic: string = '', password: string = ''): Promise { - return new Promise((resolve, reject) => { - try { - const mnemonicBuffer = Buffer.from(mnemonic.normalize('NFKD'), 'utf8') - const saltBuffer = Buffer.from(salt(password.normalize('NFKD')), 'utf8') - crypto.pbkdf2(mnemonicBuffer, saltBuffer, PBKDF2_ROUNDS, KEY_LEN, 'sha512', (err, data) => { - if (err) { - reject(err) - } - resolve(data) - }) - } catch (error) { - reject(error) - } - }) -} - -export function mnemonicToEntropy(mnemonic: string = '') { - const words = mnemonic.normalize('NFKD').split(' ') - if (words.length < MIN_WORDS_SIZE) { - throw new Error(WORDS_TOO_SHORT) - } - if (words.length > MAX_WORDS_SIZE) { - throw new Error(WORDS_TOO_LONG) - } - if (words.length % 3 !== 0) { - throw new Error(INVALID_MNEMONIC) - } - const bits = words - .map(word => { - const index = wordList!.indexOf(word) - if (index === -1) { - throw new Error(INVALID_MNEMONIC) - } - return index.toString(2).padStart(11, '0') - }) - .join('') - - const dividerIndex = Math.floor(bits.length / 33) * 32 - const entropyBits = bits.slice(0, dividerIndex) - const checksumBits = bits.slice(dividerIndex) - - const entropyBytes = entropyBits.match(/(.{1,8})/g)!.map(byte => parseInt(byte, 2)) - if (entropyBytes.length < MIN_ENTROPY_SIZE) { - throw new Error(ENTROPY_TOO_SHORT) - } - if (entropyBytes.length > MAX_ENTROPY_SIZE) { - throw new Error(ENTROPY_TOO_LONG) - } - if (entropyBytes.length % 4 !== 0) { - throw new Error(ENTROPY_NOT_DIVISIBLE) - } - - const entropy = Buffer.from(entropyBytes) - const newChecksum = deriveChecksumBits(entropy) - if (newChecksum !== checksumBits) { - throw new Error(INVALID_CHECKSUM) - } - - return entropy.toString('hex') -} - -export function entropyToMnemonic(entropyStr: string) { - const entropy = Buffer.from(entropyStr, 'hex') - - if (entropy.length < MIN_ENTROPY_SIZE) { - throw new TypeError(ENTROPY_TOO_SHORT) - } - if (entropy.length > MAX_ENTROPY_SIZE) { - throw new TypeError(ENTROPY_TOO_LONG) - } - if (entropy.length % 4 !== 0) { - throw new TypeError(ENTROPY_NOT_DIVISIBLE) - } - - const entropyBytes = bytesToBinary(entropy) - const checksumBytes = deriveChecksumBits(entropy) - - const bytes = entropyBytes + checksumBytes - const chunks = bytes.match(/(.{1,11})/g)! - const words = chunks.map(binary => { - const index = parseInt(binary, 2) - return wordList[index] - }) - - return words.join(' ') -} - -export function validateMnemonic(mnemonic: string) { - try { - mnemonicToEntropy(mnemonic) - } catch (e) { - return false - } - return true -} - -export default { - entropyToMnemonic, - mnemonicToEntropy, - mnemonicToSeed, - mnemonicToSeedSync, - validateMnemonic, -} diff --git a/packages/neuron-wallet/src/models/keys/mnemonic/word-list.ts b/packages/neuron-wallet/src/models/keys/mnemonic/word-list.ts deleted file mode 100644 index f5d81d3377..0000000000 --- a/packages/neuron-wallet/src/models/keys/mnemonic/word-list.ts +++ /dev/null @@ -1,2050 +0,0 @@ -export default [ - 'abandon', - 'ability', - 'able', - 'about', - 'above', - 'absent', - 'absorb', - 'abstract', - 'absurd', - 'abuse', - 'access', - 'accident', - 'account', - 'accuse', - 'achieve', - 'acid', - 'acoustic', - 'acquire', - 'across', - 'act', - 'action', - 'actor', - 'actress', - 'actual', - 'adapt', - 'add', - 'addict', - 'address', - 'adjust', - 'admit', - 'adult', - 'advance', - 'advice', - 'aerobic', - 'affair', - 'afford', - 'afraid', - 'again', - 'age', - 'agent', - 'agree', - 'ahead', - 'aim', - 'air', - 'airport', - 'aisle', - 'alarm', - 'album', - 'alcohol', - 'alert', - 'alien', - 'all', - 'alley', - 'allow', - 'almost', - 'alone', - 'alpha', - 'already', - 'also', - 'alter', - 'always', - 'amateur', - 'amazing', - 'among', - 'amount', - 'amused', - 'analyst', - 'anchor', - 'ancient', - 'anger', - 'angle', - 'angry', - 'animal', - 'ankle', - 'announce', - 'annual', - 'another', - 'answer', - 'antenna', - 'antique', - 'anxiety', - 'any', - 'apart', - 'apology', - 'appear', - 'apple', - 'approve', - 'april', - 'arch', - 'arctic', - 'area', - 'arena', - 'argue', - 'arm', - 'armed', - 'armor', - 'army', - 'around', - 'arrange', - 'arrest', - 'arrive', - 'arrow', - 'art', - 'artefact', - 'artist', - 'artwork', - 'ask', - 'aspect', - 'assault', - 'asset', - 'assist', - 'assume', - 'asthma', - 'athlete', - 'atom', - 'attack', - 'attend', - 'attitude', - 'attract', - 'auction', - 'audit', - 'august', - 'aunt', - 'author', - 'auto', - 'autumn', - 'average', - 'avocado', - 'avoid', - 'awake', - 'aware', - 'away', - 'awesome', - 'awful', - 'awkward', - 'axis', - 'baby', - 'bachelor', - 'bacon', - 'badge', - 'bag', - 'balance', - 'balcony', - 'ball', - 'bamboo', - 'banana', - 'banner', - 'bar', - 'barely', - 'bargain', - 'barrel', - 'base', - 'basic', - 'basket', - 'battle', - 'beach', - 'bean', - 'beauty', - 'because', - 'become', - 'beef', - 'before', - 'begin', - 'behave', - 'behind', - 'believe', - 'below', - 'belt', - 'bench', - 'benefit', - 'best', - 'betray', - 'better', - 'between', - 'beyond', - 'bicycle', - 'bid', - 'bike', - 'bind', - 'biology', - 'bird', - 'birth', - 'bitter', - 'black', - 'blade', - 'blame', - 'blanket', - 'blast', - 'bleak', - 'bless', - 'blind', - 'blood', - 'blossom', - 'blouse', - 'blue', - 'blur', - 'blush', - 'board', - 'boat', - 'body', - 'boil', - 'bomb', - 'bone', - 'bonus', - 'book', - 'boost', - 'border', - 'boring', - 'borrow', - 'boss', - 'bottom', - 'bounce', - 'box', - 'boy', - 'bracket', - 'brain', - 'brand', - 'brass', - 'brave', - 'bread', - 'breeze', - 'brick', - 'bridge', - 'brief', - 'bright', - 'bring', - 'brisk', - 'broccoli', - 'broken', - 'bronze', - 'broom', - 'brother', - 'brown', - 'brush', - 'bubble', - 'buddy', - 'budget', - 'buffalo', - 'build', - 'bulb', - 'bulk', - 'bullet', - 'bundle', - 'bunker', - 'burden', - 'burger', - 'burst', - 'bus', - 'business', - 'busy', - 'butter', - 'buyer', - 'buzz', - 'cabbage', - 'cabin', - 'cable', - 'cactus', - 'cage', - 'cake', - 'call', - 'calm', - 'camera', - 'camp', - 'can', - 'canal', - 'cancel', - 'candy', - 'cannon', - 'canoe', - 'canvas', - 'canyon', - 'capable', - 'capital', - 'captain', - 'car', - 'carbon', - 'card', - 'cargo', - 'carpet', - 'carry', - 'cart', - 'case', - 'cash', - 'casino', - 'castle', - 'casual', - 'cat', - 'catalog', - 'catch', - 'category', - 'cattle', - 'caught', - 'cause', - 'caution', - 'cave', - 'ceiling', - 'celery', - 'cement', - 'census', - 'century', - 'cereal', - 'certain', - 'chair', - 'chalk', - 'champion', - 'change', - 'chaos', - 'chapter', - 'charge', - 'chase', - 'chat', - 'cheap', - 'check', - 'cheese', - 'chef', - 'cherry', - 'chest', - 'chicken', - 'chief', - 'child', - 'chimney', - 'choice', - 'choose', - 'chronic', - 'chuckle', - 'chunk', - 'churn', - 'cigar', - 'cinnamon', - 'circle', - 'citizen', - 'city', - 'civil', - 'claim', - 'clap', - 'clarify', - 'claw', - 'clay', - 'clean', - 'clerk', - 'clever', - 'click', - 'client', - 'cliff', - 'climb', - 'clinic', - 'clip', - 'clock', - 'clog', - 'close', - 'cloth', - 'cloud', - 'clown', - 'club', - 'clump', - 'cluster', - 'clutch', - 'coach', - 'coast', - 'coconut', - 'code', - 'coffee', - 'coil', - 'coin', - 'collect', - 'color', - 'column', - 'combine', - 'come', - 'comfort', - 'comic', - 'common', - 'company', - 'concert', - 'conduct', - 'confirm', - 'congress', - 'connect', - 'consider', - 'control', - 'convince', - 'cook', - 'cool', - 'copper', - 'copy', - 'coral', - 'core', - 'corn', - 'correct', - 'cost', - 'cotton', - 'couch', - 'country', - 'couple', - 'course', - 'cousin', - 'cover', - 'coyote', - 'crack', - 'cradle', - 'craft', - 'cram', - 'crane', - 'crash', - 'crater', - 'crawl', - 'crazy', - 'cream', - 'credit', - 'creek', - 'crew', - 'cricket', - 'crime', - 'crisp', - 'critic', - 'crop', - 'cross', - 'crouch', - 'crowd', - 'crucial', - 'cruel', - 'cruise', - 'crumble', - 'crunch', - 'crush', - 'cry', - 'crystal', - 'cube', - 'culture', - 'cup', - 'cupboard', - 'curious', - 'current', - 'curtain', - 'curve', - 'cushion', - 'custom', - 'cute', - 'cycle', - 'dad', - 'damage', - 'damp', - 'dance', - 'danger', - 'daring', - 'dash', - 'daughter', - 'dawn', - 'day', - 'deal', - 'debate', - 'debris', - 'decade', - 'december', - 'decide', - 'decline', - 'decorate', - 'decrease', - 'deer', - 'defense', - 'define', - 'defy', - 'degree', - 'delay', - 'deliver', - 'demand', - 'demise', - 'denial', - 'dentist', - 'deny', - 'depart', - 'depend', - 'deposit', - 'depth', - 'deputy', - 'derive', - 'describe', - 'desert', - 'design', - 'desk', - 'despair', - 'destroy', - 'detail', - 'detect', - 'develop', - 'device', - 'devote', - 'diagram', - 'dial', - 'diamond', - 'diary', - 'dice', - 'diesel', - 'diet', - 'differ', - 'digital', - 'dignity', - 'dilemma', - 'dinner', - 'dinosaur', - 'direct', - 'dirt', - 'disagree', - 'discover', - 'disease', - 'dish', - 'dismiss', - 'disorder', - 'display', - 'distance', - 'divert', - 'divide', - 'divorce', - 'dizzy', - 'doctor', - 'document', - 'dog', - 'doll', - 'dolphin', - 'domain', - 'donate', - 'donkey', - 'donor', - 'door', - 'dose', - 'double', - 'dove', - 'draft', - 'dragon', - 'drama', - 'drastic', - 'draw', - 'dream', - 'dress', - 'drift', - 'drill', - 'drink', - 'drip', - 'drive', - 'drop', - 'drum', - 'dry', - 'duck', - 'dumb', - 'dune', - 'during', - 'dust', - 'dutch', - 'duty', - 'dwarf', - 'dynamic', - 'eager', - 'eagle', - 'early', - 'earn', - 'earth', - 'easily', - 'east', - 'easy', - 'echo', - 'ecology', - 'economy', - 'edge', - 'edit', - 'educate', - 'effort', - 'egg', - 'eight', - 'either', - 'elbow', - 'elder', - 'electric', - 'elegant', - 'element', - 'elephant', - 'elevator', - 'elite', - 'else', - 'embark', - 'embody', - 'embrace', - 'emerge', - 'emotion', - 'employ', - 'empower', - 'empty', - 'enable', - 'enact', - 'end', - 'endless', - 'endorse', - 'enemy', - 'energy', - 'enforce', - 'engage', - 'engine', - 'enhance', - 'enjoy', - 'enlist', - 'enough', - 'enrich', - 'enroll', - 'ensure', - 'enter', - 'entire', - 'entry', - 'envelope', - 'episode', - 'equal', - 'equip', - 'era', - 'erase', - 'erode', - 'erosion', - 'error', - 'erupt', - 'escape', - 'essay', - 'essence', - 'estate', - 'eternal', - 'ethics', - 'evidence', - 'evil', - 'evoke', - 'evolve', - 'exact', - 'example', - 'excess', - 'exchange', - 'excite', - 'exclude', - 'excuse', - 'execute', - 'exercise', - 'exhaust', - 'exhibit', - 'exile', - 'exist', - 'exit', - 'exotic', - 'expand', - 'expect', - 'expire', - 'explain', - 'expose', - 'express', - 'extend', - 'extra', - 'eye', - 'eyebrow', - 'fabric', - 'face', - 'faculty', - 'fade', - 'faint', - 'faith', - 'fall', - 'false', - 'fame', - 'family', - 'famous', - 'fan', - 'fancy', - 'fantasy', - 'farm', - 'fashion', - 'fat', - 'fatal', - 'father', - 'fatigue', - 'fault', - 'favorite', - 'feature', - 'february', - 'federal', - 'fee', - 'feed', - 'feel', - 'female', - 'fence', - 'festival', - 'fetch', - 'fever', - 'few', - 'fiber', - 'fiction', - 'field', - 'figure', - 'file', - 'film', - 'filter', - 'final', - 'find', - 'fine', - 'finger', - 'finish', - 'fire', - 'firm', - 'first', - 'fiscal', - 'fish', - 'fit', - 'fitness', - 'fix', - 'flag', - 'flame', - 'flash', - 'flat', - 'flavor', - 'flee', - 'flight', - 'flip', - 'float', - 'flock', - 'floor', - 'flower', - 'fluid', - 'flush', - 'fly', - 'foam', - 'focus', - 'fog', - 'foil', - 'fold', - 'follow', - 'food', - 'foot', - 'force', - 'forest', - 'forget', - 'fork', - 'fortune', - 'forum', - 'forward', - 'fossil', - 'foster', - 'found', - 'fox', - 'fragile', - 'frame', - 'frequent', - 'fresh', - 'friend', - 'fringe', - 'frog', - 'front', - 'frost', - 'frown', - 'frozen', - 'fruit', - 'fuel', - 'fun', - 'funny', - 'furnace', - 'fury', - 'future', - 'gadget', - 'gain', - 'galaxy', - 'gallery', - 'game', - 'gap', - 'garage', - 'garbage', - 'garden', - 'garlic', - 'garment', - 'gas', - 'gasp', - 'gate', - 'gather', - 'gauge', - 'gaze', - 'general', - 'genius', - 'genre', - 'gentle', - 'genuine', - 'gesture', - 'ghost', - 'giant', - 'gift', - 'giggle', - 'ginger', - 'giraffe', - 'girl', - 'give', - 'glad', - 'glance', - 'glare', - 'glass', - 'glide', - 'glimpse', - 'globe', - 'gloom', - 'glory', - 'glove', - 'glow', - 'glue', - 'goat', - 'goddess', - 'gold', - 'good', - 'goose', - 'gorilla', - 'gospel', - 'gossip', - 'govern', - 'gown', - 'grab', - 'grace', - 'grain', - 'grant', - 'grape', - 'grass', - 'gravity', - 'great', - 'green', - 'grid', - 'grief', - 'grit', - 'grocery', - 'group', - 'grow', - 'grunt', - 'guard', - 'guess', - 'guide', - 'guilt', - 'guitar', - 'gun', - 'gym', - 'habit', - 'hair', - 'half', - 'hammer', - 'hamster', - 'hand', - 'happy', - 'harbor', - 'hard', - 'harsh', - 'harvest', - 'hat', - 'have', - 'hawk', - 'hazard', - 'head', - 'health', - 'heart', - 'heavy', - 'hedgehog', - 'height', - 'hello', - 'helmet', - 'help', - 'hen', - 'hero', - 'hidden', - 'high', - 'hill', - 'hint', - 'hip', - 'hire', - 'history', - 'hobby', - 'hockey', - 'hold', - 'hole', - 'holiday', - 'hollow', - 'home', - 'honey', - 'hood', - 'hope', - 'horn', - 'horror', - 'horse', - 'hospital', - 'host', - 'hotel', - 'hour', - 'hover', - 'hub', - 'huge', - 'human', - 'humble', - 'humor', - 'hundred', - 'hungry', - 'hunt', - 'hurdle', - 'hurry', - 'hurt', - 'husband', - 'hybrid', - 'ice', - 'icon', - 'idea', - 'identify', - 'idle', - 'ignore', - 'ill', - 'illegal', - 'illness', - 'image', - 'imitate', - 'immense', - 'immune', - 'impact', - 'impose', - 'improve', - 'impulse', - 'inch', - 'include', - 'income', - 'increase', - 'index', - 'indicate', - 'indoor', - 'industry', - 'infant', - 'inflict', - 'inform', - 'inhale', - 'inherit', - 'initial', - 'inject', - 'injury', - 'inmate', - 'inner', - 'innocent', - 'input', - 'inquiry', - 'insane', - 'insect', - 'inside', - 'inspire', - 'install', - 'intact', - 'interest', - 'into', - 'invest', - 'invite', - 'involve', - 'iron', - 'island', - 'isolate', - 'issue', - 'item', - 'ivory', - 'jacket', - 'jaguar', - 'jar', - 'jazz', - 'jealous', - 'jeans', - 'jelly', - 'jewel', - 'job', - 'join', - 'joke', - 'journey', - 'joy', - 'judge', - 'juice', - 'jump', - 'jungle', - 'junior', - 'junk', - 'just', - 'kangaroo', - 'keen', - 'keep', - 'ketchup', - 'key', - 'kick', - 'kid', - 'kidney', - 'kind', - 'kingdom', - 'kiss', - 'kit', - 'kitchen', - 'kite', - 'kitten', - 'kiwi', - 'knee', - 'knife', - 'knock', - 'know', - 'lab', - 'label', - 'labor', - 'ladder', - 'lady', - 'lake', - 'lamp', - 'language', - 'laptop', - 'large', - 'later', - 'latin', - 'laugh', - 'laundry', - 'lava', - 'law', - 'lawn', - 'lawsuit', - 'layer', - 'lazy', - 'leader', - 'leaf', - 'learn', - 'leave', - 'lecture', - 'left', - 'leg', - 'legal', - 'legend', - 'leisure', - 'lemon', - 'lend', - 'length', - 'lens', - 'leopard', - 'lesson', - 'letter', - 'level', - 'liar', - 'liberty', - 'library', - 'license', - 'life', - 'lift', - 'light', - 'like', - 'limb', - 'limit', - 'link', - 'lion', - 'liquid', - 'list', - 'little', - 'live', - 'lizard', - 'load', - 'loan', - 'lobster', - 'local', - 'lock', - 'logic', - 'lonely', - 'long', - 'loop', - 'lottery', - 'loud', - 'lounge', - 'love', - 'loyal', - 'lucky', - 'luggage', - 'lumber', - 'lunar', - 'lunch', - 'luxury', - 'lyrics', - 'machine', - 'mad', - 'magic', - 'magnet', - 'maid', - 'mail', - 'main', - 'major', - 'make', - 'mammal', - 'man', - 'manage', - 'mandate', - 'mango', - 'mansion', - 'manual', - 'maple', - 'marble', - 'march', - 'margin', - 'marine', - 'market', - 'marriage', - 'mask', - 'mass', - 'master', - 'match', - 'material', - 'math', - 'matrix', - 'matter', - 'maximum', - 'maze', - 'meadow', - 'mean', - 'measure', - 'meat', - 'mechanic', - 'medal', - 'media', - 'melody', - 'melt', - 'member', - 'memory', - 'mention', - 'menu', - 'mercy', - 'merge', - 'merit', - 'merry', - 'mesh', - 'message', - 'metal', - 'method', - 'middle', - 'midnight', - 'milk', - 'million', - 'mimic', - 'mind', - 'minimum', - 'minor', - 'minute', - 'miracle', - 'mirror', - 'misery', - 'miss', - 'mistake', - 'mix', - 'mixed', - 'mixture', - 'mobile', - 'model', - 'modify', - 'mom', - 'moment', - 'monitor', - 'monkey', - 'monster', - 'month', - 'moon', - 'moral', - 'more', - 'morning', - 'mosquito', - 'mother', - 'motion', - 'motor', - 'mountain', - 'mouse', - 'move', - 'movie', - 'much', - 'muffin', - 'mule', - 'multiply', - 'muscle', - 'museum', - 'mushroom', - 'music', - 'must', - 'mutual', - 'myself', - 'mystery', - 'myth', - 'naive', - 'name', - 'napkin', - 'narrow', - 'nasty', - 'nation', - 'nature', - 'near', - 'neck', - 'need', - 'negative', - 'neglect', - 'neither', - 'nephew', - 'nerve', - 'nest', - 'net', - 'network', - 'neutral', - 'never', - 'news', - 'next', - 'nice', - 'night', - 'noble', - 'noise', - 'nominee', - 'noodle', - 'normal', - 'north', - 'nose', - 'notable', - 'note', - 'nothing', - 'notice', - 'novel', - 'now', - 'nuclear', - 'number', - 'nurse', - 'nut', - 'oak', - 'obey', - 'object', - 'oblige', - 'obscure', - 'observe', - 'obtain', - 'obvious', - 'occur', - 'ocean', - 'october', - 'odor', - 'off', - 'offer', - 'office', - 'often', - 'oil', - 'okay', - 'old', - 'olive', - 'olympic', - 'omit', - 'once', - 'one', - 'onion', - 'online', - 'only', - 'open', - 'opera', - 'opinion', - 'oppose', - 'option', - 'orange', - 'orbit', - 'orchard', - 'order', - 'ordinary', - 'organ', - 'orient', - 'original', - 'orphan', - 'ostrich', - 'other', - 'outdoor', - 'outer', - 'output', - 'outside', - 'oval', - 'oven', - 'over', - 'own', - 'owner', - 'oxygen', - 'oyster', - 'ozone', - 'pact', - 'paddle', - 'page', - 'pair', - 'palace', - 'palm', - 'panda', - 'panel', - 'panic', - 'panther', - 'paper', - 'parade', - 'parent', - 'park', - 'parrot', - 'party', - 'pass', - 'patch', - 'path', - 'patient', - 'patrol', - 'pattern', - 'pause', - 'pave', - 'payment', - 'peace', - 'peanut', - 'pear', - 'peasant', - 'pelican', - 'pen', - 'penalty', - 'pencil', - 'people', - 'pepper', - 'perfect', - 'permit', - 'person', - 'pet', - 'phone', - 'photo', - 'phrase', - 'physical', - 'piano', - 'picnic', - 'picture', - 'piece', - 'pig', - 'pigeon', - 'pill', - 'pilot', - 'pink', - 'pioneer', - 'pipe', - 'pistol', - 'pitch', - 'pizza', - 'place', - 'planet', - 'plastic', - 'plate', - 'play', - 'please', - 'pledge', - 'pluck', - 'plug', - 'plunge', - 'poem', - 'poet', - 'point', - 'polar', - 'pole', - 'police', - 'pond', - 'pony', - 'pool', - 'popular', - 'portion', - 'position', - 'possible', - 'post', - 'potato', - 'pottery', - 'poverty', - 'powder', - 'power', - 'practice', - 'praise', - 'predict', - 'prefer', - 'prepare', - 'present', - 'pretty', - 'prevent', - 'price', - 'pride', - 'primary', - 'print', - 'priority', - 'prison', - 'private', - 'prize', - 'problem', - 'process', - 'produce', - 'profit', - 'program', - 'project', - 'promote', - 'proof', - 'property', - 'prosper', - 'protect', - 'proud', - 'provide', - 'public', - 'pudding', - 'pull', - 'pulp', - 'pulse', - 'pumpkin', - 'punch', - 'pupil', - 'puppy', - 'purchase', - 'purity', - 'purpose', - 'purse', - 'push', - 'put', - 'puzzle', - 'pyramid', - 'quality', - 'quantum', - 'quarter', - 'question', - 'quick', - 'quit', - 'quiz', - 'quote', - 'rabbit', - 'raccoon', - 'race', - 'rack', - 'radar', - 'radio', - 'rail', - 'rain', - 'raise', - 'rally', - 'ramp', - 'ranch', - 'random', - 'range', - 'rapid', - 'rare', - 'rate', - 'rather', - 'raven', - 'raw', - 'razor', - 'ready', - 'real', - 'reason', - 'rebel', - 'rebuild', - 'recall', - 'receive', - 'recipe', - 'record', - 'recycle', - 'reduce', - 'reflect', - 'reform', - 'refuse', - 'region', - 'regret', - 'regular', - 'reject', - 'relax', - 'release', - 'relief', - 'rely', - 'remain', - 'remember', - 'remind', - 'remove', - 'render', - 'renew', - 'rent', - 'reopen', - 'repair', - 'repeat', - 'replace', - 'report', - 'require', - 'rescue', - 'resemble', - 'resist', - 'resource', - 'response', - 'result', - 'retire', - 'retreat', - 'return', - 'reunion', - 'reveal', - 'review', - 'reward', - 'rhythm', - 'rib', - 'ribbon', - 'rice', - 'rich', - 'ride', - 'ridge', - 'rifle', - 'right', - 'rigid', - 'ring', - 'riot', - 'ripple', - 'risk', - 'ritual', - 'rival', - 'river', - 'road', - 'roast', - 'robot', - 'robust', - 'rocket', - 'romance', - 'roof', - 'rookie', - 'room', - 'rose', - 'rotate', - 'rough', - 'round', - 'route', - 'royal', - 'rubber', - 'rude', - 'rug', - 'rule', - 'run', - 'runway', - 'rural', - 'sad', - 'saddle', - 'sadness', - 'safe', - 'sail', - 'salad', - 'salmon', - 'salon', - 'salt', - 'salute', - 'same', - 'sample', - 'sand', - 'satisfy', - 'satoshi', - 'sauce', - 'sausage', - 'save', - 'say', - 'scale', - 'scan', - 'scare', - 'scatter', - 'scene', - 'scheme', - 'school', - 'science', - 'scissors', - 'scorpion', - 'scout', - 'scrap', - 'screen', - 'script', - 'scrub', - 'sea', - 'search', - 'season', - 'seat', - 'second', - 'secret', - 'section', - 'security', - 'seed', - 'seek', - 'segment', - 'select', - 'sell', - 'seminar', - 'senior', - 'sense', - 'sentence', - 'series', - 'service', - 'session', - 'settle', - 'setup', - 'seven', - 'shadow', - 'shaft', - 'shallow', - 'share', - 'shed', - 'shell', - 'sheriff', - 'shield', - 'shift', - 'shine', - 'ship', - 'shiver', - 'shock', - 'shoe', - 'shoot', - 'shop', - 'short', - 'shoulder', - 'shove', - 'shrimp', - 'shrug', - 'shuffle', - 'shy', - 'sibling', - 'sick', - 'side', - 'siege', - 'sight', - 'sign', - 'silent', - 'silk', - 'silly', - 'silver', - 'similar', - 'simple', - 'since', - 'sing', - 'siren', - 'sister', - 'situate', - 'six', - 'size', - 'skate', - 'sketch', - 'ski', - 'skill', - 'skin', - 'skirt', - 'skull', - 'slab', - 'slam', - 'sleep', - 'slender', - 'slice', - 'slide', - 'slight', - 'slim', - 'slogan', - 'slot', - 'slow', - 'slush', - 'small', - 'smart', - 'smile', - 'smoke', - 'smooth', - 'snack', - 'snake', - 'snap', - 'sniff', - 'snow', - 'soap', - 'soccer', - 'social', - 'sock', - 'soda', - 'soft', - 'solar', - 'soldier', - 'solid', - 'solution', - 'solve', - 'someone', - 'song', - 'soon', - 'sorry', - 'sort', - 'soul', - 'sound', - 'soup', - 'source', - 'south', - 'space', - 'spare', - 'spatial', - 'spawn', - 'speak', - 'special', - 'speed', - 'spell', - 'spend', - 'sphere', - 'spice', - 'spider', - 'spike', - 'spin', - 'spirit', - 'split', - 'spoil', - 'sponsor', - 'spoon', - 'sport', - 'spot', - 'spray', - 'spread', - 'spring', - 'spy', - 'square', - 'squeeze', - 'squirrel', - 'stable', - 'stadium', - 'staff', - 'stage', - 'stairs', - 'stamp', - 'stand', - 'start', - 'state', - 'stay', - 'steak', - 'steel', - 'stem', - 'step', - 'stereo', - 'stick', - 'still', - 'sting', - 'stock', - 'stomach', - 'stone', - 'stool', - 'story', - 'stove', - 'strategy', - 'street', - 'strike', - 'strong', - 'struggle', - 'student', - 'stuff', - 'stumble', - 'style', - 'subject', - 'submit', - 'subway', - 'success', - 'such', - 'sudden', - 'suffer', - 'sugar', - 'suggest', - 'suit', - 'summer', - 'sun', - 'sunny', - 'sunset', - 'super', - 'supply', - 'supreme', - 'sure', - 'surface', - 'surge', - 'surprise', - 'surround', - 'survey', - 'suspect', - 'sustain', - 'swallow', - 'swamp', - 'swap', - 'swarm', - 'swear', - 'sweet', - 'swift', - 'swim', - 'swing', - 'switch', - 'sword', - 'symbol', - 'symptom', - 'syrup', - 'system', - 'table', - 'tackle', - 'tag', - 'tail', - 'talent', - 'talk', - 'tank', - 'tape', - 'target', - 'task', - 'taste', - 'tattoo', - 'taxi', - 'teach', - 'team', - 'tell', - 'ten', - 'tenant', - 'tennis', - 'tent', - 'term', - 'test', - 'text', - 'thank', - 'that', - 'theme', - 'then', - 'theory', - 'there', - 'they', - 'thing', - 'this', - 'thought', - 'three', - 'thrive', - 'throw', - 'thumb', - 'thunder', - 'ticket', - 'tide', - 'tiger', - 'tilt', - 'timber', - 'time', - 'tiny', - 'tip', - 'tired', - 'tissue', - 'title', - 'toast', - 'tobacco', - 'today', - 'toddler', - 'toe', - 'together', - 'toilet', - 'token', - 'tomato', - 'tomorrow', - 'tone', - 'tongue', - 'tonight', - 'tool', - 'tooth', - 'top', - 'topic', - 'topple', - 'torch', - 'tornado', - 'tortoise', - 'toss', - 'total', - 'tourist', - 'toward', - 'tower', - 'town', - 'toy', - 'track', - 'trade', - 'traffic', - 'tragic', - 'train', - 'transfer', - 'trap', - 'trash', - 'travel', - 'tray', - 'treat', - 'tree', - 'trend', - 'trial', - 'tribe', - 'trick', - 'trigger', - 'trim', - 'trip', - 'trophy', - 'trouble', - 'truck', - 'true', - 'truly', - 'trumpet', - 'trust', - 'truth', - 'try', - 'tube', - 'tuition', - 'tumble', - 'tuna', - 'tunnel', - 'turkey', - 'turn', - 'turtle', - 'twelve', - 'twenty', - 'twice', - 'twin', - 'twist', - 'two', - 'type', - 'typical', - 'ugly', - 'umbrella', - 'unable', - 'unaware', - 'uncle', - 'uncover', - 'under', - 'undo', - 'unfair', - 'unfold', - 'unhappy', - 'uniform', - 'unique', - 'unit', - 'universe', - 'unknown', - 'unlock', - 'until', - 'unusual', - 'unveil', - 'update', - 'upgrade', - 'uphold', - 'upon', - 'upper', - 'upset', - 'urban', - 'urge', - 'usage', - 'use', - 'used', - 'useful', - 'useless', - 'usual', - 'utility', - 'vacant', - 'vacuum', - 'vague', - 'valid', - 'valley', - 'valve', - 'van', - 'vanish', - 'vapor', - 'various', - 'vast', - 'vault', - 'vehicle', - 'velvet', - 'vendor', - 'venture', - 'venue', - 'verb', - 'verify', - 'version', - 'very', - 'vessel', - 'veteran', - 'viable', - 'vibrant', - 'vicious', - 'victory', - 'video', - 'view', - 'village', - 'vintage', - 'violin', - 'virtual', - 'virus', - 'visa', - 'visit', - 'visual', - 'vital', - 'vivid', - 'vocal', - 'voice', - 'void', - 'volcano', - 'volume', - 'vote', - 'voyage', - 'wage', - 'wagon', - 'wait', - 'walk', - 'wall', - 'walnut', - 'want', - 'warfare', - 'warm', - 'warrior', - 'wash', - 'wasp', - 'waste', - 'water', - 'wave', - 'way', - 'wealth', - 'weapon', - 'wear', - 'weasel', - 'weather', - 'web', - 'wedding', - 'weekend', - 'weird', - 'welcome', - 'west', - 'wet', - 'whale', - 'what', - 'wheat', - 'wheel', - 'when', - 'where', - 'whip', - 'whisper', - 'wide', - 'width', - 'wife', - 'wild', - 'will', - 'win', - 'window', - 'wine', - 'wing', - 'wink', - 'winner', - 'winter', - 'wire', - 'wisdom', - 'wise', - 'wish', - 'witness', - 'wolf', - 'woman', - 'wonder', - 'wood', - 'wool', - 'word', - 'work', - 'world', - 'worry', - 'worth', - 'wrap', - 'wreck', - 'wrestle', - 'wrist', - 'write', - 'wrong', - 'yard', - 'year', - 'yellow', - 'you', - 'young', - 'youth', - 'zebra', - 'zero', - 'zone', - 'zoo', -] diff --git a/packages/neuron-wallet/src/services/addresses.ts b/packages/neuron-wallet/src/services/addresses.ts index c9530ec1ca..f71ba1886c 100644 --- a/packages/neuron-wallet/src/services/addresses.ts +++ b/packages/neuron-wallet/src/services/addresses.ts @@ -1,5 +1,6 @@ -import { AccountExtendedPublicKey, DefaultAddressNumber } from '../models/keys/key' -import Address, { AddressType, publicKeyToAddress } from '../models/keys/address' +import { AccountExtendedPublicKey } from '../models/keys/key' +import { AddressType } from '@ckb-lumos/hd' +import Address, { publicKeyToAddress, DefaultAddressNumber } from '../models/keys/address' import { Address as AddressInterface } from '../models/address' import AddressCreatedSubject from '../models/subjects/address-created-subject' import NetworksService from '../services/networks' diff --git a/packages/neuron-wallet/src/services/hardware/common.ts b/packages/neuron-wallet/src/services/hardware/common.ts index 2cf52ae82c..67bde2b3d6 100644 --- a/packages/neuron-wallet/src/services/hardware/common.ts +++ b/packages/neuron-wallet/src/services/hardware/common.ts @@ -1,4 +1,4 @@ -import { AddressType } from '../../models/keys/address' +import { AddressType } from '@ckb-lumos/hd' export enum Manufacturer { Ledger = 'Ledger', diff --git a/packages/neuron-wallet/src/services/hardware/ledger.ts b/packages/neuron-wallet/src/services/hardware/ledger.ts index 1a41162df1..877851ed9e 100644 --- a/packages/neuron-wallet/src/services/hardware/ledger.ts +++ b/packages/neuron-wallet/src/services/hardware/ledger.ts @@ -7,7 +7,8 @@ import type Transport from '@ledgerhq/hw-transport' import { Observable, timer } from 'rxjs' import { takeUntil, filter, scan } from 'rxjs/operators' import Transaction from '../../models/chain/transaction' -import Address, { AddressType } from '../../models/keys/address' +import { AddressType } from '@ckb-lumos/hd' +import Address from '../../models/keys/address' import logger from '../../utils/logger' import NetworksService from '../../services/networks' import { generateRPC } from '../../utils/ckb-rpc' diff --git a/packages/neuron-wallet/src/services/wallets.ts b/packages/neuron-wallet/src/services/wallets.ts index 8bb5064f73..f8977b79c5 100644 --- a/packages/neuron-wallet/src/services/wallets.ts +++ b/packages/neuron-wallet/src/services/wallets.ts @@ -4,7 +4,8 @@ import Store from '../models/store' import Keystore from '../models/keys/keystore' import WalletDeletedSubject from '../models/subjects/wallet-deleted-subject' import { WalletListSubject, CurrentWalletSubject } from '../models/subjects/wallets' -import { AccountExtendedPublicKey, DefaultAddressNumber } from '../models/keys/key' +import { AccountExtendedPublicKey } from '../models/keys/key' +import { DefaultAddressNumber } from '../models/keys/address' import { Address as AddressInterface } from '../models/address' import FileService from './file' diff --git a/packages/neuron-wallet/tests/block-sync-renderer/full-synchronizer.test.ts b/packages/neuron-wallet/tests/block-sync-renderer/full-synchronizer.test.ts index 19a6ef6f18..b4f2cd19fd 100644 --- a/packages/neuron-wallet/tests/block-sync-renderer/full-synchronizer.test.ts +++ b/packages/neuron-wallet/tests/block-sync-renderer/full-synchronizer.test.ts @@ -1,6 +1,6 @@ import { scriptToAddress } from '../../src/utils/scriptAndAddress' import { when } from 'jest-when' -import { AddressType } from '../../src/models/keys/address' +import { AddressType } from '@ckb-lumos/hd' import { Address, AddressVersion } from '../../src/models/address' import SystemScriptInfo from '../../src/models/system-script-info' import FullSynchronizer from '../../src/block-sync-renderer/sync/full-synchronizer' diff --git a/packages/neuron-wallet/tests/block-sync-renderer/indexer-cache-service.intg.test.ts b/packages/neuron-wallet/tests/block-sync-renderer/indexer-cache-service.intg.test.ts index 507934f31e..2ba8f41a08 100644 --- a/packages/neuron-wallet/tests/block-sync-renderer/indexer-cache-service.intg.test.ts +++ b/packages/neuron-wallet/tests/block-sync-renderer/indexer-cache-service.intg.test.ts @@ -1,6 +1,6 @@ import { when } from 'jest-when' import AddressMeta from '../../src/database/address/meta' -import { AddressType } from '../../src/models/keys/address' +import { AddressType } from '@ckb-lumos/hd' import { AddressVersion } from '../../src/models/address' import IndexerTxHashCache from '../../src/database/chain/entities/indexer-tx-hash-cache' import RpcService from '../../src/services/rpc-service' diff --git a/packages/neuron-wallet/tests/block-sync-renderer/queue.test.ts b/packages/neuron-wallet/tests/block-sync-renderer/queue.test.ts index 0e1e8661cd..52051e88e8 100644 --- a/packages/neuron-wallet/tests/block-sync-renderer/queue.test.ts +++ b/packages/neuron-wallet/tests/block-sync-renderer/queue.test.ts @@ -2,7 +2,7 @@ import '../../src/types/ckbComponents.d.ts' import { Subject } from 'rxjs' import { Tip } from '@ckb-lumos/base' import { scriptToAddress } from '../../src/utils/scriptAndAddress' -import { AddressType } from '../../src/models/keys/address' +import { AddressType } from '@ckb-lumos/hd' import SystemScriptInfo from '../../src/models/system-script-info' import { Address, AddressVersion } from '../../src/models/address' import Queue from '../../src/block-sync-renderer/sync/queue' diff --git a/packages/neuron-wallet/tests/block-sync-renderer/synchronizer.test.ts b/packages/neuron-wallet/tests/block-sync-renderer/synchronizer.test.ts index 95df115186..c3c1e7e325 100644 --- a/packages/neuron-wallet/tests/block-sync-renderer/synchronizer.test.ts +++ b/packages/neuron-wallet/tests/block-sync-renderer/synchronizer.test.ts @@ -1,5 +1,5 @@ import { scriptToAddress } from '../../src/utils/scriptAndAddress' -import { AddressType } from '../../src/models/keys/address' +import { AddressType } from '@ckb-lumos/hd' import { Address, AddressVersion } from '../../src/models/address' import SystemScriptInfo from '../../src/models/system-script-info' import { Synchronizer, type LumosCell, type LumosCellQuery } from '../../src/block-sync-renderer/sync/synchronizer' diff --git a/packages/neuron-wallet/tests/database/address/meta.test.ts b/packages/neuron-wallet/tests/database/address/meta.test.ts index eb37c459e8..cdc9f5605e 100644 --- a/packages/neuron-wallet/tests/database/address/meta.test.ts +++ b/packages/neuron-wallet/tests/database/address/meta.test.ts @@ -1,5 +1,5 @@ import { Address, AddressVersion } from '../../../src/models/address' -import { AddressType } from '../../../src/models/keys/address' +import { AddressType } from '@ckb-lumos/hd' import AddressMeta from '../../../src/database/address/meta' import Multisig from '../../../src/models/multisig' import AssetAccountInfo from '../../../src/models/asset-account-info' diff --git a/packages/neuron-wallet/tests/mock/hardware.ts b/packages/neuron-wallet/tests/mock/hardware.ts index 67e9c500eb..bc8c04f3b3 100644 --- a/packages/neuron-wallet/tests/mock/hardware.ts +++ b/packages/neuron-wallet/tests/mock/hardware.ts @@ -1,5 +1,5 @@ import { DeviceInfo } from '../../src/services/hardware/common' -import { AddressType } from '../../src/models/keys/address' +import { AddressType } from '@ckb-lumos/hd' import type { Subscriber } from 'rxjs' enum Manufacturer { diff --git a/packages/neuron-wallet/tests/models/asset-account-info.test.ts b/packages/neuron-wallet/tests/models/asset-account-info.test.ts index 9a35c45a2b..cb7d34a570 100644 --- a/packages/neuron-wallet/tests/models/asset-account-info.test.ts +++ b/packages/neuron-wallet/tests/models/asset-account-info.test.ts @@ -2,7 +2,7 @@ import AssetAccountInfo from '../../src/models/asset-account-info' import CellDep, { DepType } from '../../src/models/chain/cell-dep' import OutPoint from '../../src/models/chain/out-point' import { ScriptHashType } from '../../src/models/chain/script' -import { AddressType } from '../../src/models/keys/address' +import { AddressType } from '@ckb-lumos/hd' import AddressMeta from '../../src/database/address/meta' describe('AssetAccountInfo', () => { diff --git a/packages/neuron-wallet/tests/models/keys/address.test.ts b/packages/neuron-wallet/tests/models/keys/address.test.ts index c0ec834827..7d8b71ac51 100644 --- a/packages/neuron-wallet/tests/models/keys/address.test.ts +++ b/packages/neuron-wallet/tests/models/keys/address.test.ts @@ -1,4 +1,5 @@ -import Address, { AddressType, publicKeyToAddress } from '../../../src/models/keys/address' +import { AddressType } from '@ckb-lumos/hd' +import Address, { publicKeyToAddress } from '../../../src/models/keys/address' describe('address', () => { it('path from index', () => { diff --git a/packages/neuron-wallet/tests/models/keys/hd-public-key-info.test.ts b/packages/neuron-wallet/tests/models/keys/hd-public-key-info.test.ts index 68c397e1bd..a9aee99971 100644 --- a/packages/neuron-wallet/tests/models/keys/hd-public-key-info.test.ts +++ b/packages/neuron-wallet/tests/models/keys/hd-public-key-info.test.ts @@ -1,5 +1,5 @@ import { scriptToAddress } from '../../../src/utils/scriptAndAddress' -import { AddressType } from '../../../src/models/keys/address' +import { AddressType } from '@ckb-lumos/hd' import KeyInfos from '../../setupAndTeardown/public-key-info.fixture' import { systemScripts } from '../../../src/utils/systemScripts' import { NetworkType } from '../../../src/models/network' diff --git a/packages/neuron-wallet/tests/models/keys/key.test.ts b/packages/neuron-wallet/tests/models/keys/key.test.ts index 5f014a7f2c..db9d3a889a 100644 --- a/packages/neuron-wallet/tests/models/keys/key.test.ts +++ b/packages/neuron-wallet/tests/models/keys/key.test.ts @@ -1,10 +1,5 @@ -import { - ExtendedPublicKey, - AccountExtendedPublicKey, - ExtendedPrivateKey, - generateMnemonic, -} from '../../../src/models/keys/key' -import { AddressType } from '../../../src/models/keys/address' +import { ExtendedPublicKey, AccountExtendedPublicKey, ExtendedPrivateKey } from '../../../src/models/keys/key' +import { AddressType } from '@ckb-lumos/hd' const fixture = { privateKey: 'e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35', @@ -70,10 +65,3 @@ describe('extended private key', () => { expect(extendedKey.chainCode).toEqual(fixture.chainCode) }) }) - -describe('generate mnemonic', () => { - it('generate 12 words code', () => { - const mnemonic = generateMnemonic() - expect(mnemonic.split(' ').length).toBe(12) - }) -}) diff --git a/packages/neuron-wallet/tests/models/keys/mnemonic/fixtures.json b/packages/neuron-wallet/tests/models/keys/mnemonic/fixtures.json deleted file mode 100644 index 5aec22150c..0000000000 --- a/packages/neuron-wallet/tests/models/keys/mnemonic/fixtures.json +++ /dev/null @@ -1,147 +0,0 @@ -{ - "vectors": [ - { - "entropy": "00000000000000000000000000000000", - "mnemonic": "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - "seed": "5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4" - }, - - { - "entropy": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "mnemonic": "legal winner thank year wave sausage worth useful legal winner thank yellow", - "seed": "878386efb78845b3355bd15ea4d39ef97d179cb712b77d5c12b6be415fffeffe5f377ba02bf3f8544ab800b955e51fbff09828f682052a20faa6addbbddfb096" - }, - - { - "entropy": "80808080808080808080808080808080", - "mnemonic": "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", - "seed": "77d6be9708c8218738934f84bbbb78a2e048ca007746cb764f0673e4b1812d176bbb173e1a291f31cf633f1d0bad7d3cf071c30e98cd0688b5bcce65ecaceb36" - }, - - { - "entropy": "ffffffffffffffffffffffffffffffff", - "mnemonic": "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "seed": "b6a6d8921942dd9806607ebc2750416b289adea669198769f2e15ed926c3aa92bf88ece232317b4ea463e84b0fcd3b53577812ee449ccc448eb45e6f544e25b6" - }, - - { - "entropy": "000000000000000000000000000000000000000000000000", - "mnemonic": "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", - "seed": "4975bb3d1faf5308c86a30893ee903a976296609db223fd717e227da5a813a34dc1428b71c84a787fc51f3b9f9dc28e9459f48c08bd9578e9d1b170f2d7ea506" - }, - - { - "entropy": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "mnemonic": "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", - "seed": "b059400ce0f55498a5527667e77048bb482ff6daa16c37b4b9e8af70c85b3f4df588004f19812a1a027c9a51e5e94259a560268e91cd10e206451a129826e740" - }, - - { - "entropy": "808080808080808080808080808080808080808080808080", - "mnemonic": "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", - "seed": "04d5f77103510c41d610f7f5fb3f0badc77c377090815cee808ea5d2f264fdfabf7c7ded4be6d4c6d7cdb021ba4c777b0b7e57ca8aa6de15aeb9905dba674d66" - }, - - { - "entropy": "ffffffffffffffffffffffffffffffffffffffffffffffff", - "mnemonic": "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", - "seed": "d2911131a6dda23ac4441d1b66e2113ec6324354523acfa20899a2dcb3087849264e91f8ec5d75355f0f617be15369ffa13c3d18c8156b97cd2618ac693f759f" - }, - - { - "entropy": "0000000000000000000000000000000000000000000000000000000000000000", - "mnemonic": "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", - "seed": "408b285c123836004f4b8842c89324c1f01382450c0d439af345ba7fc49acf705489c6fc77dbd4e3dc1dd8cc6bc9f043db8ada1e243c4a0eafb290d399480840" - }, - - { - "entropy": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "mnemonic": "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", - "seed": "761914478ebf6fe16185749372e91549361af22b386de46322cf8b1ba7e92e80c4af05196f742be1e63aab603899842ddadf4e7248d8e43870a4b6ff9bf16324" - }, - - { - "entropy": "8080808080808080808080808080808080808080808080808080808080808080", - "mnemonic": "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", - "seed": "848bbe19cad445e46f35fd3d1a89463583ac2b60b5eb4cfcf955731775a5d9e17a81a71613fed83f1ae27b408478fdec2bbc75b5161d1937aa7cdf4ad686ef5f" - }, - - { - "entropy": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "mnemonic": "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", - "seed": "e28a37058c7f5112ec9e16a3437cf363a2572d70b6ceb3b6965447623d620f14d06bb321a26b33ec15fcd84a3b5ddfd5520e230c924c87aaa0d559749e044fef" - }, - - { - "entropy": "77c2b00716cec7213839159e404db50d", - "mnemonic": "jelly better achieve collect unaware mountain thought cargo oxygen act hood bridge", - "seed": "c7b8fbb38c1abe38dfc0fea9797804558dfac244cd7737ae3a1b619991e0ad520155d982f906629639dc39e440520f98f820bea4f886a63a45923a63441f25ef" - }, - - { - "entropy": "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", - "mnemonic": "renew stay biology evidence goat welcome casual join adapt armor shuffle fault little machine walk stumble urge swap", - "seed": "b1a1f06f175feccc998684667474b3d83efa57a0f39bb3a6cf3a3350ee7a6638ae6d15c4622c8252efe5aa319b026db1d4c91a80661ed34da1f2fb7d381224c8" - }, - - { - "entropy": "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", - "mnemonic": "dignity pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic", - "seed": "ecf9632e864630c00be4ca3d752d4f19a852cd628d9bbc3309a4c1a2f39801461a6816ca52793ddd3dacb242e207ad48e8bfde3afd0e8f978ad0e8cc4dd276c1" - }, - - { - "entropy": "0460ef47585604c5660618db2e6a7e7f", - "mnemonic": "afford alter spike radar gate glance object seek swamp infant panel yellow", - "seed": "3ddfd060236156416f8915ed6ced01c3316292aec7250434f7e32cda2338e76399874787257acad15618c81bcddd88714f8c0d316140dad809f0ca8b1a971679" - }, - - { - "entropy": "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", - "mnemonic": "indicate race push merry suffer human cruise dwarf pole review arch keep canvas theme poem divorce alter left", - "seed": "fe34200c8c3781f81f48d19f628a7370eb25c94c75077c9a6d4a1ef30fd9cc2f29f8ea7ef52bb765c5278413c19b7b2854b62cb3591ce4d749cd7f497da436a6" - }, - - { - "entropy": "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", - "mnemonic": "clutch control vehicle tonight unusual clog visa ice plunge glimpse recipe series open hour vintage deposit universe tip job dress radar refuse motion taste", - "seed": "fa9ca5ef1ebfcb5e945091d413843bf7ce748d27b8b99bb5373d34b9a6b1450d2a2d7f04480904b29c78a41a6ea949288f687f72b5b8e322193a7eae8151f109" - }, - - { - "entropy": "eaebabb2383351fd31d703840b32e9e2", - "mnemonic": "turtle front uncle idea crush write shrug there lottery flower risk shell", - "seed": "4ef6e8484a846392f996b15283906b73be4ec100859ce68689d5a0fad7f761745b86d70ea5f5c43e4cc93ce4b82b3d9aeed7f85d503fac00b10ebbc150399100" - }, - - { - "entropy": "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", - "mnemonic": "kiss carry display unusual confirm curtain upgrade antique rotate hello void custom frequent obey nut hole price segment", - "seed": "f0b24a453174e3c4f27634f3e2be07c069328f7cbaa24f695cbeb79a39e79f05154bddbabec57b832a46813d2e49e7b33f438e79cc566f78a3179dbce86cdd84" - }, - - { - "entropy": "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", - "mnemonic": "exile ask congress lamp submit jacket era scheme attend cousin alcohol catch course end lucky hurt sentence oven short ball bird grab wing top", - "seed": "8a91a843ad4fede95f23937099a94f117115a369903603761ecabae734b5d501ddba04b1a3c9f2256437ef2d230f295d8f08676e5de93ad5190da6645ded8160" - }, - - { - "entropy": "18ab19a9f54a9274f03e5209a2ac8a91", - "mnemonic": "board flee heavy tunnel powder denial science ski answer betray cargo cat", - "seed": "22087755f76d6fb93ddd19e71106d4d4146f48424a241c0eda88787227827166223f61860d53652b635f360b5a37dd26c8aed3fa10b6f8e95be18f1913f4ca88" - }, - - { - "entropy": "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", - "mnemonic": "board blade invite damage undo sun mimic interest slam gaze truly inherit resist great inject rocket museum chief", - "seed": "99539dbb0a15a76cdadd9cc066bae337a006823fa3439b42656fd0fca3d48afe6a0ca6f7a1d10412df611c32e18669a29bc0494de61b4c36730a5c31045464e2" - }, - - { - "entropy": "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", - "mnemonic": "beyond stage sleep clip because twist token leaf atom beauty genius food business side grid unable middle armed observe pair crouch tonight away coconut", - "seed": "898c7388d88e3a5b3b2922a0f03f95c8e61aeadba9fa8a7b0b5629d7c98e1e0aec53f0b10fcbd4a913b4b8c985028b0026ec6fdb0a4442ee18344ca3fac4d692" - } - ] -} diff --git a/packages/neuron-wallet/tests/models/keys/mnemonic/index.test.ts b/packages/neuron-wallet/tests/models/keys/mnemonic/index.test.ts deleted file mode 100644 index 616796cc36..0000000000 --- a/packages/neuron-wallet/tests/models/keys/mnemonic/index.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { - entropyToMnemonic, - mnemonicToEntropy, - mnemonicToSeed, - mnemonicToSeedSync, - validateMnemonic, -} from '../../../../src/models/keys/mnemonic' - -const fixtures = require('./fixtures.json') - -describe('mnemonic', () => { - it('generate, validate mnemonic', () => { - fixtures.vectors.map(async ({ entropy, mnemonic }: { entropy: string; mnemonic: string; seed: string }) => { - expect(validateMnemonic(mnemonic)).toBe(true) - expect(entropyToMnemonic(entropy)).toBe(mnemonic) - expect(mnemonicToEntropy(mnemonic)).toBe(entropy) - }) - }) - - it('generate seed', () => { - fixtures.vectors.map(async ({ mnemonic, seed }: { entropy: string; mnemonic: string; seed: string }) => { - expect(await mnemonicToSeed(mnemonic).then(s => s.toString('hex'))).toBe(seed) - expect(mnemonicToSeedSync(mnemonic).toString('hex')).toBe(seed) - }) - }) -}) diff --git a/packages/neuron-wallet/tests/services/address.test.ts b/packages/neuron-wallet/tests/services/address.test.ts index e64ba06a46..c4e9f46769 100644 --- a/packages/neuron-wallet/tests/services/address.test.ts +++ b/packages/neuron-wallet/tests/services/address.test.ts @@ -2,7 +2,7 @@ import { AccountExtendedPublicKey } from '../../src/models/keys/key' import SystemScriptInfo from '../../src/models/system-script-info' import { OutputStatus } from '../../src/models/chain/output' import OutputEntity from '../../src/database/chain/entities/output' -import { AddressType } from '../../src/models/keys/address' +import { AddressType } from '@ckb-lumos/hd' import { Address } from '../../src/models/address' import Transaction from '../../src/database/chain/entities/transaction' import { TransactionStatus } from '../../src/models/chain/transaction' diff --git a/packages/neuron-wallet/tests/services/asset-account-service.test.ts b/packages/neuron-wallet/tests/services/asset-account-service.test.ts index 713ba1d5a0..0e980b8a08 100644 --- a/packages/neuron-wallet/tests/services/asset-account-service.test.ts +++ b/packages/neuron-wallet/tests/services/asset-account-service.test.ts @@ -11,7 +11,7 @@ import { TransactionStatus } from '../../src/models/chain/transaction' import { closeConnection, createAccounts, getConnection, initConnection } from '../setupAndTeardown' import accounts from '../setupAndTeardown/accounts.fixture' import HdPublicKeyInfo from '../../src/database/chain/entities/hd-public-key-info' -import { AddressType } from '../../src/models/keys/address' +import { AddressType } from '@ckb-lumos/hd' import OutPoint from '../../src/models/chain/out-point' import { when } from 'jest-when' import SystemScriptInfo from '../../src/models/system-script-info' diff --git a/packages/neuron-wallet/tests/services/tx-wallet.test.ts b/packages/neuron-wallet/tests/services/tx-wallet.test.ts index 95ebaaa9ad..39d8e94461 100644 --- a/packages/neuron-wallet/tests/services/tx-wallet.test.ts +++ b/packages/neuron-wallet/tests/services/tx-wallet.test.ts @@ -1,7 +1,7 @@ import WalletService from '../../src/services/wallets' import Keystore from '../../src/models/keys/keystore' import Keychain from '../../src/models/keys/keychain' -import { mnemonicToSeedSync } from '../../src/models/keys/mnemonic' +import { mnemonicToSeedSync } from '@ckb-lumos/hd/lib/mnemonic' import { ExtendedPrivateKey, AccountExtendedPublicKey } from '../../src/models/keys/key' import TransactionSender from '../../src/services/transaction-sender' import { signWitnesses } from '../../src/utils/signWitnesses' diff --git a/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts b/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts index f4ca99d4e1..1d28c4254f 100644 --- a/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts +++ b/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts @@ -188,7 +188,7 @@ import Input from '../../../src/models/chain/input' import Script, { ScriptHashType } from '../../../src/models/chain/script' import Output from '../../../src/models/chain/output' import Keystore from '../../../src/models/keys/keystore' -import { AddressType } from '../../../src/models/keys/address' +import { AddressType } from '@ckb-lumos/hd' import WitnessArgs from '../../../src/models/chain/witness-args' import CellWithStatus from '../../../src/models/chain/cell-with-status' import SystemScriptInfo from '../../../src/models/system-script-info' diff --git a/packages/neuron-wallet/tests/services/wallets.test.ts b/packages/neuron-wallet/tests/services/wallets.test.ts index f6c79028a4..66ab45a7c6 100644 --- a/packages/neuron-wallet/tests/services/wallets.test.ts +++ b/packages/neuron-wallet/tests/services/wallets.test.ts @@ -1,7 +1,7 @@ import Keystore from '../../src/models/keys/keystore' import { when } from 'jest-when' import { WalletFunctionNotSupported, DuplicateImportWallet } from '../../src/exceptions/wallet' -import { AddressType } from '../../src/models/keys/address' +import { AddressType } from '@ckb-lumos/hd' import { Manufacturer } from '../../src/services/hardware/common' const stubbedDeletedByWalletIdFn = jest.fn() diff --git a/packages/neuron-wallet/tests/setupAndTeardown/public-key-info.fixture.ts b/packages/neuron-wallet/tests/setupAndTeardown/public-key-info.fixture.ts index 6c314371ff..d11da66bfb 100644 --- a/packages/neuron-wallet/tests/setupAndTeardown/public-key-info.fixture.ts +++ b/packages/neuron-wallet/tests/setupAndTeardown/public-key-info.fixture.ts @@ -1,5 +1,5 @@ import { scriptToAddress } from '../../src/utils/scriptAndAddress' -import { AddressType } from '../../src/models/keys/address' +import { AddressType } from '@ckb-lumos/hd' import SystemScriptInfo from '../../src/models/system-script-info' const walletId1 = 'w1' From 300c390d6de3b150306d7e52b564cabb742baf8d Mon Sep 17 00:00:00 2001 From: Tom Wang Date: Tue, 14 May 2024 23:48:03 +0800 Subject: [PATCH 2/7] refactor: replace models/keys/keychain with lumos hd --- .../neuron-wallet/src/controllers/wallets.ts | 2 +- packages/neuron-wallet/src/models/keys/key.ts | 4 +- .../neuron-wallet/src/models/keys/keychain.ts | 149 ----------- .../src/services/sign-message.ts | 5 +- .../src/services/transaction-sender.ts | 5 +- .../tests/models/keys/keychain.test.ts | 249 ------------------ .../tests/services/tx-wallet.test.ts | 2 +- 7 files changed, 8 insertions(+), 408 deletions(-) delete mode 100644 packages/neuron-wallet/src/models/keys/keychain.ts delete mode 100644 packages/neuron-wallet/tests/models/keys/keychain.test.ts diff --git a/packages/neuron-wallet/src/controllers/wallets.ts b/packages/neuron-wallet/src/controllers/wallets.ts index ad5b3fef6a..d96b327379 100644 --- a/packages/neuron-wallet/src/controllers/wallets.ts +++ b/packages/neuron-wallet/src/controllers/wallets.ts @@ -4,7 +4,7 @@ import { dialog, SaveDialogReturnValue, BrowserWindow, OpenDialogReturnValue } f import WalletsService, { Wallet, WalletProperties, FileKeystoreWallet } from '../services/wallets' import NetworksService from '../services/networks' import Keystore from '../models/keys/keystore' -import Keychain from '../models/keys/keychain' +import { Keychain } from '@ckb-lumos/hd' import { validateMnemonic, mnemonicToSeedSync } from '@ckb-lumos/hd/lib/mnemonic' import { AccountExtendedPublicKey, ExtendedPrivateKey } from '../models/keys/key' import { generateMnemonic } from '@ckb-lumos/hd/lib/mnemonic' diff --git a/packages/neuron-wallet/src/models/keys/key.ts b/packages/neuron-wallet/src/models/keys/key.ts index b1a9c7e173..d367f61795 100644 --- a/packages/neuron-wallet/src/models/keys/key.ts +++ b/packages/neuron-wallet/src/models/keys/key.ts @@ -1,6 +1,6 @@ -import { AddressType } from '@ckb-lumos/hd' +import { AddressType, Keychain } from '@ckb-lumos/hd' +import { privateToPublic } from '@ckb-lumos/hd/lib/key' import Address from './address' -import Keychain, { privateToPublic } from './keychain' export interface PathAndPrivateKey { path: string diff --git a/packages/neuron-wallet/src/models/keys/keychain.ts b/packages/neuron-wallet/src/models/keys/keychain.ts deleted file mode 100644 index c7a0872e5f..0000000000 --- a/packages/neuron-wallet/src/models/keys/keychain.ts +++ /dev/null @@ -1,149 +0,0 @@ -import crypto from 'crypto' -import { ec as EC } from 'elliptic' -import BN from 'bn.js' - -const ec = new EC('secp256k1') - -export const privateToPublic = (privateKey: Buffer) => { - if (privateKey.length !== 32) { - throw new Error('Private key must be 32 bytes') - } - - return Buffer.from(ec.keyFromPrivate(privateKey).getPublic(true, 'hex') as string, 'hex') -} - -const EMPTY_BUFFER = Buffer.from('') - -// BIP32 Keychain. Not a full implementation. -export default class Keychain { - privateKey: Buffer = EMPTY_BUFFER - publicKey: Buffer = EMPTY_BUFFER - chainCode: Buffer = EMPTY_BUFFER - index: number = 0 - depth: number = 0 - identifier: Buffer = EMPTY_BUFFER - fingerprint: number = 0 - parentFingerprint: number = 0 - - constructor(privateKey: Buffer, chainCode: Buffer) { - this.privateKey = privateKey - this.chainCode = chainCode - - if (!this.isNeutered()) { - this.publicKey = privateToPublic(this.privateKey) - } - } - - calculateFingerprint = () => { - this.identifier = this.hash160(this.publicKey) - this.fingerprint = this.identifier.slice(0, 4).readUInt32BE(0) - } - - public static fromSeed = (seed: Buffer): Keychain => { - const i = crypto.createHmac('sha512', Buffer.from('Bitcoin seed', 'utf8')).update(seed).digest() - const keychain = new Keychain(i.slice(0, 32), i.slice(32)) - keychain.calculateFingerprint() - return keychain - } - - // Create a child keychain with extended public key and path. - // Children of this keychain should not have any hardened paths. - public static fromPublicKey = (publicKey: Buffer, chainCode: Buffer, path: string): Keychain => { - const keychain = new Keychain(EMPTY_BUFFER, chainCode) - keychain.publicKey = publicKey - keychain.calculateFingerprint() - - const pathComponents = path.split('/') - keychain.depth = pathComponents.length - 1 - keychain.index = parseInt(pathComponents[pathComponents.length - 1], 10) - - return keychain - } - - public deriveChild = (index: number, hardened: boolean): Keychain => { - let data: Buffer - - const indexBuffer = Buffer.allocUnsafe(4) - - if (hardened) { - const pk = Buffer.concat([Buffer.alloc(1, 0), this.privateKey]) - indexBuffer.writeUInt32BE(index + 0x80000000, 0) - data = Buffer.concat([pk, indexBuffer]) - } else { - indexBuffer.writeUInt32BE(index, 0) - data = Buffer.concat([this.publicKey, indexBuffer]) - } - - const i = crypto.createHmac('sha512', this.chainCode).update(data).digest() - const il = i.slice(0, 32) - const ir = i.slice(32) - - let child: Keychain - if (this.isNeutered()) { - child = new Keychain(EMPTY_BUFFER, ir) - child.publicKey = Keychain.publicKeyAdd(this.publicKey, il) - child.calculateFingerprint() - } else { - const privateKey = Keychain.privateKeyAdd(this.privateKey, il) - child = new Keychain(privateKey, ir) - child.calculateFingerprint() - } - - child.index = index - child.depth = this.depth + 1 - child.parentFingerprint = this.fingerprint - - return child - } - - public derivePath = (path: string): Keychain => { - const master = ['m', `/`, ''] - if (master.includes(path)) { - return this - } - - // eslint-disable-next-line @typescript-eslint/no-this-alias - let bip32: Keychain = this - - let entries = path.split('/') - if (entries[0] === 'm') { - entries = entries.slice(1) - } - entries.forEach(c => { - const childIndex = parseInt(c, 10) - const hardened = c.length > 1 && c[c.length - 1] === "'" - bip32 = bip32.deriveChild(childIndex, hardened) - }) - - return bip32 - } - - isNeutered = (): boolean => { - return this.privateKey === EMPTY_BUFFER - } - - hash160 = (data: Buffer): Buffer => { - const sha256 = crypto.createHash('sha256').update(data).digest() - return crypto.createHash('ripemd160').update(sha256).digest() - } - - private static privateKeyAdd = (privateKey: Buffer, factor: Buffer): Buffer => { - const result = new BN(factor) - result.iadd(new BN(privateKey)) - if (result.cmp(ec.curve.n) >= 0) { - result.isub(ec.curve.n) - } - - return result.toArrayLike(Buffer, 'be', 32) - } - - private static publicKeyAdd = (publicKey: Buffer, factor: Buffer): Buffer => { - const x = new BN(publicKey.slice(1)).toRed(ec.curve.red) - let y = x.redSqr().redIMul(x).redIAdd(ec.curve.b).redSqrt() - if ((publicKey[0] === 0x03) !== y.isOdd()) { - y = y.redNeg() - } - const point = ec.curve.g.mul(new BN(factor)).add({ x, y }) - return Buffer.from(point.encode(true, true)) - } -} diff --git a/packages/neuron-wallet/src/services/sign-message.ts b/packages/neuron-wallet/src/services/sign-message.ts index 96787d0ef2..8d3bfd562d 100644 --- a/packages/neuron-wallet/src/services/sign-message.ts +++ b/packages/neuron-wallet/src/services/sign-message.ts @@ -1,8 +1,7 @@ import AddressService from './addresses' import WalletService, { Wallet } from './wallets' -import Keychain from '../models/keys/keychain' import Blake2b from '../models/blake2b' -import hd from '@ckb-lumos/hd' +import { key, Keychain } from '@ckb-lumos/hd' import { ec as EC } from 'elliptic' import { AddressNotFound } from '../exceptions' import HardwareWalletService from './hardware' @@ -40,7 +39,7 @@ export default class SignMessage { private static signByPrivateKey(privateKey: string, message: string): string { const digest = SignMessage.signatureHash(message) - const signature = hd.key.signRecoverable(digest, privateKey) + const signature = key.signRecoverable(digest, privateKey) return signature } diff --git a/packages/neuron-wallet/src/services/transaction-sender.ts b/packages/neuron-wallet/src/services/transaction-sender.ts index 139e6f8179..84c5c01d20 100644 --- a/packages/neuron-wallet/src/services/transaction-sender.ts +++ b/packages/neuron-wallet/src/services/transaction-sender.ts @@ -9,7 +9,6 @@ import { Address } from '../models/address' import FeeMode from '../models/fee-mode' import TransactionSize from '../models/transaction-size' import TransactionFee from '../models/transaction-fee' -import Keychain from '../models/keys/keychain' import Input from '../models/chain/input' import OutPoint from '../models/chain/out-point' import Output from '../models/chain/output' @@ -43,7 +42,7 @@ import { SignStatus } from '../models/offline-sign' import NetworksService from './networks' import { generateRPC } from '../utils/ckb-rpc' import CellsService from './cells' -import hd from '@ckb-lumos/hd' +import { key, Keychain } from '@ckb-lumos/hd' import { getClusterByOutPoint } from '@spore-sdk/core' import CellDep, { DepType } from '../models/chain/cell-dep' import { dao } from '@ckb-lumos/common-scripts' @@ -429,7 +428,7 @@ export default class TransactionSender { if (!wallet.isHardware()) { // `privateKeyOrPath` variable here is a private key because wallet is not a hardware one. Otherwise, it will be a private key path. const privateKey = privateKeyOrPath - emptyWitness.lock = hd.key.signRecoverable(message, privateKey) + emptyWitness.lock = key.signRecoverable(message, privateKey) } return [emptyWitness, ...restWitnesses] diff --git a/packages/neuron-wallet/tests/models/keys/keychain.test.ts b/packages/neuron-wallet/tests/models/keys/keychain.test.ts deleted file mode 100644 index d7b88e3831..0000000000 --- a/packages/neuron-wallet/tests/models/keys/keychain.test.ts +++ /dev/null @@ -1,249 +0,0 @@ -import Keychain, { privateToPublic } from '../../../src/models/keys/keychain' - -// https://en.bitcoin.it/wiki/BIP_0032_TestVectors -describe('BIP32 Keychain tests', () => { - const shortSeed = Buffer.from('000102030405060708090a0b0c0d0e0f', 'hex') - const longSeed = Buffer.from( - 'fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542', - 'hex' - ) - - it('create master keychain from seed', () => { - const master = Keychain.fromSeed(shortSeed) - expect(master.privateKey.toString('hex')).toEqual( - 'e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35' - ) - expect(master.identifier.toString('hex')).toEqual('3442193e1bb70916e914552172cd4e2dbc9df811') - expect(master.fingerprint).toEqual(876747070) - expect(master.chainCode.toString('hex')).toEqual('873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508') - expect(master.index).toEqual(0) - expect(master.depth).toEqual(0) - expect(master.parentFingerprint).toEqual(0) - }) - - it('derive children hardened', () => { - const master = Keychain.fromSeed(shortSeed) - const child = master.deriveChild(0, true) - expect(child.privateKey.toString('hex')).toEqual('edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea') - expect(child.identifier.toString('hex')).toEqual('5c1bd648ed23aa5fd50ba52b2457c11e9e80a6a7') - expect(child.fingerprint).toEqual(1545328200) - expect(child.chainCode.toString('hex')).toEqual('47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141') - expect(child.index).toEqual(0) - expect(child.depth).toEqual(1) - }) - - it('derive path', () => { - const master = Keychain.fromSeed(shortSeed) - expect(master.derivePath(`m/0'`).privateKey.toString('hex')).toEqual( - 'edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea' - ) - - const child = master.derivePath(`m/0'/1/2'`) - expect(child.privateKey.toString('hex')).toEqual('cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca') - expect(child.identifier.toString('hex')).toEqual('ee7ab90cde56a8c0e2bb086ac49748b8db9dce72') - expect(child.fingerprint).toEqual(4001020172) - expect(child.chainCode.toString('hex')).toEqual('04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f') - expect(child.index).toEqual(2) - expect(child.depth).toEqual(3) - }) - - it('create master keychain from long seed', () => { - const master = Keychain.fromSeed(longSeed) - expect(master.privateKey.toString('hex')).toEqual( - '4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e' - ) - expect(master.identifier.toString('hex')).toEqual('bd16bee53961a47d6ad888e29545434a89bdfe95') - expect(master.fingerprint).toEqual(3172384485) - expect(master.chainCode.toString('hex')).toEqual('60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689') - expect(master.index).toEqual(0) - expect(master.depth).toEqual(0) - expect(master.parentFingerprint).toEqual(0) - }) - - it('derive path large index', () => { - const master = Keychain.fromSeed(longSeed) - expect(master.derivePath(`m`).privateKey.toString('hex')).toEqual( - '4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e' - ) - - let child = master.derivePath(`0/2147483647'`) - expect(child.privateKey.toString('hex')).toEqual('877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93') - expect(child.identifier.toString('hex')).toEqual('d8ab493736da02f11ed682f88339e720fb0379d1') - expect(child.fingerprint).toEqual(3635104055) - expect(child.chainCode.toString('hex')).toEqual('be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9') - expect(child.index).toEqual(2147483647) - expect(child.depth).toEqual(2) - - child = child.deriveChild(1, false) - expect(child.privateKey.toString('hex')).toEqual('704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7') - expect(child.identifier.toString('hex')).toEqual('78412e3a2296a40de124307b6485bd19833e2e34') - expect(child.fingerprint).toEqual(2017537594) - expect(child.chainCode.toString('hex')).toEqual('f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb') - expect(child.index).toEqual(1) - expect(child.depth).toEqual(3) - - child = child.deriveChild(2147483646, true) - expect(child.privateKey.toString('hex')).toEqual('f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d') - expect(child.identifier.toString('hex')).toEqual('31a507b815593dfc51ffc7245ae7e5aee304246e') - expect(child.fingerprint).toEqual(832899000) - expect(child.chainCode.toString('hex')).toEqual('637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29') - expect(child.index).toEqual(2147483646) - expect(child.depth).toEqual(4) - }) - - it('derive children no hardened', () => { - const master = Keychain.fromSeed(longSeed) - const child = master.deriveChild(0, false) - expect(child.privateKey.toString('hex')).toEqual('abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e') - expect(child.identifier.toString('hex')).toEqual('5a61ff8eb7aaca3010db97ebda76121610b78096') - expect(child.fingerprint).toEqual(1516371854) - expect(child.chainCode.toString('hex')).toEqual('f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c') - expect(child.index).toEqual(0) - expect(child.depth).toEqual(1) - }) - - it('create child keychain from public key', () => { - const child = Keychain.fromPublicKey( - Buffer.from('0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2', 'hex'), - Buffer.from('04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f', 'hex'), - `m/0'/1/2'` - ) - expect(child.identifier.toString('hex')).toEqual('ee7ab90cde56a8c0e2bb086ac49748b8db9dce72') - expect(child.fingerprint).toEqual(4001020172) - expect(child.index).toEqual(2) - expect(child.depth).toEqual(3) - - const grandchild = child.deriveChild(2, false) - expect(grandchild.publicKey.toString('hex')).toEqual( - '02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29' - ) - expect(grandchild.chainCode.toString('hex')).toEqual( - 'cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd' - ) - expect(grandchild.identifier.toString('hex')).toEqual('d880d7d893848509a62d8fb74e32148dac68412f') - expect(grandchild.fingerprint).toEqual(3632322520) - expect(grandchild.index).toEqual(2) - expect(grandchild.depth).toEqual(4) - }) - - it('derive ckb keys', () => { - const master = Keychain.fromSeed(shortSeed) - const extendedKey = master.derivePath(`m/44'/309'/0'`) - expect(extendedKey.privateKey.toString('hex')).toEqual( - 'bb39d218506b30ca69b0f3112427877d983dd3cd2cabc742ab723e2964d98016' - ) - expect(extendedKey.publicKey.toString('hex')).toEqual( - '03e5b310636a0f6e7dcdfffa98f28d7ed70df858bb47acf13db830bfde3510b3f3' - ) - expect(extendedKey.chainCode.toString('hex')).toEqual( - '37e85a19f54f0a242a35599abac64a71aacc21e3a5860dd024377ffc7e6827d8' - ) - - const addressKey = extendedKey.deriveChild(0, false).deriveChild(0, false) - expect(addressKey.privateKey.toString('hex')).toEqual( - 'fcba4708f1f07ddc00fc77422d7a70c72b3456f5fef3b2f68368cdee4e6fb498' - ) - expect(addressKey.publicKey.toString('hex')).toEqual( - '0331b3c0225388c5010e3507beb28ecf409c022ef6f358f02b139cbae082f5a2a3' - ) - expect(addressKey.chainCode.toString('hex')).toEqual( - 'c4b7aef857b625bbb0497267ed51151d090f81737f4f22a0ac3673483b927090' - ) - }) - - it('derive ckb keys another seed', () => { - const master = Keychain.fromSeed( - // From mnemonic `tank planet champion pottery together intact quick police asset flower sudden question` - Buffer.from( - '1371018cfad5990f5e451bf586d59c3820a8671162d8700533549b0df61a63330e5cd5099a5d3938f833d51e4572104868bfac7cfe5b4063b1509a995652bc08', - 'hex' - ) - ) - expect(master.privateKey.toString('hex')).toEqual( - '37d25afe073a6ba17badc2df8e91fc0de59ed88bcad6b9a0c2210f325fafca61' - ) - - expect(master.derivePath(`m/44'/309'/0'`).privateKey.toString('hex')).toEqual( - '2925f5dfcbee3b6ad29100a37ed36cbe92d51069779cc96164182c779c5dc20e' - ) - - expect(master.derivePath(`m/44'/309'/0'`).deriveChild(0, false).privateKey.toString('hex')).toEqual( - '047fae4f38b3204f93a6b39d6dbcfbf5901f2b09f6afec21cbef6033d01801f1' - ) - - expect(master.derivePath(`m/44'/309'/0'/0`).privateKey.toString('hex')).toEqual( - '047fae4f38b3204f93a6b39d6dbcfbf5901f2b09f6afec21cbef6033d01801f1' - ) - - expect( - master.derivePath(`m/44'/309'/0'`).deriveChild(0, false).deriveChild(0, false).privateKey.toString('hex') - ).toEqual('848422863825f69e66dc7f48a3302459ec845395370c23578817456ad6b04b14') - - expect(master.derivePath(`m/44'/309'/0'/0/0`).privateKey.toString('hex')).toEqual( - '848422863825f69e66dc7f48a3302459ec845395370c23578817456ad6b04b14' - ) - }) - - it('derive ckb keys from master extended key', () => { - const privateKey = Buffer.from('37d25afe073a6ba17badc2df8e91fc0de59ed88bcad6b9a0c2210f325fafca61', 'hex') - const chainCode = Buffer.from('5f772d1e3cfee5821911aefa5e8f79d20d4cf6678378d744efd08b66b2633b80', 'hex') - const master = new Keychain(privateKey, chainCode) - expect(master.publicKey.toString('hex')).toEqual( - '020720a7a11a9ac4f0330e2b9537f594388ea4f1cd660301f40b5a70e0bc231065' - ) - - expect(master.derivePath(`m/44'/309'/0'`).privateKey.toString('hex')).toEqual( - '2925f5dfcbee3b6ad29100a37ed36cbe92d51069779cc96164182c779c5dc20e' - ) - - expect(master.derivePath(`m/44'/309'/0'`).deriveChild(0, false).privateKey.toString('hex')).toEqual( - '047fae4f38b3204f93a6b39d6dbcfbf5901f2b09f6afec21cbef6033d01801f1' - ) - - expect(master.derivePath(`m/44'/309'/0'/0`).privateKey.toString('hex')).toEqual( - '047fae4f38b3204f93a6b39d6dbcfbf5901f2b09f6afec21cbef6033d01801f1' - ) - - expect( - master.derivePath(`m/44'/309'/0'`).deriveChild(0, false).deriveChild(0, false).privateKey.toString('hex') - ).toEqual('848422863825f69e66dc7f48a3302459ec845395370c23578817456ad6b04b14') - - expect(master.derivePath(`m/44'/309'/0'/0/0`).privateKey.toString('hex')).toEqual( - '848422863825f69e66dc7f48a3302459ec845395370c23578817456ad6b04b14' - ) - }) - - it('private key add', () => { - const privateKey = Buffer.from('9e919c96ac5a4caea7ba0ea1f7dd7bca5dca8a11e66ed633690c71e483a6e3c9', 'hex') - const toAdd = Buffer.from('36e92e33659808bf06c3e4302b657f39ca285f6bb5393019bb4e2f7b96e3f914', 'hex') - // @ts-ignore: Private method - const sum = Keychain.privateKeyAdd(privateKey, toAdd) - expect(sum.toString('hex')).toEqual('d57acaca11f2556dae7df2d22342fb0427f2e97d9ba8064d245aa1601a8adcdd') - }) - - it('public key add', () => { - const publicKey = Buffer.from('03556b2c7e03b12845a973a6555b49fe44b0836fbf3587709fa73bb040ba181b21', 'hex') - const toAdd = Buffer.from('953fd6b91b51605d32a28ab478f39ab53c90103b93bd688330b118c460e9c667', 'hex') - // @ts-ignore: Private method - const sum = Keychain.publicKeyAdd(publicKey, toAdd) - expect(sum.toString('hex')).toEqual('03db6eab66f918e434bae0e24fd73de1a2b293a2af9bd3ad53123996fa94494f37') - }) -}) - -describe('private to public', () => { - it('derive public key from private key', () => { - const privateKey = Buffer.from('bb39d218506b30ca69b0f3112427877d983dd3cd2cabc742ab723e2964d98016', 'hex') - const publicKey = Buffer.from('03e5b310636a0f6e7dcdfffa98f28d7ed70df858bb47acf13db830bfde3510b3f3', 'hex') - expect(privateToPublic(privateKey)).toEqual(publicKey) - }) - - it('derive public key from private key wrong length', () => { - expect(() => privateToPublic(Buffer.from(''))).toThrowError() - expect(() => - privateToPublic(Buffer.from('39d218506b30ca69b0f3112427877d983dd3cd2cabc742ab723e2964d98016', 'hex')) - ).toThrowError() - expect(() => - privateToPublic(Buffer.from('0xbb39d218506b30ca69b0f3112427877d983dd3cd2cabc742ab723e2964d98016', 'hex')) - ).toThrowError() - }) -}) diff --git a/packages/neuron-wallet/tests/services/tx-wallet.test.ts b/packages/neuron-wallet/tests/services/tx-wallet.test.ts index 39d8e94461..27a4b8f133 100644 --- a/packages/neuron-wallet/tests/services/tx-wallet.test.ts +++ b/packages/neuron-wallet/tests/services/tx-wallet.test.ts @@ -1,6 +1,6 @@ import WalletService from '../../src/services/wallets' import Keystore from '../../src/models/keys/keystore' -import Keychain from '../../src/models/keys/keychain' +import { Keychain } from '@ckb-lumos/hd' import { mnemonicToSeedSync } from '@ckb-lumos/hd/lib/mnemonic' import { ExtendedPrivateKey, AccountExtendedPublicKey } from '../../src/models/keys/key' import TransactionSender from '../../src/services/transaction-sender' From 9d02a3f1685eba79c0dcccbde05e0a44b5be784b Mon Sep 17 00:00:00 2001 From: Tom Wang Date: Wed, 15 May 2024 00:02:36 +0800 Subject: [PATCH 3/7] refactor: replace models/keys/keystore with lumos hd --- .../neuron-wallet/src/controllers/wallets.ts | 9 +- .../neuron-wallet/src/models/keys/keystore.ts | 176 ------------------ .../src/services/transaction-sender.ts | 4 +- .../neuron-wallet/src/services/wallets.ts | 2 +- .../tests/models/keys/keystore.test.ts | 89 --------- .../tests/services/tx-wallet.test.ts | 11 +- .../services/tx/transaction-sender.test.ts | 3 +- .../tests/services/wallets.test.ts | 3 +- 8 files changed, 14 insertions(+), 283 deletions(-) delete mode 100644 packages/neuron-wallet/src/models/keys/keystore.ts delete mode 100644 packages/neuron-wallet/tests/models/keys/keystore.test.ts diff --git a/packages/neuron-wallet/src/controllers/wallets.ts b/packages/neuron-wallet/src/controllers/wallets.ts index d96b327379..25710f194e 100644 --- a/packages/neuron-wallet/src/controllers/wallets.ts +++ b/packages/neuron-wallet/src/controllers/wallets.ts @@ -3,10 +3,9 @@ import { t } from 'i18next' import { dialog, SaveDialogReturnValue, BrowserWindow, OpenDialogReturnValue } from 'electron' import WalletsService, { Wallet, WalletProperties, FileKeystoreWallet } from '../services/wallets' import NetworksService from '../services/networks' -import Keystore from '../models/keys/keystore' -import { Keychain } from '@ckb-lumos/hd' +import { Keychain, Keystore, ExtendedPrivateKey } from '@ckb-lumos/hd' import { validateMnemonic, mnemonicToSeedSync } from '@ckb-lumos/hd/lib/mnemonic' -import { AccountExtendedPublicKey, ExtendedPrivateKey } from '../models/keys/key' +import { AccountExtendedPublicKey } from '../models/keys/key' import { generateMnemonic } from '@ckb-lumos/hd/lib/mnemonic' import CommandSubject from '../models/subjects/command' import { ResponseCode } from '../utils/const' @@ -107,8 +106,8 @@ export default class WalletsController { throw new InvalidMnemonic() } const extendedKey = new ExtendedPrivateKey( - masterKeychain.privateKey.toString('hex'), - masterKeychain.chainCode.toString('hex') + `0x${masterKeychain.privateKey.toString('hex')}`, + `0x${masterKeychain.chainCode.toString('hex')}` ) const keystore = Keystore.create(extendedKey, password) diff --git a/packages/neuron-wallet/src/models/keys/keystore.ts b/packages/neuron-wallet/src/models/keys/keystore.ts deleted file mode 100644 index f69427433c..0000000000 --- a/packages/neuron-wallet/src/models/keys/keystore.ts +++ /dev/null @@ -1,176 +0,0 @@ -import crypto from 'crypto' -import { Keccak } from 'sha3' -import { v4 as uuid } from 'uuid' - -import { UnsupportedCipher, IncorrectPassword, InvalidKeystore } from '../../exceptions' -import { ExtendedPrivateKey } from './key' - -const CIPHER = 'aes-128-ctr' -const CKB_CLI_ORIGIN = 'ckb-cli' - -interface CipherParams { - iv: string -} - -interface KdfParams { - dklen: number - n: number - r: number - p: number - salt: string -} - -interface Crypto { - cipher: string - cipherparams: CipherParams - ciphertext: string - kdf: string - kdfparams: KdfParams - mac: string -} - -// Encrypt and save master extended private key. -export default class Keystore { - crypto: Crypto - id: string - version: number = 3 - - constructor(theCrypto: Crypto, id: string) { - this.crypto = theCrypto - this.id = id - } - - static fromJson = (json: string) => { - try { - const object = JSON.parse(json) - if (object.origin === CKB_CLI_ORIGIN) { - throw 'Keystore from CKB CLI is not supported' - } - if (!object.crypto || !object.id) { - throw new InvalidKeystore() - } - return new Keystore(object.crypto, object.id) - } catch { - throw new InvalidKeystore() - } - } - - // Create an empty keystore object that contains empty private key - static createEmpty = () => { - const salt = crypto.randomBytes(32) - const iv = crypto.randomBytes(16) - const kdfparams: KdfParams = { - dklen: 32, - salt: salt.toString('hex'), - n: 2 ** 18, - r: 8, - p: 1, - } - return new Keystore( - { - ciphertext: '', - cipherparams: { - iv: iv.toString('hex'), - }, - cipher: CIPHER, - kdf: 'scrypt', - kdfparams, - mac: '', - }, - uuid() - ) - } - - static create = ( - extendedPrivateKey: ExtendedPrivateKey, - password: string, - options: { salt?: Buffer; iv?: Buffer } = {} - ) => { - const salt = options.salt || crypto.randomBytes(32) - const iv = options.iv || crypto.randomBytes(16) - const kdfparams: KdfParams = { - dklen: 32, - salt: salt.toString('hex'), - n: 2 ** 18, - r: 8, - p: 1, - } - const derivedKey = crypto.scryptSync(password, salt, kdfparams.dklen, Keystore.scryptOptions(kdfparams)) - - const cipher = crypto.createCipheriv(CIPHER, derivedKey.slice(0, 16), iv) - if (!cipher) { - throw new UnsupportedCipher() - } - const ciphertext = Buffer.concat([ - cipher.update(Buffer.from(extendedPrivateKey.serialize(), 'hex')), - cipher.final(), - ]) - - return new Keystore( - { - ciphertext: ciphertext.toString('hex'), - cipherparams: { - iv: iv.toString('hex'), - }, - cipher: CIPHER, - kdf: 'scrypt', - kdfparams, - mac: Keystore.mac(derivedKey, ciphertext), - }, - uuid() - ) - } - - // Imported from xpub with empty private key. - isEmpty(): boolean { - return this.crypto.ciphertext === '' && this.crypto.mac === '' - } - - // Decrypt and return serialized extended private key. - decrypt(password: string): string { - const derivedKey = this.derivedKey(password) - const ciphertext = Buffer.from(this.crypto.ciphertext, 'hex') - if (Keystore.mac(derivedKey, ciphertext) !== this.crypto.mac) { - throw new IncorrectPassword() - } - const decipher = crypto.createDecipheriv( - this.crypto.cipher, - derivedKey.slice(0, 16), - Buffer.from(this.crypto.cipherparams.iv, 'hex') - ) - return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString('hex') - } - - extendedPrivateKey = (password: string): ExtendedPrivateKey => { - return ExtendedPrivateKey.parse(this.decrypt(password)) - } - - checkPassword = (password: string) => { - const derivedKey = this.derivedKey(password) - const ciphertext = Buffer.from(this.crypto.ciphertext, 'hex') - return Keystore.mac(derivedKey, ciphertext) === this.crypto.mac - } - - derivedKey = (password: string) => { - const { kdfparams } = this.crypto - return crypto.scryptSync( - password, - Buffer.from(kdfparams.salt, 'hex'), - kdfparams.dklen, - Keystore.scryptOptions(kdfparams) - ) - } - - static mac = (derivedKey: Buffer, ciphertext: Buffer) => { - return new Keccak(256).update(Buffer.concat([derivedKey.slice(16, 32), ciphertext])).digest('hex') - } - - static scryptOptions = (kdfparams: KdfParams) => { - return { - N: kdfparams.n, - r: kdfparams.r, - p: kdfparams.p, - maxmem: 128 * (kdfparams.n + kdfparams.p + 2) * kdfparams.r, - } - } -} diff --git a/packages/neuron-wallet/src/services/transaction-sender.ts b/packages/neuron-wallet/src/services/transaction-sender.ts index 84c5c01d20..b540b347e4 100644 --- a/packages/neuron-wallet/src/services/transaction-sender.ts +++ b/packages/neuron-wallet/src/services/transaction-sender.ts @@ -927,8 +927,8 @@ export default class TransactionSender { public getPrivateKeys = (wallet: Wallet, paths: string[], password: string): PathAndPrivateKey[] => { const masterPrivateKey = wallet.loadKeystore().extendedPrivateKey(password) const masterKeychain = new Keychain( - Buffer.from(masterPrivateKey.privateKey, 'hex'), - Buffer.from(masterPrivateKey.chainCode, 'hex') + Buffer.from(masterPrivateKey.privateKey.slice(2), 'hex'), + Buffer.from(masterPrivateKey.chainCode.slice(2), 'hex') ) const uniquePaths = paths.filter((value, idx, a) => a.indexOf(value) === idx) diff --git a/packages/neuron-wallet/src/services/wallets.ts b/packages/neuron-wallet/src/services/wallets.ts index f8977b79c5..bd88922384 100644 --- a/packages/neuron-wallet/src/services/wallets.ts +++ b/packages/neuron-wallet/src/services/wallets.ts @@ -1,7 +1,7 @@ import { v4 as uuid } from 'uuid' import { WalletNotFound, IsRequired, UsedName, WalletFunctionNotSupported, DuplicateImportWallet } from '../exceptions' import Store from '../models/store' -import Keystore from '../models/keys/keystore' +import { Keystore } from '@ckb-lumos/hd' import WalletDeletedSubject from '../models/subjects/wallet-deleted-subject' import { WalletListSubject, CurrentWalletSubject } from '../models/subjects/wallets' import { AccountExtendedPublicKey } from '../models/keys/key' diff --git a/packages/neuron-wallet/tests/models/keys/keystore.test.ts b/packages/neuron-wallet/tests/models/keys/keystore.test.ts deleted file mode 100644 index 39b7e0b041..0000000000 --- a/packages/neuron-wallet/tests/models/keys/keystore.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { ExtendedPrivateKey } from '../../../src/models/keys/key' -import Keystore from '../../../src/models/keys/keystore' -import { IncorrectPassword } from '../../../src/exceptions/wallet' - -const fixture = { - privateKey: 'e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35', - publicKey: '0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2', - chainCode: '873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508', -} - -describe('load and check password', () => { - const password = 'hello~!23' - const keystore = Keystore.create(new ExtendedPrivateKey(fixture.privateKey, fixture.chainCode), password) - - it('checks wrong password', () => { - expect(keystore.checkPassword(`oops${password}`)).toBe(false) - }) - - it('checks correct password', () => { - expect(keystore.checkPassword(password)).toBe(true) - }) - - it('decrypts', () => { - expect(keystore.decrypt(password)).toEqual( - new ExtendedPrivateKey(fixture.privateKey, fixture.chainCode).serialize() - ) - }) - - it('loads private key', () => { - const extendedPrivateKey = keystore.extendedPrivateKey(password) - expect(extendedPrivateKey.privateKey).toEqual(fixture.privateKey) - expect(extendedPrivateKey.chainCode).toEqual(fixture.chainCode) - }) -}) - -describe('load ckb cli light keystore', () => { - const password = '123' - const keystoreString = - '{"crypto":{"cipher": "aes-128-ctr", "ciphertext": "253397209cae86474e368720f9baa30f448767047d2cc5a7672ef121861974ed", "cipherparams": {"iv": "8bd8523e0048db3a4ae2534aec6d303a"}, "kdf": "scrypt", "kdfparams": {"dklen": 32, "n": 4096, "p": 6, "r": 8, "salt": "be3d86c99f4895f99d1a0048afb61a34153fa83d5edd033fc914de2c502f57e7"}, "mac": "4453cf5d4f6ec43d0664c3895c4ab9b1c9bcd2d02c7abb190c84375a42739099" },"id": "id", "version": 3}' - const keystore = Keystore.fromJson(keystoreString) - - it('checks correct password', () => { - expect(keystore.checkPassword(password)).toBe(true) - }) -}) - -describe('load ckb cli standard keystore', () => { - const password = '123' - const keystoreString = - '{"address":"ea22142fa5be326e834681144ca30326f99a6d5a","crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"29304e5bcbb1885ef5cdcb40b5312b58"},"ciphertext":"93054530a8fbe5b11995acda856585d7362ac7d2b1e4f268c633d997be2d6532c4962501d0835bf52a4693ae7a091ac9bac9297793f4116ef7c123edb00dbc85","kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"724327e67ca321ccf15035bb78a0a05c816bebbe218a0840abdc26da8453c1f4"},"mac":"1d0e5660ffbfc1f9ff4da97aefcfc2153c0ec1b411e35ffee26ee92815cc06f9"},"id":"43c1116e-efd5-4c9e-a86a-3ec0ab163122","version":3}' - const keystore = Keystore.fromJson(keystoreString) - - it('checks correct password', () => { - expect(keystore.checkPassword(password)).toBe(true) - }) - - it('loads private key', () => { - const extendedPrivateKey = keystore.extendedPrivateKey(password) - expect(extendedPrivateKey.privateKey).toEqual('8af124598932440269a81771ad662642e83a38b323b2f70223b8ae0b6c5e0779') - expect(extendedPrivateKey.chainCode).toEqual('615302e2c93151a55c29121dd02ad554e47908a6df6d7374f357092cec11675b') - }) -}) - -describe('load ckb cli origin keystore', () => { - const keystoreString = - '{"origin":"ckb-cli", "address":"ea22142fa5be326e834681144ca30326f99a6d5a","crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"29304e5bcbb1885ef5cdcb40b5312b58"},"ciphertext":"93054530a8fbe5b11995acda856585d7362ac7d2b1e4f268c633d997be2d6532c4962501d0835bf52a4693ae7a091ac9bac9297793f4116ef7c123edb00dbc85","kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"724327e67ca321ccf15035bb78a0a05c816bebbe218a0840abdc26da8453c1f4"},"mac":"1d0e5660ffbfc1f9ff4da97aefcfc2153c0ec1b411e35ffee26ee92815cc06f9"},"id":"43c1116e-efd5-4c9e-a86a-3ec0ab163122","version":3}' - - it('does not load', () => { - expect(() => Keystore.fromJson(keystoreString)).toThrowError() - }) -}) - -describe('create empty keystore', () => { - const keystore = Keystore.createEmpty() - - it('has empty ciphertext and mac', () => { - expect(keystore.crypto.ciphertext).toEqual('') - expect(keystore.crypto.mac).toEqual('') - }) - - it("won't verify password", () => { - expect(keystore.checkPassword('')).toBeFalsy() - expect(keystore.checkPassword('anypassword')).toBeFalsy() - }) - - it('cannot decrypt', () => { - expect(() => keystore.decrypt('')).toThrowError(new IncorrectPassword()) - }) -}) diff --git a/packages/neuron-wallet/tests/services/tx-wallet.test.ts b/packages/neuron-wallet/tests/services/tx-wallet.test.ts index 27a4b8f133..7a1b7576a5 100644 --- a/packages/neuron-wallet/tests/services/tx-wallet.test.ts +++ b/packages/neuron-wallet/tests/services/tx-wallet.test.ts @@ -1,8 +1,7 @@ import WalletService from '../../src/services/wallets' -import Keystore from '../../src/models/keys/keystore' -import { Keychain } from '@ckb-lumos/hd' +import { Keychain, Keystore, ExtendedPrivateKey } from '@ckb-lumos/hd' import { mnemonicToSeedSync } from '@ckb-lumos/hd/lib/mnemonic' -import { ExtendedPrivateKey, AccountExtendedPublicKey } from '../../src/models/keys/key' +import { AccountExtendedPublicKey } from '../../src/models/keys/key' import TransactionSender from '../../src/services/transaction-sender' import { signWitnesses } from '../../src/utils/signWitnesses' @@ -45,8 +44,8 @@ describe('get keys with paths', () => { const seed = mnemonicToSeedSync(mnemonic) const masterKeychain = Keychain.fromSeed(seed) const extendedKey = new ExtendedPrivateKey( - masterKeychain.privateKey.toString('hex'), - masterKeychain.chainCode.toString('hex') + `0x${masterKeychain.privateKey.toString('hex')}`, + `0x${masterKeychain.chainCode.toString('hex')}` ) const p = masterKeychain.derivePath(receivingPath).privateKey.toString('hex') expect(`0x${p}`).toEqual(receivingPrivateKey) @@ -66,7 +65,7 @@ describe('get keys with paths', () => { }) const masterPrivateKey = wallet.loadKeystore().extendedPrivateKey(password) - expect(masterKeychain.privateKey.toString('hex')).toEqual(masterPrivateKey.privateKey) + expect(`0x${masterKeychain.privateKey.toString('hex')}`).toEqual(masterPrivateKey.privateKey) const pathsAndKeys = new TransactionSender().getPrivateKeys(wallet, [receivingPath, changePath], password) expect(pathsAndKeys[0]).toEqual({ diff --git a/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts b/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts index 1d28c4254f..919d8f3bdd 100644 --- a/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts +++ b/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts @@ -187,8 +187,7 @@ import OutPoint from '../../../src/models/chain/out-point' import Input from '../../../src/models/chain/input' import Script, { ScriptHashType } from '../../../src/models/chain/script' import Output from '../../../src/models/chain/output' -import Keystore from '../../../src/models/keys/keystore' -import { AddressType } from '@ckb-lumos/hd' +import { AddressType, Keystore } from '@ckb-lumos/hd' import WitnessArgs from '../../../src/models/chain/witness-args' import CellWithStatus from '../../../src/models/chain/cell-with-status' import SystemScriptInfo from '../../../src/models/system-script-info' diff --git a/packages/neuron-wallet/tests/services/wallets.test.ts b/packages/neuron-wallet/tests/services/wallets.test.ts index 66ab45a7c6..0009709fd4 100644 --- a/packages/neuron-wallet/tests/services/wallets.test.ts +++ b/packages/neuron-wallet/tests/services/wallets.test.ts @@ -1,7 +1,6 @@ -import Keystore from '../../src/models/keys/keystore' import { when } from 'jest-when' import { WalletFunctionNotSupported, DuplicateImportWallet } from '../../src/exceptions/wallet' -import { AddressType } from '@ckb-lumos/hd' +import { AddressType, Keystore } from '@ckb-lumos/hd' import { Manufacturer } from '../../src/services/hardware/common' const stubbedDeletedByWalletIdFn = jest.fn() From bbf5f45dfbb1698beee132bca63a1ee4571387d2 Mon Sep 17 00:00:00 2001 From: Tom Wang Date: Wed, 15 May 2024 12:27:38 +0800 Subject: [PATCH 4/7] refactor: replace models/keys/key with lumos hd --- .../neuron-wallet/src/controllers/hardware.ts | 2 +- .../neuron-wallet/src/controllers/wallets.ts | 21 ++-- .../neuron-wallet/src/models/keys/address.ts | 3 +- packages/neuron-wallet/src/models/keys/key.ts | 95 ------------------- .../neuron-wallet/src/services/addresses.ts | 24 ++--- .../src/services/hardware/hardware.ts | 2 +- .../src/services/transaction-sender.ts | 6 +- .../neuron-wallet/src/services/wallets.ts | 12 +-- .../src/utils/scriptAndAddress.ts | 2 + .../tests/models/keys/key.test.ts | 67 ------------- .../tests/services/address.test.ts | 22 ++--- .../tests/services/tx-wallet.test.ts | 7 +- .../tests/services/wallets.test.ts | 26 ++--- 13 files changed, 62 insertions(+), 227 deletions(-) delete mode 100644 packages/neuron-wallet/src/models/keys/key.ts delete mode 100644 packages/neuron-wallet/tests/models/keys/key.test.ts diff --git a/packages/neuron-wallet/src/controllers/hardware.ts b/packages/neuron-wallet/src/controllers/hardware.ts index 41cd9f0d8a..182381ba61 100644 --- a/packages/neuron-wallet/src/controllers/hardware.ts +++ b/packages/neuron-wallet/src/controllers/hardware.ts @@ -2,7 +2,7 @@ import { DeviceInfo, ExtendedPublicKey, PublicKey } from '../services/hardware/c import { ResponseCode } from '../utils/const' import HardwareWalletService from '../services/hardware' import { connectDeviceFailed } from '../exceptions' -import { AccountExtendedPublicKey } from '../models/keys/key' +import { AccountExtendedPublicKey } from '@ckb-lumos/hd' export default class HardwareController { public async connectDevice(deviceInfo: DeviceInfo): Promise> { diff --git a/packages/neuron-wallet/src/controllers/wallets.ts b/packages/neuron-wallet/src/controllers/wallets.ts index 25710f194e..459464fb34 100644 --- a/packages/neuron-wallet/src/controllers/wallets.ts +++ b/packages/neuron-wallet/src/controllers/wallets.ts @@ -1,12 +1,11 @@ import fs from 'fs' import { t } from 'i18next' +import { Ox } from '../utils/scriptAndAddress' import { dialog, SaveDialogReturnValue, BrowserWindow, OpenDialogReturnValue } from 'electron' import WalletsService, { Wallet, WalletProperties, FileKeystoreWallet } from '../services/wallets' import NetworksService from '../services/networks' -import { Keychain, Keystore, ExtendedPrivateKey } from '@ckb-lumos/hd' -import { validateMnemonic, mnemonicToSeedSync } from '@ckb-lumos/hd/lib/mnemonic' -import { AccountExtendedPublicKey } from '../models/keys/key' -import { generateMnemonic } from '@ckb-lumos/hd/lib/mnemonic' +import { Keychain, Keystore, ExtendedPrivateKey, AccountExtendedPublicKey } from '@ckb-lumos/hd' +import { generateMnemonic, validateMnemonic, mnemonicToSeedSync } from '@ckb-lumos/hd/lib/mnemonic' import CommandSubject from '../models/subjects/command' import { ResponseCode } from '../utils/const' import { @@ -106,15 +105,15 @@ export default class WalletsController { throw new InvalidMnemonic() } const extendedKey = new ExtendedPrivateKey( - `0x${masterKeychain.privateKey.toString('hex')}`, - `0x${masterKeychain.chainCode.toString('hex')}` + Ox(masterKeychain.privateKey.toString('hex')), + Ox(masterKeychain.chainCode.toString('hex')) ) const keystore = Keystore.create(extendedKey, password) const accountKeychain = masterKeychain.derivePath(AccountExtendedPublicKey.ckbAccountPath) const accountExtendedPublicKey = new AccountExtendedPublicKey( - accountKeychain.publicKey.toString('hex'), - accountKeychain.chainCode.toString('hex') + Ox(accountKeychain.publicKey.toString('hex')), + Ox(accountKeychain.chainCode.toString('hex')) ) const walletsService = WalletsService.getInstance() @@ -173,8 +172,8 @@ export default class WalletsController { ) const accountKeychain = masterKeychain.derivePath(AccountExtendedPublicKey.ckbAccountPath) const accountExtendedPublicKey = new AccountExtendedPublicKey( - accountKeychain.publicKey.toString('hex'), - accountKeychain.chainCode.toString('hex') + Ox(accountKeychain.publicKey.toString('hex')), + Ox(accountKeychain.chainCode.toString('hex')) ) const walletsService = WalletsService.getInstance() @@ -273,7 +272,7 @@ export default class WalletsController { walletName, }: ExtendedPublicKey & { walletName: string }): Promise> { const device = HardwareWalletService.getInstance().getCurrent()! - const accountExtendedPublicKey = new AccountExtendedPublicKey(publicKey, chainCode) + const accountExtendedPublicKey = new AccountExtendedPublicKey(Ox(publicKey), Ox(chainCode)) const walletsService = WalletsService.getInstance() const wallet = walletsService.create({ device: device.deviceInfo, diff --git a/packages/neuron-wallet/src/models/keys/address.ts b/packages/neuron-wallet/src/models/keys/address.ts index 61a5e2482c..747e49b973 100644 --- a/packages/neuron-wallet/src/models/keys/address.ts +++ b/packages/neuron-wallet/src/models/keys/address.ts @@ -1,7 +1,6 @@ import { scriptToAddress } from '../../utils/scriptAndAddress' -import { AccountExtendedPublicKey } from './key' import { systemScripts } from '../../utils/systemScripts' -import { key, AddressType } from '@ckb-lumos/hd' +import { key, AddressType, AccountExtendedPublicKey } from '@ckb-lumos/hd' export enum DefaultAddressNumber { Receiving = 20, diff --git a/packages/neuron-wallet/src/models/keys/key.ts b/packages/neuron-wallet/src/models/keys/key.ts deleted file mode 100644 index d367f61795..0000000000 --- a/packages/neuron-wallet/src/models/keys/key.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { AddressType, Keychain } from '@ckb-lumos/hd' -import { privateToPublic } from '@ckb-lumos/hd/lib/key' -import Address from './address' - -export interface PathAndPrivateKey { - path: string - privateKey: string -} - -const UNCOMPRESSED_KEY_LENGTH = 130 - -export class ExtendedPublicKey { - publicKey: string - chainCode: string - - constructor(publicKey: string, chainCode: string) { - this.publicKey = ExtendedPublicKey.compressPublicKey(publicKey) - this.chainCode = chainCode - } - - static compressPublicKey = (key: string) => { - if (key.length !== UNCOMPRESSED_KEY_LENGTH) { - return key - } - - const publicKey = Buffer.from(key, 'hex') - const compressedPublicKey = Buffer.alloc(33) - // '03' for odd value, '02' for even value - .fill(publicKey[64] & 1 ? '03' : '02', 0, 1, 'hex') - .fill(publicKey.subarray(1, 33), 1, 33) - return compressedPublicKey.toString('hex') - } - - isUncompressedKey = (publicKey: string) => { - return publicKey.startsWith('04') - } - - serialize = () => { - return this.publicKey + this.chainCode - } - - static parse = (serialized: string) => { - return new ExtendedPublicKey(serialized.slice(0, 66), serialized.slice(66)) - } -} - -// Extended public key of the BIP44 path down to account level, -// which is `m/44'/309'/0'`. This key will be persisted to wallet -// and used to derive receiving/change addresses. -export class AccountExtendedPublicKey extends ExtendedPublicKey { - public static ckbAccountPath = `m/44'/309'/0'` - - static parse = (serialized: string) => { - return new AccountExtendedPublicKey(serialized.slice(0, 66), serialized.slice(66)) - } - - address = (type: AddressType = AddressType.Receiving, index: number, isMainnet = false): Address => { - return Address.fromPublicKey(this.addressPublicKey(type, index), Address.pathFor(type, index), isMainnet) - } - - private addressPublicKey = (type = AddressType.Receiving, index: number) => { - const keychain = Keychain.fromPublicKey( - Buffer.from(this.publicKey, 'hex'), - Buffer.from(this.chainCode, 'hex'), - AccountExtendedPublicKey.ckbAccountPath - ) - .deriveChild(type, false) - .deriveChild(index, false) - - return keychain.publicKey.toString('hex') - } -} - -export class ExtendedPrivateKey { - privateKey: string - chainCode: string - - constructor(privateKey: string, chainCode: string) { - this.privateKey = privateKey - this.chainCode = chainCode - } - - serialize = () => { - return this.privateKey + this.chainCode - } - - toExtendedPublicKey = (): ExtendedPublicKey => { - const publicKey = privateToPublic(Buffer.from(this.privateKey, 'hex')).toString('hex') - return new ExtendedPublicKey(publicKey, this.chainCode) - } - - static parse = (serialized: string) => { - return new ExtendedPrivateKey(serialized.slice(0, 64), serialized.slice(64)) - } -} diff --git a/packages/neuron-wallet/src/services/addresses.ts b/packages/neuron-wallet/src/services/addresses.ts index f71ba1886c..550ba2977a 100644 --- a/packages/neuron-wallet/src/services/addresses.ts +++ b/packages/neuron-wallet/src/services/addresses.ts @@ -1,6 +1,6 @@ -import { AccountExtendedPublicKey } from '../models/keys/key' +import { AccountExtendedPublicKey } from '@ckb-lumos/hd' import { AddressType } from '@ckb-lumos/hd' -import Address, { publicKeyToAddress, DefaultAddressNumber } from '../models/keys/address' +import { publicKeyToAddress, DefaultAddressNumber } from '../models/keys/address' import { Address as AddressInterface } from '../models/address' import AddressCreatedSubject from '../models/subjects/address-created-subject' import NetworksService from '../services/networks' @@ -261,25 +261,21 @@ export default class AddressService { } private static toAddress = (addressMetaInfo: AddressMetaInfo): AddressInterface => { - const path: string = Address.pathFor(addressMetaInfo.addressType, addressMetaInfo.addressIndex) - const address: string = addressMetaInfo.accountExtendedPublicKey.address( + const info = addressMetaInfo.accountExtendedPublicKey.publicKeyInfo( addressMetaInfo.addressType, - addressMetaInfo.addressIndex, - NetworksService.getInstance().isMainnet() - ).address - - const blake160: string = AddressParser.toBlake160(address) + addressMetaInfo.addressIndex + ) - const addressInfo: AddressInterface = { + const address: AddressInterface = { walletId: addressMetaInfo.walletId, - address, - path, + address: publicKeyToAddress(info.publicKey, NetworksService.getInstance().isMainnet()), + path: info.path, addressType: addressMetaInfo.addressType, addressIndex: addressMetaInfo.addressIndex, - blake160, + blake160: info.blake160, } - return addressInfo + return address } private static async maxAddressIndex(walletId: string, addressType: AddressType): Promise { diff --git a/packages/neuron-wallet/src/services/hardware/hardware.ts b/packages/neuron-wallet/src/services/hardware/hardware.ts index 20af74e74c..9d28825752 100644 --- a/packages/neuron-wallet/src/services/hardware/hardware.ts +++ b/packages/neuron-wallet/src/services/hardware/hardware.ts @@ -7,7 +7,7 @@ import Multisig from '../../models/multisig' import WalletService from '../../services/wallets' import DeviceSignIndexSubject from '../../models/subjects/device-sign-index-subject' import type { DeviceInfo, ExtendedPublicKey, PublicKey } from './common' -import { AccountExtendedPublicKey } from '../../models/keys/key' +import { AccountExtendedPublicKey } from '@ckb-lumos/hd' import AssetAccountInfo from '../../models/asset-account-info' export abstract class Hardware { diff --git a/packages/neuron-wallet/src/services/transaction-sender.ts b/packages/neuron-wallet/src/services/transaction-sender.ts index b540b347e4..9c4c788a6f 100644 --- a/packages/neuron-wallet/src/services/transaction-sender.ts +++ b/packages/neuron-wallet/src/services/transaction-sender.ts @@ -4,7 +4,6 @@ import { TargetOutput, TransactionGenerator, TransactionPersistor } from './tx' import AddressService from './addresses' import WalletService, { Wallet } from '../services/wallets' import RpcService from '../services/rpc-service' -import { PathAndPrivateKey } from '../models/keys/key' import { Address } from '../models/address' import FeeMode from '../models/fee-mode' import TransactionSize from '../models/transaction-size' @@ -54,6 +53,11 @@ interface SignInfo { lockArgs: string } +interface PathAndPrivateKey { + path: string + privateKey: string +} + export default class TransactionSender { static MULTI_SIGN_ARGS_LENGTH = 58 diff --git a/packages/neuron-wallet/src/services/wallets.ts b/packages/neuron-wallet/src/services/wallets.ts index bd88922384..94076ce3ea 100644 --- a/packages/neuron-wallet/src/services/wallets.ts +++ b/packages/neuron-wallet/src/services/wallets.ts @@ -1,10 +1,9 @@ import { v4 as uuid } from 'uuid' import { WalletNotFound, IsRequired, UsedName, WalletFunctionNotSupported, DuplicateImportWallet } from '../exceptions' import Store from '../models/store' -import { Keystore } from '@ckb-lumos/hd' +import { Keystore, AccountExtendedPublicKey } from '@ckb-lumos/hd' import WalletDeletedSubject from '../models/subjects/wallet-deleted-subject' import { WalletListSubject, CurrentWalletSubject } from '../models/subjects/wallets' -import { AccountExtendedPublicKey } from '../models/keys/key' import { DefaultAddressNumber } from '../models/keys/address' import { Address as AddressInterface } from '../models/address' @@ -18,6 +17,7 @@ import NetworksService from './networks' import { NetworkType } from '../models/network' import { resetSyncTaskQueue } from '../block-sync-renderer' import SyncProgressService from './sync-progress' +import { Ox } from '../utils/scriptAndAddress' const fileService = FileService.getInstance() @@ -57,7 +57,7 @@ export abstract class Wallet { this.id = id this.name = name - this.extendedKey = extendedKey + this.extendedKey = Ox(extendedKey) this.device = device this.isHD = isHDWallet ?? true this.startBlockNumber = startBlockNumber @@ -150,7 +150,7 @@ export class FileKeystoreWallet extends Wallet { } accountExtendedPublicKey = (): AccountExtendedPublicKey => { - return AccountExtendedPublicKey.parse(this.extendedKey) as AccountExtendedPublicKey + return AccountExtendedPublicKey.parse(this.extendedKey) } public toJSON = () => { @@ -236,7 +236,7 @@ export class HardwareWallet extends Wallet { } accountExtendedPublicKey = (): AccountExtendedPublicKey => { - return AccountExtendedPublicKey.parse(this.extendedKey) as AccountExtendedPublicKey + return AccountExtendedPublicKey.parse(this.extendedKey) } static fromJSON = (json: WalletProperties) => { @@ -390,7 +390,7 @@ export default class WalletService { if (!props) { throw new IsRequired('wallet property') } - + props = { ...props, extendedKey: Ox(props.extendedKey) } const index = this.getAll().findIndex(wallet => wallet.name === props.name) if (index !== -1) { diff --git a/packages/neuron-wallet/src/utils/scriptAndAddress.ts b/packages/neuron-wallet/src/utils/scriptAndAddress.ts index a744ebe29f..dd75ee49e5 100644 --- a/packages/neuron-wallet/src/utils/scriptAndAddress.ts +++ b/packages/neuron-wallet/src/utils/scriptAndAddress.ts @@ -2,6 +2,8 @@ import { Script } from '@ckb-lumos/base' import { predefined } from '@ckb-lumos/config-manager' import { encodeToAddress, parseAddress } from '@ckb-lumos/helpers' +export const Ox = (hex: string) => (hex.startsWith('0x') ? hex : `0x${hex}`) + export const scriptToAddress = (script: CKBComponents.Script, isMainnet = true): string => { const lumosConfig = !isMainnet ? predefined.AGGRON4 : predefined.LINA return encodeToAddress( diff --git a/packages/neuron-wallet/tests/models/keys/key.test.ts b/packages/neuron-wallet/tests/models/keys/key.test.ts deleted file mode 100644 index db9d3a889a..0000000000 --- a/packages/neuron-wallet/tests/models/keys/key.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { ExtendedPublicKey, AccountExtendedPublicKey, ExtendedPrivateKey } from '../../../src/models/keys/key' -import { AddressType } from '@ckb-lumos/hd' - -const fixture = { - privateKey: 'e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35', - publicKey: '0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2', - chainCode: '873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508', -} - -describe('extended public key', () => { - it('serialize and parse', () => { - const extendedKey = new ExtendedPublicKey(fixture.publicKey, fixture.chainCode) - const serialized = extendedKey.serialize() - const parsed = ExtendedPublicKey.parse(serialized) - expect(parsed.publicKey).toEqual(fixture.publicKey) - expect(parsed.chainCode).toEqual(fixture.chainCode) - }) -}) - -describe('account extended public key', () => { - const extendedKey = new AccountExtendedPublicKey( - '03e5b310636a0f6e7dcdfffa98f28d7ed70df858bb47acf13db830bfde3510b3f3', - '37e85a19f54f0a242a35599abac64a71aacc21e3a5860dd024377ffc7e6827d8' - ) - - it('key from extended public key', () => { - // @ts-ignore: Private method - expect(extendedKey.addressPublicKey(AddressType.Receiving, 0)).toEqual( - '0331b3c0225388c5010e3507beb28ecf409c022ef6f358f02b139cbae082f5a2a3' - ) - // @ts-ignore: Private method - expect(extendedKey.addressPublicKey(AddressType.Change, 1)).toEqual( - '0360bf05c11e7b4ac8de58077554e3d777acd64bf4abb9cd947002eb98a4827bba' - ) - }) - - it('serialize and parse', () => { - const serialized = extendedKey.serialize() - const parsed = AccountExtendedPublicKey.parse(serialized) - expect(parsed.publicKey).toEqual(extendedKey.publicKey) - expect(parsed.chainCode).toEqual(extendedKey.chainCode) - }) - - it('derive address', () => { - const receivingAddress = extendedKey.address(AddressType.Receiving, 0) - expect(receivingAddress.path).toEqual(`m/44'/309'/0'/0/0`) - - const changeAddress = extendedKey.address(AddressType.Change, 1) - expect(changeAddress.path).toEqual(`m/44'/309'/0'/1/1`) - }) -}) - -describe('extended private key', () => { - it('serialize and parse', () => { - const extendedKey = new ExtendedPrivateKey(fixture.privateKey, fixture.chainCode) - const serialized = extendedKey.serialize() - const parsed = ExtendedPrivateKey.parse(serialized) - expect(parsed.privateKey).toEqual(fixture.privateKey) - expect(parsed.chainCode).toEqual(fixture.chainCode) - }) - - it('derivative extended public key', () => { - const extendedKey = new ExtendedPrivateKey(fixture.privateKey, fixture.chainCode).toExtendedPublicKey() - expect(extendedKey.publicKey).toEqual(fixture.publicKey) - expect(extendedKey.chainCode).toEqual(fixture.chainCode) - }) -}) diff --git a/packages/neuron-wallet/tests/services/address.test.ts b/packages/neuron-wallet/tests/services/address.test.ts index c4e9f46769..c2b09c39e7 100644 --- a/packages/neuron-wallet/tests/services/address.test.ts +++ b/packages/neuron-wallet/tests/services/address.test.ts @@ -1,12 +1,10 @@ -import { AccountExtendedPublicKey } from '../../src/models/keys/key' import SystemScriptInfo from '../../src/models/system-script-info' import { OutputStatus } from '../../src/models/chain/output' import OutputEntity from '../../src/database/chain/entities/output' -import { AddressType } from '@ckb-lumos/hd' +import { AddressType, AccountExtendedPublicKey } from '@ckb-lumos/hd' import { Address } from '../../src/models/address' import Transaction from '../../src/database/chain/entities/transaction' import { TransactionStatus } from '../../src/models/chain/transaction' -import AddressParser from '../../src/models/address-parser' import { when } from 'jest-when' import HdPublicKeyInfo from '../../src/database/chain/entities/hd-public-key-info' import { closeConnection, getConnection, initConnection } from '../setupAndTeardown' @@ -14,8 +12,8 @@ import { NetworkType } from '../../src/models/network' const walletId = '1' const extendedKey = new AccountExtendedPublicKey( - '03e5b310636a0f6e7dcdfffa98f28d7ed70df858bb47acf13db830bfde3510b3f3', - '37e85a19f54f0a242a35599abac64a71aacc21e3a5860dd024377ffc7e6827d8' + '0x03e5b310636a0f6e7dcdfffa98f28d7ed70df858bb47acf13db830bfde3510b3f3', + '0x37e85a19f54f0a242a35599abac64a71aacc21e3a5860dd024377ffc7e6827d8' ) const preloadedPublicKeys: any = [] @@ -95,21 +93,21 @@ describe('integration tests for AddressService', () => { beforeAll(() => { for (let addressType = 0; addressType <= 1; addressType++) { for (let addressIndex = 0; addressIndex <= 7; addressIndex++) { - const address = extendedKey.address(addressType, addressIndex, true) + const publicKeyInfo = extendedKey.publicKeyInfo(addressType, addressIndex) preloadedPublicKeys.push({ - address, addressType, addressIndex, - publicKeyHash: AddressParser.toBlake160(address.address), + publicKeyInfo, + publicKeyHash: publicKeyInfo.blake160, }) } } - const stubbedExtendedKeyAddressFn = when(jest.spyOn(extendedKey, 'address')) + const stubbedExtendedPublicKeyInfoFn = when(jest.spyOn(extendedKey, 'publicKeyInfo')) for (const addressToMock of preloadedPublicKeys) { - stubbedExtendedKeyAddressFn - .calledWith(addressToMock.addressType, addressToMock.addressIndex, true) - .mockReturnValue(addressToMock.address) + stubbedExtendedPublicKeyInfoFn + .calledWith(addressToMock.addressType, addressToMock.addressIndex) + .mockReturnValue(addressToMock.publicKeyInfo) } }) diff --git a/packages/neuron-wallet/tests/services/tx-wallet.test.ts b/packages/neuron-wallet/tests/services/tx-wallet.test.ts index 7a1b7576a5..74f2b7b274 100644 --- a/packages/neuron-wallet/tests/services/tx-wallet.test.ts +++ b/packages/neuron-wallet/tests/services/tx-wallet.test.ts @@ -1,7 +1,6 @@ import WalletService from '../../src/services/wallets' -import { Keychain, Keystore, ExtendedPrivateKey } from '@ckb-lumos/hd' +import { Keychain, Keystore, ExtendedPrivateKey, AccountExtendedPublicKey } from '@ckb-lumos/hd' import { mnemonicToSeedSync } from '@ckb-lumos/hd/lib/mnemonic' -import { AccountExtendedPublicKey } from '../../src/models/keys/key' import TransactionSender from '../../src/services/transaction-sender' import { signWitnesses } from '../../src/utils/signWitnesses' @@ -53,8 +52,8 @@ describe('get keys with paths', () => { const accountKeychain = masterKeychain.derivePath(AccountExtendedPublicKey.ckbAccountPath) const accountExtendedPublicKey = new AccountExtendedPublicKey( - accountKeychain.publicKey.toString('hex'), - accountKeychain.chainCode.toString('hex') + `0x${accountKeychain.publicKey.toString('hex')}`, + `0x${accountKeychain.chainCode.toString('hex')}` ) const wallet = walletService.create({ diff --git a/packages/neuron-wallet/tests/services/wallets.test.ts b/packages/neuron-wallet/tests/services/wallets.test.ts index 0009709fd4..0ee3c07a73 100644 --- a/packages/neuron-wallet/tests/services/wallets.test.ts +++ b/packages/neuron-wallet/tests/services/wallets.test.ts @@ -1,7 +1,8 @@ import { when } from 'jest-when' import { WalletFunctionNotSupported, DuplicateImportWallet } from '../../src/exceptions/wallet' -import { AddressType, Keystore } from '@ckb-lumos/hd' +import { AddressType, Keystore, AccountExtendedPublicKey } from '@ckb-lumos/hd' import { Manufacturer } from '../../src/services/hardware/common' +import { Ox } from '../../src/utils/scriptAndAddress' const stubbedDeletedByWalletIdFn = jest.fn() const stubbedGenerateAndSaveForExtendedKeyQueue = jest.fn() @@ -31,7 +32,6 @@ jest.doMock('../../src/services/addresses', () => { } }) import WalletService, { WalletProperties, Wallet } from '../../src/services/wallets' -import { AccountExtendedPublicKey } from '../../src/models/keys/key' import HdPublicKeyInfo from '../../src/database/chain/entities/hd-public-key-info' import { closeConnection, getConnection, initConnection } from '../setupAndTeardown' @@ -53,8 +53,8 @@ describe('wallet service', () => { let wallet3: WalletProperties let wallet4: WalletProperties let wallet5: WalletProperties - const fakePublicKey = 'keykeykeykeykeykeykeykeykeykeykeykeykeykeykeykeykeykeykeykeykeykey' - const fakeChainCode = 'codecodecodecodecodecodecodecodecodecodecodecodecodecodecodecode' + const fakePublicKey = 'abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc' + const fakeChainCode = '1234123412341234123412341234123412341234123412341234123412341234' beforeAll(async () => { await initConnection() @@ -98,7 +98,7 @@ describe('wallet service', () => { wallet2 = { name: 'wallet-test2', id: '', - extendedKey: 'a', + extendedKey: 'b'.repeat(66) + '2'.repeat(64), keystore: new Keystore( { cipher: 'wallet2', @@ -121,7 +121,7 @@ describe('wallet service', () => { wallet3 = { name: 'wallet-test3', id: '', - extendedKey: 'b', + extendedKey: 'c'.repeat(66) + '3'.repeat(64), keystore: new Keystore( { cipher: 'wallet3', @@ -144,7 +144,7 @@ describe('wallet service', () => { wallet4 = { name: 'wallet-test4', id: '', - extendedKey: 'a'.repeat(66) + 'b'.repeat(64), + extendedKey: Ox('a'.repeat(66) + 'b'.repeat(64)), device: { manufacturer: Manufacturer.Ledger, product: 'Nano S', @@ -159,7 +159,7 @@ describe('wallet service', () => { wallet5 = { name: 'wallet-test5', id: '', - extendedKey: 'a', + extendedKey: 'b'.repeat(66) + '2'.repeat(64), keystore: new Keystore( { cipher: 'wallet5', @@ -208,8 +208,8 @@ describe('wallet service', () => { it('returns xpubkey', () => { const wallet = walletService.get(createdWallet.id) const extendedPublicKey = wallet.accountExtendedPublicKey() - expect(extendedPublicKey.publicKey).toEqual(fakePublicKey) - expect(extendedPublicKey.chainCode).toEqual(fakeChainCode) + expect(extendedPublicKey.publicKey).toEqual(Ox(fakePublicKey)) + expect(extendedPublicKey.chainCode).toEqual(Ox(fakeChainCode)) }) }) describe('#getDeviceInfo', () => { @@ -440,14 +440,14 @@ describe('wallet service', () => { it('generates addresses for wallets not having addresses', () => { expect(stubbedGenerateAndSaveForExtendedKeyQueue).toHaveBeenCalledWith({ walletId: createdWallet2.id, - extendedKey: expect.objectContaining({ publicKey: 'a' }), + extendedKey: expect.objectContaining({ publicKey: Ox('b'.repeat(66)) }), isImporting: false, receivingAddressCount: 20, changeAddressCount: 10, }) expect(stubbedGenerateAndSaveForExtendedKeyQueue).toHaveBeenCalledWith({ walletId: createdWallet3.id, - extendedKey: expect.objectContaining({ publicKey: 'b' }), + extendedKey: expect.objectContaining({ publicKey: Ox('c'.repeat(66)) }), isImporting: false, receivingAddressCount: 20, changeAddressCount: 10, @@ -527,7 +527,7 @@ describe('wallet service', () => { } catch (error) { const { extendedKey, id } = JSON.parse(error.message) await walletService.replace(createdWallet2.id, id) - expect(extendedKey).toBe('a') + expect(extendedKey).toBe(Ox('b'.repeat(66) + '2'.repeat(64))) expect(() => walletService.get(createdWallet2.id)).toThrowError() expect(walletService.get(id).name).toBe(wallet5.name) } From 562ff4c2b1a9d4552d299921eada6c668628bc88 Mon Sep 17 00:00:00 2001 From: Tom Wang Date: Wed, 15 May 2024 13:44:44 +0800 Subject: [PATCH 5/7] refactor: replace models/keys/address with lumos hd --- .../neuron-wallet/src/models/keys/address.ts | 50 ------------------- .../src/models/keys/hd-public-key-info.ts | 5 +- .../neuron-wallet/src/services/addresses.ts | 5 +- .../src/services/hardware/ledger.ts | 9 ++-- .../neuron-wallet/src/services/wallets.ts | 2 +- .../src/utils/scriptAndAddress.ts | 21 +++++++- .../tests/models/keys/address.test.ts | 42 ---------------- 7 files changed, 29 insertions(+), 105 deletions(-) delete mode 100644 packages/neuron-wallet/src/models/keys/address.ts delete mode 100644 packages/neuron-wallet/tests/models/keys/address.test.ts diff --git a/packages/neuron-wallet/src/models/keys/address.ts b/packages/neuron-wallet/src/models/keys/address.ts deleted file mode 100644 index 747e49b973..0000000000 --- a/packages/neuron-wallet/src/models/keys/address.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { scriptToAddress } from '../../utils/scriptAndAddress' -import { systemScripts } from '../../utils/systemScripts' -import { key, AddressType, AccountExtendedPublicKey } from '@ckb-lumos/hd' - -export enum DefaultAddressNumber { - Receiving = 20, - Change = 10, -} - -export const publicKeyToAddress = (publicKey: string, isMainnet = false) => { - const pubkey = publicKey.startsWith('0x') ? publicKey : `0x${publicKey}` - return scriptToAddress( - { - codeHash: systemScripts.SECP256K1_BLAKE160.CODE_HASH, - hashType: systemScripts.SECP256K1_BLAKE160.HASH_TYPE, - args: key.publicKeyToBlake160(pubkey), - }, - isMainnet - ) -} - -export default class Address { - publicKey?: string - address: string - path: string // BIP44 path - - constructor(address: string, path: string = Address.pathForReceiving(0)) { - this.address = address - this.path = path - } - - public static fromPublicKey = (publicKey: string, path: string, isMainnet = false) => { - const address = publicKeyToAddress(publicKey, isMainnet) - const instance = new Address(address, path) - instance.publicKey = publicKey - return instance - } - - public static pathFor = (type: AddressType, index: number) => { - return `${AccountExtendedPublicKey.ckbAccountPath}/${type}/${index}` - } - - public static pathForReceiving = (index: number) => { - return Address.pathFor(AddressType.Receiving, index) - } - - public static pathForChange = (index: number) => { - return Address.pathFor(AddressType.Change, index) - } -} diff --git a/packages/neuron-wallet/src/models/keys/hd-public-key-info.ts b/packages/neuron-wallet/src/models/keys/hd-public-key-info.ts index 49bc9845d2..86075d9589 100644 --- a/packages/neuron-wallet/src/models/keys/hd-public-key-info.ts +++ b/packages/neuron-wallet/src/models/keys/hd-public-key-info.ts @@ -1,8 +1,7 @@ +import { AddressType, AccountExtendedPublicKey } from '@ckb-lumos/hd' import { scriptToAddress } from '../../utils/scriptAndAddress' import SystemScriptInfo from '../../models/system-script-info' import NetworksService from '../../services/networks' -import { AddressType } from '@ckb-lumos/hd' -import Address from './address' export default class HdPublicKeyInfoModel { public walletId: string @@ -23,7 +22,7 @@ export default class HdPublicKeyInfoModel { } public get path(): string { - return Address.pathFor(this.addressType, this.addressIndex) + return AccountExtendedPublicKey.pathFor(this.addressType, this.addressIndex) } constructor( diff --git a/packages/neuron-wallet/src/services/addresses.ts b/packages/neuron-wallet/src/services/addresses.ts index 550ba2977a..6f7f75b98c 100644 --- a/packages/neuron-wallet/src/services/addresses.ts +++ b/packages/neuron-wallet/src/services/addresses.ts @@ -1,6 +1,5 @@ -import { AccountExtendedPublicKey } from '@ckb-lumos/hd' -import { AddressType } from '@ckb-lumos/hd' -import { publicKeyToAddress, DefaultAddressNumber } from '../models/keys/address' +import { AddressType, AccountExtendedPublicKey } from '@ckb-lumos/hd' +import { publicKeyToAddress, DefaultAddressNumber } from '../utils/scriptAndAddress' import { Address as AddressInterface } from '../models/address' import AddressCreatedSubject from '../models/subjects/address-created-subject' import NetworksService from '../services/networks' diff --git a/packages/neuron-wallet/src/services/hardware/ledger.ts b/packages/neuron-wallet/src/services/hardware/ledger.ts index 877851ed9e..a3f6fca5eb 100644 --- a/packages/neuron-wallet/src/services/hardware/ledger.ts +++ b/packages/neuron-wallet/src/services/hardware/ledger.ts @@ -7,8 +7,7 @@ import type Transport from '@ledgerhq/hw-transport' import { Observable, timer } from 'rxjs' import { takeUntil, filter, scan } from 'rxjs/operators' import Transaction from '../../models/chain/transaction' -import { AddressType } from '@ckb-lumos/hd' -import Address from '../../models/keys/address' +import { AddressType, AccountExtendedPublicKey } from '@ckb-lumos/hd' import logger from '../../utils/logger' import NetworksService from '../../services/networks' import { generateRPC } from '../../utils/ckb-rpc' @@ -65,7 +64,7 @@ export default class Ledger extends Hardware { } const signature = await this.ledgerCKB!.signTransaction( - path === Address.pathForReceiving(0) ? this.defaultPath : path, + path === AccountExtendedPublicKey.pathForReceiving(0) ? this.defaultPath : path, rawTx, witnesses, context, @@ -78,7 +77,7 @@ export default class Ledger extends Hardware { async signMessage(path: string, messageHex: string) { const message = this.removePrefix(messageHex) const signed = await this.ledgerCKB!.signMessage( - path === Address.pathForReceiving(0) ? this.defaultPath : path, + path === AccountExtendedPublicKey.pathForReceiving(0) ? this.defaultPath : path, message, false ) @@ -104,7 +103,7 @@ export default class Ledger extends Hardware { const networkService = NetworksService.getInstance() const isTestnet = !networkService.isMainnet() const result = await this.ledgerCKB!.getWalletPublicKey( - path === Address.pathForReceiving(0) ? this.defaultPath : path, + path === AccountExtendedPublicKey.pathForReceiving(0) ? this.defaultPath : path, isTestnet ) return result diff --git a/packages/neuron-wallet/src/services/wallets.ts b/packages/neuron-wallet/src/services/wallets.ts index 94076ce3ea..9edcb28398 100644 --- a/packages/neuron-wallet/src/services/wallets.ts +++ b/packages/neuron-wallet/src/services/wallets.ts @@ -4,7 +4,7 @@ import Store from '../models/store' import { Keystore, AccountExtendedPublicKey } from '@ckb-lumos/hd' import WalletDeletedSubject from '../models/subjects/wallet-deleted-subject' import { WalletListSubject, CurrentWalletSubject } from '../models/subjects/wallets' -import { DefaultAddressNumber } from '../models/keys/address' +import { DefaultAddressNumber } from '../utils/scriptAndAddress' import { Address as AddressInterface } from '../models/address' import FileService from './file' diff --git a/packages/neuron-wallet/src/utils/scriptAndAddress.ts b/packages/neuron-wallet/src/utils/scriptAndAddress.ts index dd75ee49e5..9ca83db68d 100644 --- a/packages/neuron-wallet/src/utils/scriptAndAddress.ts +++ b/packages/neuron-wallet/src/utils/scriptAndAddress.ts @@ -1,9 +1,28 @@ -import { Script } from '@ckb-lumos/base' +import { key } from '@ckb-lumos/hd' +import { type Script } from '@ckb-lumos/base' import { predefined } from '@ckb-lumos/config-manager' import { encodeToAddress, parseAddress } from '@ckb-lumos/helpers' +import { systemScripts } from './systemScripts' + +export enum DefaultAddressNumber { + Change = 10, + Receiving = 20, +} export const Ox = (hex: string) => (hex.startsWith('0x') ? hex : `0x${hex}`) +export const publicKeyToAddress = (publicKey: string, isMainnet = false) => { + const pubkey = publicKey.startsWith('0x') ? publicKey : `0x${publicKey}` + return scriptToAddress( + { + codeHash: systemScripts.SECP256K1_BLAKE160.CODE_HASH, + hashType: systemScripts.SECP256K1_BLAKE160.HASH_TYPE, + args: key.publicKeyToBlake160(pubkey), + }, + isMainnet + ) +} + export const scriptToAddress = (script: CKBComponents.Script, isMainnet = true): string => { const lumosConfig = !isMainnet ? predefined.AGGRON4 : predefined.LINA return encodeToAddress( diff --git a/packages/neuron-wallet/tests/models/keys/address.test.ts b/packages/neuron-wallet/tests/models/keys/address.test.ts deleted file mode 100644 index 7d8b71ac51..0000000000 --- a/packages/neuron-wallet/tests/models/keys/address.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { AddressType } from '@ckb-lumos/hd' -import Address, { publicKeyToAddress } from '../../../src/models/keys/address' - -describe('address', () => { - it('path from index', () => { - expect(Address.pathFor(AddressType.Receiving, 0)).toEqual(`m/44'/309'/0'/0/0`) - expect(Address.pathFor(AddressType.Receiving, 1)).toEqual(`m/44'/309'/0'/0/1`) - expect(Address.pathFor(AddressType.Change, 0)).toEqual(`m/44'/309'/0'/1/0`) - expect(Address.pathFor(AddressType.Change, 1)).toEqual(`m/44'/309'/0'/1/1`) - - expect(Address.pathForReceiving(0)).toEqual(`m/44'/309'/0'/0/0`) - expect(Address.pathForReceiving(1)).toEqual(`m/44'/309'/0'/0/1`) - expect(Address.pathForChange(0)).toEqual(`m/44'/309'/0'/1/0`) - expect(Address.pathForChange(1)).toEqual(`m/44'/309'/0'/1/1`) - }) - - it('from public key', () => { - const publicKey = '0x024a501efd328e062c8675f2365970728c859c592beeefd6be8ead3d901330bc01' - const path = `m/44'/309'/0'/0/0` - const address = Address.fromPublicKey(publicKey, `m/44'/309'/0'/0/0`) - expect(address.address).toEqual( - 'ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqfkcv576ccddnn4quf2ga65xee2m26h7nq4sds0r' - ) - expect(address.path).toEqual(path) - }) - - it('Generate testnet address from public key', () => { - const publicKey = '0x024a501efd328e062c8675f2365970728c859c592beeefd6be8ead3d901330bc01' - const address = publicKeyToAddress(publicKey) - expect(address).toEqual( - 'ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqfkcv576ccddnn4quf2ga65xee2m26h7nq4sds0r' - ) - }) - - it('Generate mainnet address from public key', () => { - const publicKey = '0x024a501efd328e062c8675f2365970728c859c592beeefd6be8ead3d901330bc01' - const address = publicKeyToAddress(publicKey, true) - expect(address).toEqual( - 'ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqfkcv576ccddnn4quf2ga65xee2m26h7nqmzxl9m' - ) - }) -}) From 32e913d69d491fe3353d201e3dfb317822d75773 Mon Sep 17 00:00:00 2001 From: Tom Wang Date: Wed, 15 May 2024 16:40:45 +0800 Subject: [PATCH 6/7] refactor: rename Ox() to prefixWith0x() --- .../neuron-wallet/src/controllers/wallets.ts | 16 ++++++++-------- packages/neuron-wallet/src/services/wallets.ts | 6 +++--- .../neuron-wallet/src/utils/scriptAndAddress.ts | 5 ++--- .../neuron-wallet/tests/services/wallets.test.ts | 14 +++++++------- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/packages/neuron-wallet/src/controllers/wallets.ts b/packages/neuron-wallet/src/controllers/wallets.ts index 459464fb34..81a04b5a18 100644 --- a/packages/neuron-wallet/src/controllers/wallets.ts +++ b/packages/neuron-wallet/src/controllers/wallets.ts @@ -1,6 +1,6 @@ import fs from 'fs' import { t } from 'i18next' -import { Ox } from '../utils/scriptAndAddress' +import { prefixWith0x } from '../utils/scriptAndAddress' import { dialog, SaveDialogReturnValue, BrowserWindow, OpenDialogReturnValue } from 'electron' import WalletsService, { Wallet, WalletProperties, FileKeystoreWallet } from '../services/wallets' import NetworksService from '../services/networks' @@ -105,15 +105,15 @@ export default class WalletsController { throw new InvalidMnemonic() } const extendedKey = new ExtendedPrivateKey( - Ox(masterKeychain.privateKey.toString('hex')), - Ox(masterKeychain.chainCode.toString('hex')) + prefixWith0x(masterKeychain.privateKey.toString('hex')), + prefixWith0x(masterKeychain.chainCode.toString('hex')) ) const keystore = Keystore.create(extendedKey, password) const accountKeychain = masterKeychain.derivePath(AccountExtendedPublicKey.ckbAccountPath) const accountExtendedPublicKey = new AccountExtendedPublicKey( - Ox(accountKeychain.publicKey.toString('hex')), - Ox(accountKeychain.chainCode.toString('hex')) + prefixWith0x(accountKeychain.publicKey.toString('hex')), + prefixWith0x(accountKeychain.chainCode.toString('hex')) ) const walletsService = WalletsService.getInstance() @@ -172,8 +172,8 @@ export default class WalletsController { ) const accountKeychain = masterKeychain.derivePath(AccountExtendedPublicKey.ckbAccountPath) const accountExtendedPublicKey = new AccountExtendedPublicKey( - Ox(accountKeychain.publicKey.toString('hex')), - Ox(accountKeychain.chainCode.toString('hex')) + prefixWith0x(accountKeychain.publicKey.toString('hex')), + prefixWith0x(accountKeychain.chainCode.toString('hex')) ) const walletsService = WalletsService.getInstance() @@ -272,7 +272,7 @@ export default class WalletsController { walletName, }: ExtendedPublicKey & { walletName: string }): Promise> { const device = HardwareWalletService.getInstance().getCurrent()! - const accountExtendedPublicKey = new AccountExtendedPublicKey(Ox(publicKey), Ox(chainCode)) + const accountExtendedPublicKey = new AccountExtendedPublicKey(prefixWith0x(publicKey), prefixWith0x(chainCode)) const walletsService = WalletsService.getInstance() const wallet = walletsService.create({ device: device.deviceInfo, diff --git a/packages/neuron-wallet/src/services/wallets.ts b/packages/neuron-wallet/src/services/wallets.ts index 9edcb28398..025bedd07f 100644 --- a/packages/neuron-wallet/src/services/wallets.ts +++ b/packages/neuron-wallet/src/services/wallets.ts @@ -17,7 +17,7 @@ import NetworksService from './networks' import { NetworkType } from '../models/network' import { resetSyncTaskQueue } from '../block-sync-renderer' import SyncProgressService from './sync-progress' -import { Ox } from '../utils/scriptAndAddress' +import { prefixWith0x } from '../utils/scriptAndAddress' const fileService = FileService.getInstance() @@ -57,7 +57,7 @@ export abstract class Wallet { this.id = id this.name = name - this.extendedKey = Ox(extendedKey) + this.extendedKey = prefixWith0x(extendedKey) this.device = device this.isHD = isHDWallet ?? true this.startBlockNumber = startBlockNumber @@ -390,7 +390,7 @@ export default class WalletService { if (!props) { throw new IsRequired('wallet property') } - props = { ...props, extendedKey: Ox(props.extendedKey) } + props = { ...props, extendedKey: prefixWith0x(props.extendedKey) } const index = this.getAll().findIndex(wallet => wallet.name === props.name) if (index !== -1) { diff --git a/packages/neuron-wallet/src/utils/scriptAndAddress.ts b/packages/neuron-wallet/src/utils/scriptAndAddress.ts index 9ca83db68d..a20fb27596 100644 --- a/packages/neuron-wallet/src/utils/scriptAndAddress.ts +++ b/packages/neuron-wallet/src/utils/scriptAndAddress.ts @@ -9,15 +9,14 @@ export enum DefaultAddressNumber { Receiving = 20, } -export const Ox = (hex: string) => (hex.startsWith('0x') ? hex : `0x${hex}`) +export const prefixWith0x = (hex: string) => (hex.startsWith('0x') ? hex : `0x${hex}`) export const publicKeyToAddress = (publicKey: string, isMainnet = false) => { - const pubkey = publicKey.startsWith('0x') ? publicKey : `0x${publicKey}` return scriptToAddress( { codeHash: systemScripts.SECP256K1_BLAKE160.CODE_HASH, hashType: systemScripts.SECP256K1_BLAKE160.HASH_TYPE, - args: key.publicKeyToBlake160(pubkey), + args: key.publicKeyToBlake160(prefixWith0x(publicKey)), }, isMainnet ) diff --git a/packages/neuron-wallet/tests/services/wallets.test.ts b/packages/neuron-wallet/tests/services/wallets.test.ts index 0ee3c07a73..5940e0c57a 100644 --- a/packages/neuron-wallet/tests/services/wallets.test.ts +++ b/packages/neuron-wallet/tests/services/wallets.test.ts @@ -2,7 +2,7 @@ import { when } from 'jest-when' import { WalletFunctionNotSupported, DuplicateImportWallet } from '../../src/exceptions/wallet' import { AddressType, Keystore, AccountExtendedPublicKey } from '@ckb-lumos/hd' import { Manufacturer } from '../../src/services/hardware/common' -import { Ox } from '../../src/utils/scriptAndAddress' +import { prefixWith0x } from '../../src/utils/scriptAndAddress' const stubbedDeletedByWalletIdFn = jest.fn() const stubbedGenerateAndSaveForExtendedKeyQueue = jest.fn() @@ -144,7 +144,7 @@ describe('wallet service', () => { wallet4 = { name: 'wallet-test4', id: '', - extendedKey: Ox('a'.repeat(66) + 'b'.repeat(64)), + extendedKey: '0x' + 'a'.repeat(66) + 'b'.repeat(64), device: { manufacturer: Manufacturer.Ledger, product: 'Nano S', @@ -208,8 +208,8 @@ describe('wallet service', () => { it('returns xpubkey', () => { const wallet = walletService.get(createdWallet.id) const extendedPublicKey = wallet.accountExtendedPublicKey() - expect(extendedPublicKey.publicKey).toEqual(Ox(fakePublicKey)) - expect(extendedPublicKey.chainCode).toEqual(Ox(fakeChainCode)) + expect(extendedPublicKey.publicKey).toEqual(prefixWith0x(fakePublicKey)) + expect(extendedPublicKey.chainCode).toEqual(prefixWith0x(fakeChainCode)) }) }) describe('#getDeviceInfo', () => { @@ -440,14 +440,14 @@ describe('wallet service', () => { it('generates addresses for wallets not having addresses', () => { expect(stubbedGenerateAndSaveForExtendedKeyQueue).toHaveBeenCalledWith({ walletId: createdWallet2.id, - extendedKey: expect.objectContaining({ publicKey: Ox('b'.repeat(66)) }), + extendedKey: expect.objectContaining({ publicKey: prefixWith0x('b'.repeat(66)) }), isImporting: false, receivingAddressCount: 20, changeAddressCount: 10, }) expect(stubbedGenerateAndSaveForExtendedKeyQueue).toHaveBeenCalledWith({ walletId: createdWallet3.id, - extendedKey: expect.objectContaining({ publicKey: Ox('c'.repeat(66)) }), + extendedKey: expect.objectContaining({ publicKey: prefixWith0x('c'.repeat(66)) }), isImporting: false, receivingAddressCount: 20, changeAddressCount: 10, @@ -527,7 +527,7 @@ describe('wallet service', () => { } catch (error) { const { extendedKey, id } = JSON.parse(error.message) await walletService.replace(createdWallet2.id, id) - expect(extendedKey).toBe(Ox('b'.repeat(66) + '2'.repeat(64))) + expect(extendedKey).toBe(prefixWith0x('b'.repeat(66) + '2'.repeat(64))) expect(() => walletService.get(createdWallet2.id)).toThrowError() expect(walletService.get(id).name).toBe(wallet5.name) } From bc59c26f0d224f5fb5baad3286ba568d34df78e6 Mon Sep 17 00:00:00 2001 From: Tom Wang Date: Wed, 15 May 2024 18:58:10 +0800 Subject: [PATCH 7/7] refactor: create Buffer / HexString with bytify / hexify --- packages/neuron-wallet/src/controllers/wallets.ts | 13 +++++++------ .../src/services/transaction-sender.ts | 12 ++++++------ .../tests/services/tx-wallet.test.ts | 15 ++++++++------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/packages/neuron-wallet/src/controllers/wallets.ts b/packages/neuron-wallet/src/controllers/wallets.ts index 81a04b5a18..29acc6fea2 100644 --- a/packages/neuron-wallet/src/controllers/wallets.ts +++ b/packages/neuron-wallet/src/controllers/wallets.ts @@ -4,6 +4,7 @@ import { prefixWith0x } from '../utils/scriptAndAddress' import { dialog, SaveDialogReturnValue, BrowserWindow, OpenDialogReturnValue } from 'electron' import WalletsService, { Wallet, WalletProperties, FileKeystoreWallet } from '../services/wallets' import NetworksService from '../services/networks' +import { bytes } from '@ckb-lumos/codec' import { Keychain, Keystore, ExtendedPrivateKey, AccountExtendedPublicKey } from '@ckb-lumos/hd' import { generateMnemonic, validateMnemonic, mnemonicToSeedSync } from '@ckb-lumos/hd/lib/mnemonic' import CommandSubject from '../models/subjects/command' @@ -105,15 +106,15 @@ export default class WalletsController { throw new InvalidMnemonic() } const extendedKey = new ExtendedPrivateKey( - prefixWith0x(masterKeychain.privateKey.toString('hex')), - prefixWith0x(masterKeychain.chainCode.toString('hex')) + bytes.hexify(masterKeychain.privateKey), + bytes.hexify(masterKeychain.chainCode) ) const keystore = Keystore.create(extendedKey, password) const accountKeychain = masterKeychain.derivePath(AccountExtendedPublicKey.ckbAccountPath) const accountExtendedPublicKey = new AccountExtendedPublicKey( - prefixWith0x(accountKeychain.publicKey.toString('hex')), - prefixWith0x(accountKeychain.chainCode.toString('hex')) + bytes.hexify(accountKeychain.publicKey), + bytes.hexify(accountKeychain.chainCode) ) const walletsService = WalletsService.getInstance() @@ -172,8 +173,8 @@ export default class WalletsController { ) const accountKeychain = masterKeychain.derivePath(AccountExtendedPublicKey.ckbAccountPath) const accountExtendedPublicKey = new AccountExtendedPublicKey( - prefixWith0x(accountKeychain.publicKey.toString('hex')), - prefixWith0x(accountKeychain.chainCode.toString('hex')) + bytes.hexify(accountKeychain.publicKey), + bytes.hexify(accountKeychain.chainCode) ) const walletsService = WalletsService.getInstance() diff --git a/packages/neuron-wallet/src/services/transaction-sender.ts b/packages/neuron-wallet/src/services/transaction-sender.ts index 9c4c788a6f..a0681e4673 100644 --- a/packages/neuron-wallet/src/services/transaction-sender.ts +++ b/packages/neuron-wallet/src/services/transaction-sender.ts @@ -18,7 +18,7 @@ import Multisig from '../models/multisig' import Blake2b from '../models/blake2b' import logger from '../utils/logger' import { signWitnesses } from '../utils/signWitnesses' -import { bytes as byteUtils, bytes, number } from '@ckb-lumos/codec' +import { bytes, number } from '@ckb-lumos/codec' import SystemScriptInfo from '../models/system-script-info' import AddressParser from '../models/address-parser' import HardwareWalletService from './hardware' @@ -414,7 +414,7 @@ export default class TransactionSender { lock: `0x` + serializedMultiSign.slice(2) + '0'.repeat(130 * m), }) const serializedEmptyWitness = serializeWitnessArgs(emptyWitness.toSDK()) - const serializedEmptyWitnessSize = byteUtils.bytify(serializedEmptyWitness).byteLength + const serializedEmptyWitnessSize = bytes.bytify(serializedEmptyWitness).byteLength const blake2b = new Blake2b() blake2b.update(txHash) blake2b.update(bytes.hexify(number.Uint64LE.pack(`0x${serializedEmptyWitnessSize.toString(16)}`))) @@ -422,7 +422,7 @@ export default class TransactionSender { restWitnesses.forEach(w => { const wit: string = typeof w === 'string' ? w : serializeWitnessArgs(w.toSDK()) - const byteLength = byteUtils.bytify(wit).byteLength + const byteLength = bytes.bytify(wit).byteLength blake2b.update(bytes.hexify(number.Uint64LE.pack(`0x${byteLength.toString(16)}`))) blake2b.update(wit) }) @@ -931,14 +931,14 @@ export default class TransactionSender { public getPrivateKeys = (wallet: Wallet, paths: string[], password: string): PathAndPrivateKey[] => { const masterPrivateKey = wallet.loadKeystore().extendedPrivateKey(password) const masterKeychain = new Keychain( - Buffer.from(masterPrivateKey.privateKey.slice(2), 'hex'), - Buffer.from(masterPrivateKey.chainCode.slice(2), 'hex') + Buffer.from(bytes.bytify(masterPrivateKey.privateKey)), + Buffer.from(bytes.bytify(masterPrivateKey.chainCode)) ) const uniquePaths = paths.filter((value, idx, a) => a.indexOf(value) === idx) return uniquePaths.map(path => ({ path, - privateKey: `0x${masterKeychain.derivePath(path).privateKey.toString('hex')}`, + privateKey: bytes.hexify(masterKeychain.derivePath(path).privateKey), })) } } diff --git a/packages/neuron-wallet/tests/services/tx-wallet.test.ts b/packages/neuron-wallet/tests/services/tx-wallet.test.ts index 74f2b7b274..66cde86d55 100644 --- a/packages/neuron-wallet/tests/services/tx-wallet.test.ts +++ b/packages/neuron-wallet/tests/services/tx-wallet.test.ts @@ -1,4 +1,5 @@ import WalletService from '../../src/services/wallets' +import { bytes } from '@ckb-lumos/codec' import { Keychain, Keystore, ExtendedPrivateKey, AccountExtendedPublicKey } from '@ckb-lumos/hd' import { mnemonicToSeedSync } from '@ckb-lumos/hd/lib/mnemonic' import TransactionSender from '../../src/services/transaction-sender' @@ -43,17 +44,17 @@ describe('get keys with paths', () => { const seed = mnemonicToSeedSync(mnemonic) const masterKeychain = Keychain.fromSeed(seed) const extendedKey = new ExtendedPrivateKey( - `0x${masterKeychain.privateKey.toString('hex')}`, - `0x${masterKeychain.chainCode.toString('hex')}` + bytes.hexify(masterKeychain.privateKey), + bytes.hexify(masterKeychain.chainCode) ) - const p = masterKeychain.derivePath(receivingPath).privateKey.toString('hex') - expect(`0x${p}`).toEqual(receivingPrivateKey) + const privateKey = bytes.hexify(masterKeychain.derivePath(receivingPath).privateKey) + expect(privateKey).toEqual(receivingPrivateKey) const keystore = Keystore.create(extendedKey, password) const accountKeychain = masterKeychain.derivePath(AccountExtendedPublicKey.ckbAccountPath) const accountExtendedPublicKey = new AccountExtendedPublicKey( - `0x${accountKeychain.publicKey.toString('hex')}`, - `0x${accountKeychain.chainCode.toString('hex')}` + bytes.hexify(accountKeychain.publicKey), + bytes.hexify(accountKeychain.chainCode) ) const wallet = walletService.create({ @@ -64,7 +65,7 @@ describe('get keys with paths', () => { }) const masterPrivateKey = wallet.loadKeystore().extendedPrivateKey(password) - expect(`0x${masterKeychain.privateKey.toString('hex')}`).toEqual(masterPrivateKey.privateKey) + expect(bytes.hexify(masterKeychain.privateKey)).toEqual(masterPrivateKey.privateKey) const pathsAndKeys = new TransactionSender().getPrivateKeys(wallet, [receivingPath, changePath], password) expect(pathsAndKeys[0]).toEqual({