diff --git a/examples/testNode.js b/examples/testNode.js index f3678c1..f4f40d5 100644 --- a/examples/testNode.js +++ b/examples/testNode.js @@ -124,5 +124,9 @@ const acc = wallet.addByPrivateKey( // console.log(getContractAddress(acc.publicKey, 248)); -const harmony = new Harmony('https://devnet.harmony.one'); -console.log(harmony.blockchain); +const harmony = new Harmony('https://dev-api.zilliqa.com'); + +const file = + '{"version":3,"id":"05D302EE-23DC-48C4-B89C-CAAAC1C780C4","x-ethers":{"gethFilename":"UTC--2018-01-26T20-25-02.0Z--15db397ed5f682acb22b0afc6c8de4cdfbda7cbc","mnemonicCiphertext":"b92c7c3da540ae7beee55365fb330c33","mnemonicCounter":"a65d689a73c096025f2acae3f7068510","client":"ethers/iOS","version":"0.1"},"Crypto":{"ciphertext":"fa6ff2374087a089ec9fcba3bc21389f5e26ec2932c95b608ebe0218efab83c6","cipherparams":{"iv":"5ddca45b254406516ca2c97d18d5dfd9"},"kdf":"scrypt","kdfparams":{"r":8,"p":1,"n":262144,"dklen":32,"salt":"864a474f8586ab0fa97ed9240ae6227b2b22b48bdf298137c355e4a07eb19831"},"mac":"eaa89325acedbf88c0893e53c8c8d426b590655746c66da9cd76e4f72d84084f","cipher":"aes-128-ctr"},"address":"15db397ed5f682acb22b0afc6c8de4cdfbda7cbc"}'; + +const acc2 = new Account().fromFile(file, 'password').then(console.log); diff --git a/package.json b/package.json index f785756..7aa94fb 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "bundle": "ts-node -P scripts/tsconfig.json scripts/bundle.ts umd,esm", "clean": "lerna clean --yes && lerna run clean && rimraf includes", "schema": "ts-node -P scripts/tsconfig.json scripts/typings/schema.ts core", - "test": "cross-env TEST_ENV=unit jest -c jest.config.js --rootDir=.", + "test": "cross-env TEST_ENV=unit jest -c scripts/jest/jest.config.js --rootDir=.", + "test:src": "cross-env NODE_ENV=test jest --config ./scripts/jest/jest.src.config.js --silent --runInBand --no-cache", "test:build": "cross-env TEST_ENV=unit jest -c jest.build.config.js", "test:integration": "cross-env TEST_ENV=integration jest -c jest.iconfig.js --runInBand --verbose --collectCoverage=false", "release": "yarn bootstrap && yarn bundle && lerna publish --exact", diff --git a/packages/harmony-account/src/wallet.ts b/packages/harmony-account/src/wallet.ts index 47ecba2..9600e26 100644 --- a/packages/harmony-account/src/wallet.ts +++ b/packages/harmony-account/src/wallet.ts @@ -42,7 +42,7 @@ class Wallet { } const seed = bip39.mnemonicToSeed(phrase); const hdKey = hdkey.fromMasterSeed(seed); - //TODO:hdkey should apply to Harmony's settings + // TODO:hdkey should apply to Harmony's settings const childKey = hdKey.derive(`m/44'/313'/0'/0/${index}`); const privateKey = childKey.privateKey.toString('hex'); return this.addByPrivateKey(privateKey); @@ -68,6 +68,31 @@ class Wallet { throw error; } } + + /** + * @function createAccount + * @description create a new account using Mnemonic + * @return {Account} {description} + */ + async createAccount( + password?: string, + options?: EncryptOptions, + ): Promise { + const words = this.generateMnemonic(); + const acc = this.addByMnemonic(words); + 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'); + } + } /** * @function encryptAccount * @memberof Wallet diff --git a/packages/harmony-crypto/src/keystore.ts b/packages/harmony-crypto/src/keystore.ts index e07559a..d685c48 100644 --- a/packages/harmony-crypto/src/keystore.ts +++ b/packages/harmony-crypto/src/keystore.ts @@ -119,7 +119,7 @@ export const encrypt = async ( version: 3, id: uuid.v4({ random: uuidRandom || hexToIntArray(randomBytes(16)) }), address: address.toLowerCase().replace('0x', ''), - crypto: { + Crypto: { ciphertext: ciphertext.toString('hex'), cipherparams: { iv: iv.toString('hex'), @@ -142,13 +142,13 @@ export const decrypt = async ( keystore: Keystore, password: string, ): Promise => { - const ciphertext = Buffer.from(keystore.crypto.ciphertext, 'hex'); - const iv = Buffer.from(keystore.crypto.cipherparams.iv, 'hex'); - const { kdfparams } = keystore.crypto; + const ciphertext = Buffer.from(keystore.Crypto.ciphertext, 'hex'); + const iv = Buffer.from(keystore.Crypto.cipherparams.iv, 'hex'); + const { kdfparams } = keystore.Crypto; const derivedKey = await getDerivedKey( Buffer.from(password), - keystore.crypto.kdf, + keystore.Crypto.kdf, kdfparams, ); @@ -157,7 +157,7 @@ export const decrypt = async ( '', ); - if (mac.toUpperCase() !== keystore.crypto.mac.toUpperCase()) { + if (mac.toUpperCase() !== keystore.Crypto.mac.toUpperCase()) { return Promise.reject(new Error('Failed to decrypt.')); } diff --git a/packages/harmony-crypto/src/types.ts b/packages/harmony-crypto/src/types.ts index 8e28d4a..9497956 100644 --- a/packages/harmony-crypto/src/types.ts +++ b/packages/harmony-crypto/src/types.ts @@ -24,7 +24,7 @@ export interface EncryptOptions { export interface Keystore { address: string; - crypto: { + Crypto: { cipher: string; cipherparams: { iv: string; diff --git a/packages/harmony-utils/__test__/fixture.ts b/packages/harmony-utils/__test__/fixture.ts new file mode 100644 index 0000000..e3f6df4 --- /dev/null +++ b/packages/harmony-utils/__test__/fixture.ts @@ -0,0 +1,32 @@ +// import BN from 'bn.js'; + +export const basicType = { + zero: 0, + float: 0.1, + text: 'testString', + jsonString: + '{"name":"@harmony/utils","version":"0.0.48","description":"utils for harmony"}', + hexNumber: 0x123, + hexString: '0x123', + bool: true, + undefined, + null: null, + // tslint:disable-next-line: no-empty + function: () => {}, + array: [1, 2, 3], + object: {}, +}; + +export const advanceType = { + privateKey: + '0x97d2d3a21d829800eeb01aa7f244926f993a1427d9ba79d9dc3bf14fe04d9e37', + publicKey: + '0x028fe48b60c4511f31cf58906ddaa8422725d9313d4b994fab598d2cf220146228', + address: '0x84fece7d1f5629bc728c956ffd313dd0c3ac8f17', + hexAddress: '0x84fece7d1f5629bc728c956ffd313dd0c3ac8f17', + checkSumAddress: '0x84fece7d1f5629Bc728c956Ffd313dD0C3AC8f17', + hex: '0x8423', + hash: 'F5A5FD42D16A20302798EF6ED309979B43003D2320D9F0E8EA9831A92759FB4B', + byStrX: '0x84fece7d1f5629bc728c956ffd313dd0c3ac8f17', + url: 'https://www.zilliqa.com', +}; diff --git a/packages/harmony-utils/__test__/tsconfig.json b/packages/harmony-utils/__test__/tsconfig.json new file mode 100644 index 0000000..38ca0b1 --- /dev/null +++ b/packages/harmony-utils/__test__/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../tsconfig.test.json" +} diff --git a/packages/harmony-utils/__test__/validators.test.ts b/packages/harmony-utils/__test__/validators.test.ts new file mode 100644 index 0000000..20c0834 --- /dev/null +++ b/packages/harmony-utils/__test__/validators.test.ts @@ -0,0 +1,83 @@ +import * as validators from '../src/validators'; +import { basicType, advanceType } from './fixture'; + +function expector(fun: any, val: any, bool: boolean) { + return expect(fun(val)).toEqual(bool); +} + +function mapTest(testObject: any, testTrue: string[], testFunc: any) { + const keys = Object.keys(testObject); + keys.forEach((k: string) => { + if (testTrue.includes(k)) { + expector(testFunc, testObject[k], true); + } else { + expector(testFunc, testObject[k], false); + } + }); +} + +describe('test transformer', () => { + it('test isNumber', () => { + const beTrue = ['zero', 'float', 'hexNumber']; + mapTest(basicType, beTrue, validators.isNumber); + }); + it('test isInt', () => { + const beTrue = ['zero', 'hexNumber']; + mapTest(basicType, beTrue, validators.isInt); + }); + it('test isString', () => { + const beTrue = ['text', 'hexString', 'jsonString']; + mapTest(basicType, beTrue, validators.isString); + }); + it('test isBoolean', () => { + const beTrue = ['bool']; + mapTest(basicType, beTrue, validators.isBoolean); + }); + it('test isArray', () => { + const beTrue = ['array']; + mapTest(basicType, beTrue, validators.isArray); + }); + it('test isJsonString', () => { + const beTrue = ['jsonString']; + mapTest(basicType, beTrue, validators.isJsonString); + }); + it('test isObject', () => { + const beTrue = ['object']; + mapTest(basicType, beTrue, validators.isObject); + }); + it('test isFunction', () => { + const beTrue = ['function']; + mapTest(basicType, beTrue, validators.isFunction); + }); + + it('test isPubKey', () => { + const beTrue = ['publicKey']; + mapTest({ ...advanceType }, beTrue, validators.isPublicKey); + }); + it('test isAddress', () => { + const beTrue = ['address', 'hexAddress', 'checkSumAddress', 'byStrX']; + mapTest({ ...advanceType }, beTrue, validators.isAddress); + }); + it('test isPrivateKey', () => { + const beTrue = ['privateKey', 'hash']; + mapTest({ ...advanceType }, beTrue, validators.isPrivateKey); + }); + it('test isHex', () => { + const beTrue = [ + 'privateKey', + 'publicKey', + 'address', + 'hexString', + 'hexAddress', + 'checkSumAddress', + 'hex', + 'byStrX', + ]; + mapTest({ ...advanceType }, beTrue, validators.isHex); + try { + validators.isHex(basicType.zero); + } catch (error) { + expect(error.message).toEqual(`${basicType.zero} is not string`); + } + }); +}); diff --git a/packages/harmony-utils/src/validators.ts b/packages/harmony-utils/src/validators.ts index 9541a2c..d439939 100644 --- a/packages/harmony-utils/src/validators.ts +++ b/packages/harmony-utils/src/validators.ts @@ -91,17 +91,12 @@ export const isFunction = (obj: any): boolean => { return typeof obj === 'function'; }; -export const isHex = (obj: string): boolean => { +export const isHex = (obj: any): boolean => { if (!isString(obj)) { throw new Error(`${obj} is not string`); - } else { - try { - return ( - (obj.startsWith('0x') || obj.startsWith('-0x')) && - isNumber(Number.parseInt(obj.toLowerCase().replace('0x', ''), 16)) - ); - } catch (error) { - throw error; - } } + return ( + (obj.startsWith('0x') || obj.startsWith('-0x')) && + isNumber(Number.parseInt(`${obj}`.toLowerCase().replace('0x', ''), 16)) + ); }; diff --git a/packages/harmony-utils/tsconfig.test.json b/packages/harmony-utils/tsconfig.test.json new file mode 100644 index 0000000..8daf0f0 --- /dev/null +++ b/packages/harmony-utils/tsconfig.test.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.test.json", + "include": ["src", "test", "../../typings/**/*.d.ts"], + "references": [] +} diff --git a/scripts/jest/jest.build.config.js b/scripts/jest/jest.build.config.js index 13ead20..f9d91fa 100644 --- a/scripts/jest/jest.build.config.js +++ b/scripts/jest/jest.build.config.js @@ -1,29 +1,29 @@ -const { readdirSync, statSync } = require('fs') -const { join } = require('path') -const baseConfig = require('./jest.src.config') +const { readdirSync, statSync } = require('fs'); +const { join } = require('path'); +const baseConfig = require('./jest.src.config'); // Find all folders in packages/* with package.json -const packagesRoot = join(__dirname, '..', '..', 'packages') -const packages = readdirSync(packagesRoot).filter(dir => { +const packagesRoot = join(__dirname, '..', '..', 'packages'); +const packages = readdirSync(packagesRoot).filter((dir) => { if (dir.charAt(0) === '.') { - return false + return false; } if (dir === 'events') { // There's an actual Node package called "events" // that's used by jsdom so we don't want to alias that. - return false + return false; } - const packagePath = join(packagesRoot, dir, 'package.json') - return statSync(packagePath).isFile() -}) + const packagePath = join(packagesRoot, dir, 'package.json'); + return statSync(packagePath).isFile(); +}); // Create a module map to point packages to the build output -const moduleNameMapper = {} -packages.forEach(name => { +const moduleNameMapper = {}; +packages.forEach((name) => { // Root entry point - moduleNameMapper[`^${name}$`] = `/packages/${name}/lib/index.js` + moduleNameMapper[`^${name}$`] = `/packages/${name}/dist/index.js`; // Named entry points // moduleNameMapper[`^${name}/(.*)$`] = `/dist/node_modules/${name}/$1` -}) +}); module.exports = Object.assign({}, baseConfig, { // Redirect imports to the compiled bundles @@ -31,5 +31,5 @@ module.exports = Object.assign({}, baseConfig, { // Don't run bundle tests on blacklisted -test.internal.* files testPathIgnorePatterns: ['/node_modules/', '-test.internal.js$'], // Exclude the build output from transforms - transformIgnorePatterns: ['/node_modules/', '/build/'] -}) + transformIgnorePatterns: ['/node_modules/', '/build/'], +}); diff --git a/scripts/jest/jest.src.config.js b/scripts/jest/jest.src.config.js index 1a1310f..220bd7c 100644 --- a/scripts/jest/jest.src.config.js +++ b/scripts/jest/jest.src.config.js @@ -1,9 +1,16 @@ const config = { transform: { - '^.+\\.(t|j)s$': require.resolve('./transformer.js') + // '^.+\\.(t|j)s$': require.resolve('./transformer.js') + '^.+\\.(t)s$': 'ts-jest', + }, + globals: { + 'ts-jest': { + babelConfig: true, + tsConfig: './tsconfig.test.json', + }, }, testMatch: [ - '/packages/**/__test__/?(*.)+(spec|test).js' + // '/packages/**/__test__/?(*.)+(spec|test).js', // '/packages/laksa-account/__test__/?(*.)+(spec|test).js', // '/packages/laksa-blockchain/__test__/?(*.)+(spec|test).js', // '/packages/laksa-core/__test__/?(*.)+(spec|test).js' @@ -15,14 +22,14 @@ const config = { // '/packages/laksa-extend-keystore/__test__/?(*.)+(spec|test).js', // '/packages/laksa-providers-http/__test__/?(*.)+(spec|test).js', // '/packages/laksa-shared/__test__/?(*.)+(spec|test).js' - // '/packages/laksa-utils/__test__/?(*.)+(spec|test).js', + '/packages/harmony-utils/__test__/?(*.)+(spec|test).ts', // '/packages/laksa-wallet/__test__/?(*.)+(spec|test).js' // '/packages/laksa/__test__/?(*.)+(spec|test).js' ], moduleDirectories: ['src', 'node_modules'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], moduleNameMapper: { - 'cross-fetch': 'jest-fetch-mock' + 'cross-fetch': 'jest-fetch-mock', }, testURL: 'http://localhost', coverageThreshold: { @@ -30,21 +37,23 @@ const config = { branches: 80, functions: 80, lines: 80, - statements: 80 - } + statements: 80, + }, }, rootDir: process.cwd(), roots: ['/packages', '/scripts'], collectCoverageFrom: [ - 'packages/!(laksa-hd-wallet)/src/**/*.js' + // 'packages/!(harmony-core)/src/**/*.ts', + 'packages/harmony-utils/src/**/*.ts', // 'packages/!(laksa-core-crypto)/src/*.js' ], timers: 'fake', setupFiles: ['/scripts/jest/jest.setup.js'], - setupTestFrameworkScriptFile: '/scripts/jest/jest.framework-setup.js', + setupTestFrameworkScriptFile: + '/scripts/jest/jest.framework-setup.js', testEnvironment: process.env.NODE_ENV === 'development' ? 'node' : 'jsdom', collectCoverage: true, - automock: false -} + automock: false, +}; -module.exports = config +module.exports = config; diff --git a/tsconfig.test.json b/tsconfig.test.json index af56bfc..5656591 100644 --- a/tsconfig.test.json +++ b/tsconfig.test.json @@ -2,5 +2,5 @@ "extends": "./tsconfig.base.json", "files": [], "include": ["./typings/**/*.d.ts"], - "references": [] + "references": [{ "path": "packages/harmony-utils" }] }