diff --git a/package.json b/package.json index 7895c68..8a1d994 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@leapwallet/leap-keychain", - "version": "0.2.3-beta.1", + "version": "0.2.3-beta.2", "description": "A javascript library for crypto key management", "scripts": { "test": "jest", diff --git a/src/key/eth-wallet.ts b/src/key/eth-wallet.ts index 1bebb8c..343e1f3 100644 --- a/src/key/eth-wallet.ts +++ b/src/key/eth-wallet.ts @@ -13,6 +13,7 @@ import { bip39Token, getBip39 } from '../crypto/bip39/bip39-token'; import { SignDoc } from 'cosmjs-types/cosmos/tx/v1beta1/tx'; import { TransactionRequest, Provider } from '@ethersproject/abstract-provider'; import Container from 'typedi'; +import { pubkeyToAddress } from './wallet'; export class EthWallet { private constructor( @@ -72,13 +73,18 @@ export class EthWallet { this.walletType === 'mnemonic' ? HDNode.fromSeed(seed).derivePath(path) : new Wallet(this.pvtKey); const ethAddr = EthereumUtilsAddress.fromString(hdWallet.address).toBuffer(); - const bech32Address = bech32.encode(this.options.addressPrefix, bech32.toWords(ethAddr)); + const ethWallet = new Wallet(hdWallet.privateKey, this.provider); + const pubkey = fromHex(ethWallet._signingKey().compressedPublicKey.replace('0x', '')); + + const bech32Address = this.options.pubKeyBech32Address + ? pubkeyToAddress(this.options.addressPrefix, pubkey) + : bech32.encode(this.options.addressPrefix, bech32.toWords(ethAddr)); return { algo: 'ethsecp256k1', address: bech32Address, ethWallet: ethWallet, - pubkey: fromHex(ethWallet._signingKey().compressedPublicKey.replace('0x', '')), + pubkey, }; }); } diff --git a/src/key/wallet-utils.ts b/src/key/wallet-utils.ts index 6bd8375..b3d7101 100644 --- a/src/key/wallet-utils.ts +++ b/src/key/wallet-utils.ts @@ -7,16 +7,24 @@ import { bip39Token } from '../crypto/bip39/bip39-token'; export function generateWalletFromMnemonic( mnemonic: string, - hdPath: string, - addressPrefix: string, - ethWallet?: boolean, + { + hdPath, + addressPrefix, + ethWallet, + pubKeyBech32Address, + }: { + hdPath: string; + addressPrefix: string; + ethWallet: boolean; + pubKeyBech32Address?: boolean; + }, ) { const bip39 = Container.get(bip39Token); bip39.mnemonicToEntropy(mnemonic); const hdPathParams = hdPath.split('/'); const coinType = hdPathParams[2]; if (coinType?.replace("'", '') === '60' || ethWallet) { - return EthWallet.generateWalletFromMnemonic(mnemonic, { paths: [hdPath], addressPrefix }); + return EthWallet.generateWalletFromMnemonic(mnemonic, { paths: [hdPath], addressPrefix, pubKeyBech32Address }); } return Wallet.generateWallet(mnemonic, { paths: [hdPath], addressPrefix }); } diff --git a/src/keychain/keychain.ts b/src/keychain/keychain.ts index fbb17ef..af1cf33 100644 --- a/src/keychain/keychain.ts +++ b/src/keychain/keychain.ts @@ -206,9 +206,17 @@ export class KeyChain { public static async getSigner( walletId: string, password: string, - addressPrefix: string, - coinType: string, - ethWallet?: boolean, + { + addressPrefix, + coinType, + ethWallet, + pubKeyBech32Address, + }: { + addressPrefix: string; + coinType: string; + ethWallet?: boolean; + pubKeyBech32Address?: boolean; + }, ) { const storage = Container.get(storageToken); const keychain = (await storage.get(KEYCHAIN)) as unknown as Keystore; @@ -225,12 +233,12 @@ export class KeyChain { if (walletData.walletType === WALLETTYPE.PRIVATE_KEY) { if (coinType === '60' || ethWallet) { const hdPath = getHDPath(coinType, walletData.addressIndex.toString()); - return EthWallet.generateWalletFromPvtKey(secret, { paths: [hdPath], addressPrefix }); + return EthWallet.generateWalletFromPvtKey(secret, { paths: [hdPath], addressPrefix, pubKeyBech32Address }); } return PvtKeyWallet.generateWallet(secret, addressPrefix); } else { const hdPath = getHDPath(coinType, walletData.addressIndex.toString()); - return generateWalletFromMnemonic(secret, hdPath, addressPrefix, ethWallet); + return generateWalletFromMnemonic(secret, { hdPath, addressPrefix, ethWallet: !!ethWallet, pubKeyBech32Address }); } } @@ -286,11 +294,11 @@ export class KeyChain { const addresses: Record = {}; const pubKeys: Record = {}; for (const chainInfo of chainsData) { - const wallet = generateWalletFromMnemonic( - mnemonic, - getHDPath(chainInfo.coinType, addressIndex.toString()), - chainInfo.addressPrefix, - ); + const wallet = generateWalletFromMnemonic(mnemonic, { + hdPath: getHDPath(chainInfo.coinType, addressIndex.toString()), + addressPrefix: chainInfo.addressPrefix, + ethWallet: false, + }); const [account] = wallet.getAccounts(); if (account?.address && account?.pubkey) { diff --git a/src/types/wallet.ts b/src/types/wallet.ts index a8cc33f..abf1cb5 100644 --- a/src/types/wallet.ts +++ b/src/types/wallet.ts @@ -4,6 +4,7 @@ import { PvtKeyWallet, Wallet } from '../key/wallet'; export type WalletOptions = { paths: string[]; addressPrefix: string; + pubKeyBech32Address?: boolean; }; export type LeapSigner = EthWallet | Wallet | PvtKeyWallet; diff --git a/tests/wallet.test.ts b/tests/wallet.test.ts index 8b41091..0b54ee4 100644 --- a/tests/wallet.test.ts +++ b/tests/wallet.test.ts @@ -72,12 +72,20 @@ describe('generateMnemonic', () => { ).toThrow('Invalid private key'); }); test('generateWalletFromMnemonic', () => { - const wallet = generateWalletFromMnemonic(mnemonic, "m/44'/118'/0'/0/1", 'cosmos'); + const wallet = generateWalletFromMnemonic(mnemonic, { + hdPath: "m/44'/118'/0'/0/1", + addressPrefix: 'cosmos', + ethWallet: false, + }); const accounts = wallet.getAccounts(); expect(accounts[0]?.address).toBe(referenceWallets.ref2.addresses.cosmos); }); test('generateWalletFromMnemonic for cointype=60', () => { - const wallet = generateWalletFromMnemonic(mnemonic, "m/44'/60'/0'/0/1", 'evmos'); + const wallet = generateWalletFromMnemonic(mnemonic, { + hdPath: "m/44'/60'/0'/0/1", + addressPrefix: 'evmos', + ethWallet: false, + }); const accounts = wallet.getAccounts(); expect(accounts[0]?.address).toBe(referenceWallets.ref2.addresses.evmos); }); @@ -94,7 +102,9 @@ describe('generateMnemonic', () => { expect(accounts[1]?.address).toBe(referenceWallets.ref2.addresses.evmos); }); test('generateWalletFromMnemonic throws error if mnemonic is invalid', () => { - expect(() => generateWalletFromMnemonic('', "m/44'/118'/0'/0/0", 'cosmos')).toThrow('Invalid mnemonic'); + expect(() => + generateWalletFromMnemonic('', { hdPath: "m/44'/118'/0'/0/0", addressPrefix: 'cosmos', ethWallet: false }), + ).toThrow('Invalid mnemonic'); }); test('generateWalletsFromMnemonic throws error if mnemonic is invalid', () => { expect(() => generateWalletsFromMnemonic('', ["m/44'/118'/0'/0/0"], 'cosmos')).toThrow('Invalid mnemonic');