packageDocumentation module import { bip39 , hdkey , EncryptOptions , getAddress , generatePrivateKey } from '@harmony-js/crypto' ; import { Messenger } from '@harmony-js/network' ; import { isPrivateKey , isAddress , ChainType } from '@harmony-js/utils' ; import { Transaction } from '@harmony-js/transaction' ; import { StakingTransaction } from '@harmony-js/staking' ; import { Account } from './account' ; import { defaultMessenger } from './utils' ; class Wallet { static generateMnemonic ( ) { return bip39 . generateMnemonic ( ) ; } hidden messenger : Messenger ; hidden protected defaultSigner ? : string ; hidden private accountMap : Map < string , Account > = new Map ( ) ; return { string [ ] } example get accounts ( ) : string [ ] { return [ ... this . accountMap . keys ( ) ] ; } example get signer ( ) : Account | undefined { if ( this . defaultSigner ) { return this . getAccount ( this . defaultSigner ) ; } else if ( ! this . defaultSigner && this . accounts . length > 0 ) { this . setSigner ( this . accounts [ 0 ] ) ; return this . getAccount ( this . accounts [ 0 ] ) ; } else { return undefined ; } } example constructor ( messenger = defaultMessenger ) { this . messenger = messenger ; } function memberof return { string } newMnemonic ( ) { return Wallet . generateMnemonic ( ) ; } param { string } phrase param { index } index example addByMnemonic ( phrase , index = 0 ) { if ( ! this . isValidMnemonic ( phrase ) ) { throw new Error ( `Invalid mnemonic phrase: ${ phrase }` ) ; } const seed = bip39 . mnemonicToSeed ( phrase ) ; const hdKey = hdkey . fromMasterSeed ( seed ) ; const path = this . messenger . chainType === ChainType . Harmony ? '1023' : '60' ; const childKey = hdKey . derive ( `m/44'/${ path }'/0'/0/${ index }` ) ; const privateKey = childKey . privateKey . toString ( 'hex' ) ; return this . addByPrivateKey ( privateKey ) ; } param { string } privateKey return { Account } example addByPrivateKey ( privateKey ) { try { const newAcc = Account . add ( privateKey ) ; newAcc . setMessenger ( this . messenger ) ; if ( newAcc . address ) { this . accountMap . set ( newAcc . address , newAcc ) ; if ( ! this . defaultSigner ) { this . setSigner ( newAcc . address ) ; } return newAcc ; } else { throw new Error ( 'add account failed' ) ; } } catch ( error ) { throw error ; } } param { string } keyStore param { string } password return { Account } async addByKeyStore ( keyStore , password ) { try { const newAcc = new Account ( undefined ) ; const result = await newAcc . fromFile ( keyStore , password ) ; result . setMessenger ( this . messenger ) ; if ( result . address ) { this . accountMap . set ( result . address , result ) ; if ( ! this . defaultSigner ) { this . setSigner ( result . address ) ; } return result ; } else { throw new Error ( 'add account failed' ) ; } } catch ( error ) { throw error ; } } return { Account } example async createAccount ( password ? , options ? ) { const prv = generatePrivateKey ( ) ; const acc = this . addByPrivateKey ( prv ) ; if ( acc . address && password ) { const encrypted = await this . encryptAccount ( acc . address , password , options ) ; return encrypted ; } else if ( acc . address && ! password ) { return acc ; } else { throw new Error ( 'create acount failed' ) ; } } param { string } address param { string } password param { EncryptOptions } options return { Promise < Account > } example async encryptAccount ( address , password , options ? ) { try { const foundAcc = this . getAccount ( address ) ; if ( foundAcc && foundAcc . privateKey && isPrivateKey ( foundAcc . privateKey ) ) { await foundAcc . toFile ( password , options ) ; return foundAcc ; } else if ( foundAcc && foundAcc . privateKey && ! isPrivateKey ( foundAcc . privateKey ) ) { return foundAcc ; } else { throw new Error ( 'encrypt account failed' ) ; } } catch ( error ) { throw error ; } } param { string } address param { string } password return { Promise < Account > } example async decryptAccount ( address , password ) { try { const foundAcc = this . getAccount ( address ) ; if ( foundAcc && foundAcc . privateKey && ! isPrivateKey ( foundAcc . privateKey ) ) { await foundAcc . fromFile ( foundAcc . privateKey , password ) ; return foundAcc ; } else if ( foundAcc && foundAcc . privateKey && isPrivateKey ( foundAcc . privateKey ) ) { foundAcc . encrypted = false ; return foundAcc ; } else { throw new Error ( 'decrypt account failed' ) ; } } catch ( error ) { throw error ; } } param { string } address return { Account } example getAccount ( address ) { return this . accountMap . get ( getAddress ( address ) . basicHex ) ; } function memberof description param { string } address removeAccount ( address ) { this . accountMap . delete ( getAddress ( address ) . basicHex ) ; if ( this . defaultSigner === address ) { this . defaultSigner = undefined ; } } param messenger example setMessenger ( messenger ) { this . messenger = messenger ; } param address setSigner ( address ) { if ( ! isAddress ( address ) && ! this . getAccount ( address ) ) { throw new Error ( 'could not set signer' ) ; } this . defaultSigner = address ; } async signTransaction ( transaction , account = this . signer , password = undefined , updateNonce = true , encodeMode = 'rlp' , blockNumber = 'latest' ) { const toSignWith = account || this . signer ; if ( ! toSignWith ) { throw new Error ( 'no signer found or did not provide correct account' ) ; } if ( toSignWith instanceof Account && toSignWith . encrypted && toSignWith . address ) { if ( ! password ) { throw new Error ( 'must provide password to further execution' ) ; } try { const decrypted = await this . decryptAccount ( toSignWith . address , password ) ; const signed = await decrypted . signTransaction ( transaction , updateNonce , encodeMode , blockNumber ) ; await this . encryptAccount ( toSignWith . address , password ) ; return signed ; } catch ( error ) { throw error ; } } else if ( toSignWith instanceof Account && ! toSignWith . encrypted && toSignWith . address ) { try { const signed = await toSignWith . signTransaction ( transaction , updateNonce , encodeMode , blockNumber ) ; return signed ; } catch ( error ) { throw error ; } } else { throw new Error ( 'sign transaction failed' ) ; } } async signStaking ( staking , account = this . signer , password = undefined , updateNonce = true , encodeMode = 'rlp' , blockNumber = 'latest' , shardID = this . messenger . currentShard ) { const toSignWith = account || this . signer ; if ( ! toSignWith ) { throw new Error ( 'no signer found or did not provide correct account' ) ; } if ( toSignWith instanceof Account && toSignWith . encrypted && toSignWith . address ) { if ( ! password ) { throw new Error ( 'must provide password to further execution' ) ; } try { const decrypted = await this . decryptAccount ( toSignWith . address , password ) ; const signed = await decrypted . signStaking ( staking , updateNonce , encodeMode , blockNumber , shardID ) ; await this . encryptAccount ( toSignWith . address , password ) ; return signed ; } catch ( error ) { throw error ; } } else if ( toSignWith instanceof Account && ! toSignWith . encrypted && toSignWith . address ) { try { const signed = await toSignWith . signStaking ( staking , updateNonce , encodeMode , blockNumber , shardID ) ; return signed ; } catch ( error ) { throw error ; } } else { throw new Error ( 'sign transaction failed' ) ; } } function memberof description param { string } phrase return { boolean } ignore private isValidMnemonic ( phrase ) { if ( phrase . trim ( ) . split ( /\s+/g ) . length < 12 ) { return false ; } return bip39 . validateMnemonic ( phrase ) ; } } export { Wallet } ;