break(hdnode):remake hdnode

dev
neeboo 5 years ago
parent edb8e7a05d
commit fd524cd61e
  1. 0
      docs/README.md
  2. 6
      package.json
  3. 218
      packages/harmony-account/src/hdnode.ts
  4. 4
      packages/harmony-core/src/blockchain.ts
  5. 101
      packages/harmony-core/src/util.ts
  6. 4
      packages/harmony-network/src/rpcMethod/builder.ts
  7. 2
      packages/harmony-network/src/rpcMethod/rpc.ts
  8. 14
      scripts/docs.ts
  9. 30
      scripts/typedoc/batch.js

@ -18,7 +18,6 @@
"dist": "yarn packages:bundler && yarn bundle:webpack",
"packages:cleanUnexpected": "gulp cleanUnexpected",
"packages:clean": "gulp cleanServer && yarn packages:cleanUnexpected",
"packages:cleanDocs": "gulp cleanDocs",
"packages:bundler": "yarn packages:clean && yarn build:ts && ts-node -P scripts/tsconfig.json scripts/bundle.ts",
"schema": "ts-node -P scripts/tsconfig.json scripts/typings/schema.ts core",
"test": "cross-env TEST_ENV=unit jest -c scripts/jest/jest.config.js --rootDir=.",
@ -28,7 +27,10 @@
"test:e2e": "cross-env TEST_ENV=e2e jest -c ./scripts/jest/jest.e2e.config.js --runInBand --verbose --collectCoverage=false",
"docs:vue": "ts-node -P scripts/tsconfig.json scripts/docs.ts vuepress",
"docs:gitbook": "ts-node -P scripts/tsconfig.json scripts/docs.ts gitbook",
"docs:build": "ts-node -P scripts/tsconfig.json scripts/docs.ts docusaurus,vuepress,gitbook,bitbucket,default",
"docs:docusaurus": "ts-node -P scripts/tsconfig.json scripts/docs.ts docusaurus",
"docs:bitbucket": "ts-node -P scripts/tsconfig.json scripts/docs.ts bitbucket",
"docs:default": "ts-node -P scripts/tsconfig.json scripts/docs.ts default",
"docs:clean": "gulp cleanDocs",
"docs:bundler": "yarn packages:cleanDocs && yarn docs:build",
"release": "yarn bootstrap && yarn bundle && lerna publish --exact",
"format": "prettier --write '**/*.{ts,tsx,js}' --config .prettierrc",

@ -1,19 +1,47 @@
import {bip39, hdkey, getAddress, BN, Signature} from '@harmony-js/crypto';
import {
bip39,
hdkey,
encryptPhrase,
decryptPhrase,
EncryptOptions,
} from '@harmony-js/crypto';
import { HDPath } from '@harmony-js/utils';
HDPath,
// defineReadOnly,
isHttp,
isWs,
ChainID,
ChainType,
Unit,
isHex,
numberToHex,
} from '@harmony-js/utils';
import {Messenger, HttpProvider, WSProvider} from '@harmony-js/network';
import {
Transaction,
TxStatus,
RLPSign,
TransasctionReceipt,
} from '@harmony-js/transaction';
import {Account} from './account';
export class HDNode extends hdkey {
static new() {
return new HDNode(bip39.generateMnemonic(), 0);
}
static add(phrase: string, index: number) {
return new HDNode(phrase, index);
}
interface WalletsInterfaces {
[key: string]: Account;
}
interface Web3TxPrams {
id?: string;
from?: string;
to?: string;
nonce?: number | string;
gasLimit?: BN | number | string;
gasPrice?: BN | number | string;
shardID?: number | string;
toShardID?: number | string;
data?: string;
value?: BN;
chainId?: number;
rawTransaction?: string;
unsignedRawTransaction?: string;
signature?: Signature | string;
receipt?: TransasctionReceipt;
}
export class HDNode {
static isValidMnemonic(phrase: string): boolean {
if (phrase.trim().split(/\s+/g).length < 12) {
return false;
@ -23,60 +51,148 @@ export class HDNode extends hdkey {
static generateMnemonic(): string {
return bip39.generateMnemonic();
}
public provider: HttpProvider | WSProvider;
private messenger: Messenger;
private hdwallet: hdkey | undefined;
private path: string;
private mnemonic?: string;
private entropy?: string;
private childKey?: hdkey;
private index: number;
private addressCount: number;
private addresses: string[];
private wallets: WalletsInterfaces;
constructor(menmonic?: string, index: number = 0) {
super();
constructor(
provider: string | HttpProvider | WSProvider = 'http://localhost:9500',
menmonic?: string,
index: number = 0,
addressCount: number = 1,
chainType: ChainType = ChainType.Harmony,
chainId: ChainID = ChainID.Default,
) {
this.provider = this.setProvider(provider);
this.messenger = new Messenger(this.provider, chainType, chainId);
this.hdwallet = undefined;
this.addresses = [];
this.wallets = {};
this.path = HDPath;
this.mnemonic = menmonic;
this.entropy = this.mnemonic ? this.getEntropy(this.mnemonic) : undefined;
this.childKey = this.entropy
? this.getChildKey(this.entropy, index)
: undefined;
this.index = index;
this.addressCount = addressCount;
this.getHdWallet(menmonic || HDNode.generateMnemonic());
}
getEntropy(mnemonic: string) {
return bip39.mnemonicToEntropy(mnemonic);
normalizePrivateKeys(mnemonic: string | string[]) {
if (Array.isArray(mnemonic)) {
return mnemonic;
} else if (mnemonic && !mnemonic.includes(' ')) {
return [mnemonic];
} else {
return false;
}
}
getChildKey(entropy: string, index: number) {
const master = HDNode.fromMasterSeed(Buffer.from(entropy, 'hex'));
return master.derive(`${this.path}${index}`);
setProvider(provider: string | HttpProvider | WSProvider) {
if (isHttp(provider) && typeof provider === 'string') {
return new HttpProvider(provider);
} else if (provider instanceof HttpProvider) {
return provider;
} else if (isWs(provider) && typeof provider === 'string') {
return new WSProvider(provider);
} else if (provider instanceof WSProvider) {
return provider;
} else {
throw new Error('provider is not recognized');
}
}
async lock(password: string, options: EncryptOptions) {
if (this.mnemonic && HDNode.isValidMnemonic(this.mnemonic)) {
try {
this.mnemonic = await encryptPhrase(this.mnemonic, password, options);
} catch (error) {
throw error;
getHdWallet(mnemonic: string) {
if (!HDNode.isValidMnemonic(mnemonic)) {
throw new Error('Mnemonic invalid or undefined');
}
this.hdwallet = hdkey.fromMasterSeed(bip39.mnemonicToSeed(mnemonic));
for (let i = this.index; i < this.index + this.addressCount; i++) {
if (!this.hdwallet) {
throw new Error('hdwallet is not found');
}
} else {
throw new Error('mnemonic is not valid');
const childKey = this.hdwallet.derive(`${this.path}${i}`);
const prv = childKey.privateKey.toString('hex');
const account = new Account(prv);
const addr = account.checksumAddress;
this.addresses.push(addr);
this.wallets[addr] = account;
}
}
send(
...args: [string, (string | any[] | undefined)?, (string | undefined)?]
) {
this.messenger.send.apply(this.messenger, args);
}
async unlock(password: string) {
if (this.mnemonic) {
try {
this.mnemonic = await decryptPhrase(
JSON.parse(this.mnemonic),
password,
);
} catch (error) {
throw error;
sendAsync(
...args: [string, (string | any[] | undefined)?, (string | undefined)?]
) {
this.send(...args);
}
// tslint:disable-next-line: ban-types
getAccounts(cb?: Function) {
if (cb) {
cb(null, this.addresses);
}
return this.addresses;
}
// tslint:disable-next-line: ban-types
getPrivateKey(address: string, cb?: Function) {
if (!cb) {
if (!this.wallets[address]) {
throw new Error('Account not found');
} else {
return this.wallets[address].privateKey;
}
}
if (!this.wallets[address]) {
return cb('Account not found');
} else {
throw new Error('mnemonic is not valid');
cb(null, this.wallets[address].privateKey);
}
}
signTransaction(txParams: any | Web3TxPrams, cb: Function) {
const from: string = getAddress(txParams.from).checksum;
const to: string = getAddress(txParams.to).checksum;
const gasLimit = isHex(txParams.gasLimit)
? txParams.gasLimit
: new Unit(txParams.gasLimit).asWei().toWei();
const gasPrice = isHex(txParams.gasPrice)
? txParams.gasPrice
: new Unit(txParams.gasPrice).asWei().toWei();
const value = isHex(txParams.value)
? txParams.value
: numberToHex(txParams.value);
const nonce = isHex(txParams.nonce)
? txParams.nonce
: numberToHex(txParams.nonce);
const prv = this.wallets[from].privateKey;
get _privateKey() {
return this.childKey ? this.childKey.privateKey.toString('hex') : '';
const tx = new Transaction(
{...txParams, from, to, gasLimit, gasPrice, value, nonce},
this.messenger,
TxStatus.INTIALIZED,
);
tx.getRLPUnsigned();
if (prv) {
const rawTransaction = RLPSign(tx, prv)[1];
if (cb) {
cb(null, rawTransaction);
}
return rawTransaction;
}
}
getAddress(idx?: number) {
if (!idx) {
return this.addresses[0];
} else {
return this.addresses[idx];
}
}
get _publicKey() {
return this.childKey ? this.childKey.publicKey.toString('hex') : '';
getAddresses() {
return this.addresses;
}
}

@ -235,9 +235,9 @@ class Blockchain {
return this.getRpcResult(result);
}
async getProtocalVersion() {
async getProtocolVersion() {
const result = await this.messenger.send(
RPCMethod.ProtocalVersion,
RPCMethod.ProtocolVersion,
[],
this.messenger.chainPrefix,
);

@ -1,7 +1,106 @@
import { ChainType, ChainID } from '@harmony-js/utils';
import {ChainType, ChainID, defaultConfig} from '@harmony-js/utils';
import {Harmony} from './harmony';
export interface HarmonyConfig {
chainUrl: string;
chainType: ChainType;
chainId: ChainID;
}
// tslint:disable-next-line: variable-name
export function createWeb3(_web3: any) {
const url: string = _web3.currentProvider.url;
const harmony = new Harmony(url, {
chainId: defaultConfig.Default.Chain_ID,
chainType: defaultConfig.Default.Chain_Type,
chainUrl: defaultConfig.Default.Chain_URL,
});
_web3.setProvider(harmony.messenger.provider);
_web3.messenger = harmony.messenger;
_web3.eth.getRpcResult = harmony.blockchain.getRpcResult;
// map blockchain to eth
const {blockchain} = harmony;
_web3.eth.getBlockNumber = () => blockchain.getBlockByNumber;
_web3.eth.getBalance = (address: string, blockNumber?: string) =>
blockchain.getBalance({address, blockNumber});
_web3.eth.getBlockByHash = (blockHash: string, returnObject?: boolean) =>
blockchain.getBlockByHash({blockHash, returnObject});
_web3.eth.getBlockByNumber = (blockNumber: string, returnObject?: boolean) =>
blockchain.getBlockByNumber({blockNumber, returnObject});
_web3.eth.getBlockTransactionCountByHash = (blockHash: string) =>
blockchain.getBlockTransactionCountByHash({blockHash});
_web3.eth.getBlockTransactionCountByNumber = (blockNumber: string) =>
blockchain.getBlockTransactionCountByNumber({blockNumber});
_web3.eth.getTransactionByBlockHashAndIndex = (
blockHash: string,
index: string,
) => blockchain.getTransactionByBlockHashAndIndex({blockHash, index});
_web3.eth.getTransactionByBlockNumberAndIndex = (
blockNumber: string,
index: string,
) => blockchain.getTransactionByBlockNumberAndIndex({blockNumber, index});
_web3.eth.getTransactionByHash = (txnHash: string) =>
blockchain.getTransactionByHash({txnHash});
_web3.eth.getTransactionReceipt = (txnHash: string) =>
blockchain.getTransactionReceipt({txnHash});
_web3.eth.getCode = (address: string, blockNumber?: string) =>
blockchain.getCode({address, blockNumber});
_web3.eth.net_peerCount = () => blockchain.net_peerCount();
_web3.eth.net_version = () => blockchain.net_version();
_web3.eth.getProtocolVersion = () => blockchain.getProtocolVersion();
_web3.eth.getStorageAt = (
address: string,
position: string,
blockNumber: string | undefined,
) => blockchain.getStorageAt({address, position, blockNumber});
_web3.eth.getTransactionCount = (
address: string,
blockNumber: string | undefined,
) => blockchain.getTransactionCount({address, blockNumber});
_web3.eth.estimateGas = (to: string, data: string) =>
blockchain.estimateGas({to, data});
_web3.eth.gasPrice = () => blockchain.gasPrice();
_web3.eth.call = (payload: any, blockNumber: string | undefined) =>
blockchain.call({payload, blockNumber});
_web3.eth.newPendingTransactions = () => blockchain.newPendingTransactions();
_web3.eth.newBlockHeaders = () => blockchain.newBlockHeaders();
_web3.eth.syncing = () => blockchain.syncing();
_web3.eth.logs = (options: any) => blockchain.logs(options);
// map subscribe to _web3
_web3.eth.subscribe = harmony.messenger.subscribe;
// map accounts to _web3
_web3.accounts = harmony.wallet.accounts;
_web3.eth.accounts.create = harmony.wallet.createAccount;
_web3.eth.accounts.privateKeyToAccount = harmony.wallet.addByPrivateKey;
_web3.eth.accounts.encrypt = async (privateKey: string, password: string) => {
const newAcc = new harmony.Modules.Account(privateKey, harmony.messenger);
const result = await newAcc.toFile(password);
return result;
};
_web3.eth.accounts.decrypt = async (
keystoreJsonV3: any,
password: string,
) => {
const newAcc = new harmony.Modules.Account();
const result = await newAcc.fromFile(
JSON.stringify(keystoreJsonV3),
password,
);
return result;
};
_web3.eth.accounts.signTransaction = harmony.wallet.signTransaction;
// map transaction to web3
_web3.eth.recoverTransaction = harmony.transactions.recover;
// map contract to web3
_web3.eth.Contract = harmony.contracts.createContract;
_web3.utils = {..._web3.utils, ...harmony.utils, ...harmony.crypto};
}

@ -29,7 +29,9 @@ class JsonRpc {
params: string | undefined | any[],
): RPCRequestPayload<any> => {
// FIXME: error to be done by shared/errors
if (!method) throw new Error('jsonrpc method should be specified!');
if (!method) {
throw new Error('jsonrpc method should be specified!');
}
// advance message ID
this.messageId += 1;

@ -63,7 +63,7 @@ export const enum RPCMethod {
// 30. net_version
NetVersion = 'net_version',
// 31. hmy_protocolVersion
ProtocalVersion = 'hmy_protocolVersion',
ProtocolVersion = 'hmy_protocolVersion',
}
export const enum RPCErrorCode {

@ -5,6 +5,7 @@ import spawn from 'cross-spawn';
// tslint:disable-next-line: no-var-requires
const runner = require.resolve('./typedoc/runner');
const batch = require.resolve('./typedoc/batch');
const options = {stdio: 'inherit'};
const outputs = process.argv.slice(2)[0].split(',');
@ -51,7 +52,18 @@ async function docs() {
}
}
docs();
// docs();
async function batchDocs() {
await preProcessFunc(preProcessProjects);
// const srcArry = [];
// for (const pkg of projects) {
// srcArry.push(pkg.src);
// }
}
batchDocs();
// async function docs() {
// await preProcessFunc(preProcessProjects);

@ -0,0 +1,30 @@
const path = require('path');
// tslint:disable-next-line: no-implicit-dependencies no-var-requires
const {Application} = require('typedoc');
// tslint:disable-next-line: no-implicit-dependencies no-var-requires
const arg = require('arg');
const args = arg({
'--pkgPath': String,
'-p': '--pkgPath',
'--pkgSrc': String,
'-s': '--pkgSrc',
'--target': String,
'-t': '--target',
});
const pkgSrc = args['--pkgSrc'];
const pkgPath = args['--pkgPath'];
const target = args['--target'];
const app = new Application({
mode: 'file',
tsconfig: `tsconfig.json`,
theme: target === 'default' ? 'default' : 'markdown',
plugin: path.resolve('node_modules/typedoc-plugin-markdown'),
platform: target,
});
const files = [...app.expandInputFiles([pkgSrc])];
console.log(files);
Loading…
Cancel
Save