├── .eslintignore ├── .yarnrc ├── tsconfig.e2e.json ├── packages ├── harmony-crypto │ ├── test │ │ ├── tsconfig.json │ │ ├── keccak256.test.ts │ │ ├── rlp.test.ts │ │ ├── keyTool.test.ts │ │ ├── bytes.test.ts │ │ ├── address.test.ts │ │ └── keystore.test.ts │ ├── tsconfig.test.json │ ├── src │ │ ├── signature.ts │ │ ├── index.ts │ │ ├── keccak256.ts │ │ ├── types.ts │ │ ├── random.ts │ │ └── rlp.ts │ ├── tsconfig.json │ ├── package.json │ ├── LICENSE │ └── README.md ├── harmony-staking │ ├── test │ │ └── tsconfig.json │ ├── tsconfig.test.json │ ├── src │ │ └── index.ts │ ├── tsconfig.json │ ├── package.json │ ├── LICENSE │ └── README.md ├── harmony-utils │ ├── src │ │ ├── errors.ts │ │ ├── index.ts │ │ ├── tools.ts │ │ ├── utils.ts │ │ └── chain.ts │ ├── test │ │ ├── tsconfig.json │ │ └── fixture.ts │ ├── tsconfig.test.json │ ├── tsconfig.json │ ├── package.json │ ├── LICENSE │ └── README.md ├── harmony-transaction │ ├── test │ │ └── tsconfig.json │ ├── tsconfig.test.json │ ├── tsconfig.json │ ├── src │ │ ├── index.ts │ │ ├── abstractTransaction.ts │ │ ├── shardingTransaction.ts │ │ └── factory.ts │ ├── package.json │ ├── LICENSE │ └── README.md ├── harmony-account │ ├── tsconfig.test.json │ ├── src │ │ ├── index.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── tsconfig.json │ ├── package.json │ ├── LICENSE │ └── test │ │ └── testAccount.test.ts ├── harmony-core │ ├── tsconfig.test.json │ ├── src │ │ ├── index.ts │ │ ├── types.ts │ │ └── util.ts │ ├── tsconfig.json │ ├── package.json │ ├── LICENSE │ └── README.md ├── harmony-network │ ├── tsconfig.test.json │ ├── tsconfig.json │ ├── src │ │ ├── subscriptions │ │ │ ├── NewPendingTransactionsSub.ts │ │ │ ├── NewHeadersSub.ts │ │ │ ├── SyncingSub.ts │ │ │ ├── LogSub.ts │ │ │ └── Subscription.ts │ │ ├── util.ts │ │ ├── providers │ │ │ ├── defaultFetcher.ts │ │ │ ├── provider.ts │ │ │ ├── emitter.ts │ │ │ ├── baseProvider.ts │ │ │ ├── baseSocket.ts │ │ │ └── http.ts │ │ ├── index.ts │ │ ├── rpcMethod │ │ │ ├── net.ts │ │ │ └── builder.ts │ │ ├── types.ts │ │ ├── messenger │ │ │ └── responseMiddleware.ts │ │ └── tracker │ │ │ ├── subscribeTracker.ts │ │ │ └── pollingTracker.ts │ ├── package.json │ ├── README.md │ └── LICENSE ├── harmony-contract │ ├── tsconfig.test.json │ ├── src │ │ ├── abi │ │ │ ├── index.ts │ │ │ ├── utils.ts │ │ │ └── api.ts │ │ ├── index.ts │ │ ├── utils │ │ │ ├── status.ts │ │ │ ├── options.ts │ │ │ ├── decoder.ts │ │ │ ├── encoder.ts │ │ │ ├── mapper.ts │ │ │ └── formatter.ts │ │ ├── contractFactory.ts │ │ ├── models │ │ │ ├── types.ts │ │ │ ├── AbiItemModel.ts │ │ │ └── AbiModel.ts │ │ ├── events │ │ │ ├── event.ts │ │ │ └── eventFactory.ts │ │ ├── methods │ │ │ └── methodFactory.ts │ │ └── contract.ts │ ├── tsconfig.json │ ├── package.json │ ├── LICENSE │ └── test │ │ └── abiCoder.test.ts └── README.md ├── typings ├── window.d.ts ├── scrypt.d.ts ├── aes-js.d.ts └── elliptic.d.ts ├── lerna.json ├── scripts ├── jest │ ├── jest.setup.js │ ├── jest.framework-setup.js │ ├── jest.e2e.config.js │ ├── transformer.js │ ├── jest.build.config.js │ └── jest.src.config.js ├── tsconfig.json ├── packagesTs.ts ├── webpack.ts ├── webpack │ ├── packagesForWP.ts │ └── webpack.config.ts ├── typedoc │ ├── batch.js │ └── runner.js ├── typings │ └── schema.ts ├── docs.ts ├── projects.ts └── bundle.ts ├── .prettierignore ├── .prettierrc ├── tsconfig.json ├── .travis.yml ├── tsconfig.test.json ├── e2e ├── tsconfig.json ├── src │ └── harmony.ts └── fixtures │ └── testAccount.json ├── tsconfig.base.json ├── tslint.json ├── gulpfile.js ├── LICENSE ├── .gitignore ├── RELEASE.md ├── .babelrc ├── TYPEDOC.md └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | .babelrc 2 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | registry "https://registry.npmjs.org" -------------------------------------------------------------------------------- /tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [{ "path": "e2e" }] 4 | } 5 | -------------------------------------------------------------------------------- /packages/harmony-crypto/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.test.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/harmony-staking/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.test.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/harmony-utils/src/errors.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @ignore 4 | */ 5 | -------------------------------------------------------------------------------- /packages/harmony-utils/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.test.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/harmony-transaction/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.test.json" 3 | } 4 | -------------------------------------------------------------------------------- /typings/window.d.ts: -------------------------------------------------------------------------------- 1 | export interface Window { 2 | WebSocket: any; 3 | MozWebSocket: any; 4 | } 5 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/*"], 3 | "npmClient": "yarn", 4 | "useWorkspaces": true, 5 | "version": "0.1.58" 6 | } 7 | -------------------------------------------------------------------------------- /scripts/jest/jest.setup.js: -------------------------------------------------------------------------------- 1 | global.fetch = require('jest-fetch-mock'); 2 | 3 | window.fetch = global.fetch; 4 | 5 | require('dotenv').config('../../.env'); 6 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Development folders and files # 4 | ################################# 5 | .tmp/ 6 | node_modules/ 7 | package.json 8 | .travis.yml 9 | *.md -------------------------------------------------------------------------------- /packages/harmony-crypto/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.json", 3 | "include": ["src", "test", "../../typings/**/*.d.ts"], 4 | "references": [] 5 | } 6 | -------------------------------------------------------------------------------- /packages/harmony-utils/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.json", 3 | "include": ["src", "test", "../../typings/**/*.d.ts"], 4 | "references": [] 5 | } 6 | -------------------------------------------------------------------------------- /packages/harmony-account/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.json", 3 | "include": ["src", "__test__", "../../typings/**/*.d.ts"], 4 | "references": [] 5 | } 6 | -------------------------------------------------------------------------------- /packages/harmony-core/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.json", 3 | "include": ["src", "__test__", "../../typings/**/*.d.ts"], 4 | "references": [] 5 | } 6 | -------------------------------------------------------------------------------- /packages/harmony-network/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.json", 3 | "include": ["src", "__test__", "../../typings/**/*.d.ts"], 4 | "references": [] 5 | } 6 | -------------------------------------------------------------------------------- /packages/harmony-staking/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.json", 3 | "include": ["src", "test", "../../typings/**/*.d.ts"], 4 | "references": [] 5 | } 6 | -------------------------------------------------------------------------------- /packages/harmony-contract/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.json", 3 | "include": ["src", "__test__", "../../typings/**/*.d.ts"], 4 | "references": [] 5 | } 6 | -------------------------------------------------------------------------------- /scripts/jest/jest.framework-setup.js: -------------------------------------------------------------------------------- 1 | const { matchersWithOptions } = require('jest-json-schema') 2 | 3 | expect.extend(matchersWithOptions({ allErrors: true })) 4 | jest.setTimeout(180000) 5 | -------------------------------------------------------------------------------- /scripts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "module": "commonjs", 5 | "target": "es2015", 6 | "resolveJsonModule": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/harmony-transaction/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.test.json", 3 | "include": ["src", "test", "../../typings/**/*.d.ts", "src/types"], 4 | "references": [] 5 | } 6 | -------------------------------------------------------------------------------- /packages/harmony-staking/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-staking 4 | * @ignore 5 | */ 6 | 7 | export * from './stakingTransaction'; 8 | export * from './factory'; 9 | -------------------------------------------------------------------------------- /packages/harmony-utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | }, 7 | "include": ["src", "../../typings/**/*.d.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/harmony-crypto/src/signature.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 suwei 2 | // 3 | // This software is released under the MIT License. 4 | // https://opensource.org/licenses/MIT 5 | 6 | /** 7 | * @packageDocumentation 8 | * @ignore 9 | */ 10 | -------------------------------------------------------------------------------- /typings/scrypt.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'scrypt.js' { 2 | export default function syncScrypt( 3 | password: ArrayLike, 4 | salt: ArrayLike, 5 | N: number, 6 | r: number, 7 | p: number, 8 | dkLen: number, 9 | ): Buffer; 10 | } 11 | -------------------------------------------------------------------------------- /scripts/packagesTs.ts: -------------------------------------------------------------------------------- 1 | const packages = [ 2 | 'harmony-utils', 3 | 'harmony-crypto', 4 | 'harmony-account', 5 | 'harmony-network', 6 | 'harmony-transaction', 7 | 'harmony-staking', 8 | 'harmony-contract', 9 | 'harmony-core', 10 | ]; 11 | 12 | export { packages }; 13 | -------------------------------------------------------------------------------- /packages/harmony-account/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-account 4 | * @ignore 5 | */ 6 | 7 | export * from './account'; 8 | export * from './wallet'; 9 | export * from './types'; 10 | export * from './utils'; 11 | export * from './hdnode'; 12 | -------------------------------------------------------------------------------- /packages/harmony-crypto/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | }, 7 | "include": ["src", "../../typings/**/*.d.ts"], 8 | "references": [{"path": "../harmony-utils"}] 9 | } 10 | -------------------------------------------------------------------------------- /packages/harmony-network/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | }, 7 | "include": ["src", "../../typings/**/*.d.ts"], 8 | "references": [{"path": "../harmony-utils"}] 9 | } 10 | -------------------------------------------------------------------------------- /packages/harmony-utils/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-utils 4 | * @ignore 5 | */ 6 | 7 | export * from './validators'; 8 | export * from './transformers'; 9 | export * from './utils'; 10 | export * from './chain'; 11 | export * from './tools'; 12 | -------------------------------------------------------------------------------- /packages/harmony-core/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-core 4 | * @hidden 5 | */ 6 | 7 | export * from './harmony'; 8 | export * from './blockchain'; 9 | export * from './truffleProvider'; 10 | export * from './harmonyExtension'; 11 | export * from './types'; 12 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/abi/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * @hidden 5 | */ 6 | 7 | import { AbiCoderClass } from './api'; 8 | import { AbiCoder as EtherCoder } from './abiCoder'; 9 | 10 | export function AbiCoder() { 11 | return new AbiCoderClass(new EtherCoder()); 12 | } 13 | -------------------------------------------------------------------------------- /packages/harmony-utils/src/tools.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-utils 4 | * @hidden 5 | */ 6 | 7 | export function defineReadOnly(object: any, name: string, value: any): void { 8 | Object.defineProperty(object, name, { 9 | enumerable: true, 10 | value, 11 | writable: false, 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * @hidden 5 | */ 6 | 7 | export * from './abi/index'; 8 | export { toUtf8Bytes, toUtf8String, formatBytes32String, parseBytes32String } from './abi/abiCoder'; 9 | 10 | export { Contract } from './contract'; 11 | export { ContractFactory } from './contractFactory'; 12 | -------------------------------------------------------------------------------- /packages/harmony-account/src/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-account 4 | * @hidden 5 | */ 6 | 7 | /** 8 | * test type docs 9 | */ 10 | export type ShardID = string | number; 11 | export interface BalanceObject { 12 | address: string; 13 | balance: string; 14 | nonce: number; 15 | } 16 | export type Shards = Map; 17 | -------------------------------------------------------------------------------- /packages/harmony-transaction/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | }, 7 | "include": ["src", "../../typings/**/*.d.ts"], 8 | "references": [ 9 | {"path": "../harmony-utils"}, 10 | {"path": "../harmony-crypto"}, 11 | {"path": "../harmony-network"} 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/harmony-transaction/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-transaction 4 | * @hidden 5 | */ 6 | 7 | export * from './factory'; 8 | export * from './transaction'; 9 | export * from './shardingTransaction'; 10 | export * from './types'; 11 | export * from './utils'; 12 | export * from './transactionBase'; 13 | export * from './abstractTransaction'; 14 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/utils/status.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * @hidden 5 | */ 6 | 7 | export enum ContractStatus { 8 | INITIALISED = 'initialised', 9 | TESTED = 'tested', 10 | ERROR = 'error', 11 | SIGNED = 'signed', 12 | SENT = 'sent', 13 | REJECTED = 'rejected', 14 | DEPLOYED = 'deployed', 15 | CALLED = 'called', 16 | } 17 | -------------------------------------------------------------------------------- /packages/harmony-account/src/utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-account 4 | * @hidden 5 | */ 6 | 7 | import { HttpProvider, Messenger } from '@harmony-js/network'; 8 | import { ChainType, ChainID } from '@harmony-js/utils'; 9 | 10 | export const defaultMessenger = new Messenger( 11 | new HttpProvider('http://localhost:9500'), 12 | ChainType.Harmony, 13 | ChainID.HmyLocal, 14 | ); 15 | -------------------------------------------------------------------------------- /packages/harmony-staking/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | }, 7 | "include": ["src", "../../typings/**/*.d.ts"], 8 | "references": [ 9 | { "path": "../harmony-utils" }, 10 | { "path": "../harmony-crypto" }, 11 | { "path": "../harmony-network" }, 12 | { "path": "../harmony-transaction" } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /packages/harmony-crypto/test/keccak256.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @ignore 4 | */ 5 | 6 | import * as hash from '../src/keccak256'; 7 | 8 | import hashes from './fixtures/hashes.json'; 9 | 10 | describe('should test keccak256', () => { 11 | it('should test keccak256 hashing', () => { 12 | hashes.forEach((testcase) => { 13 | expect(hash.keccak256(testcase.data)).toEqual(testcase.keccak256); 14 | }); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "typescript", 3 | "printWidth": 100, 4 | "singleQuote": true, 5 | "bracketSpacing": true, 6 | "trailingComma": "all", 7 | "arrowParens": "always", 8 | "overrides": [ 9 | { 10 | "files": "*.json", 11 | "options": { 12 | "parser": "json" 13 | } 14 | }, 15 | { 16 | "files": ".prettierrc", 17 | "options": { 18 | "parser": "json" 19 | } 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /packages/harmony-contract/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | }, 7 | "include": ["src", "../../typings/**/*.d.ts"], 8 | "references": [ 9 | {"path": "../harmony-account"}, 10 | {"path": "../harmony-crypto"}, 11 | {"path": "../harmony-utils"}, 12 | {"path": "../harmony-transaction"}, 13 | {"path": "../harmony-network"} 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /packages/harmony-account/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | }, 7 | "include": ["src", "../../typings/**/*.d.ts", "aaa.ts"], 8 | "references": [ 9 | { "path": "../harmony-crypto" }, 10 | { "path": "../harmony-utils" }, 11 | { "path": "../harmony-transaction" }, 12 | { "path": "../harmony-staking" }, 13 | { "path": "../harmony-network" } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /typings/aes-js.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'aes-js' { 2 | export class Counter { 3 | constructor(iv: Buffer); 4 | setValue(value: number): void; 5 | setBytes(bytes: Array | Buffer | string): void; 6 | increment(): void; 7 | } 8 | 9 | class CTR { 10 | constructor(derivedKey: Buffer, iv: Counter); 11 | encrypt(bytes: Buffer): Uint8Array; 12 | decrypt(bytes: Buffer): Uint8Array; 13 | } 14 | 15 | export const ModeOfOperation: { ctr: typeof CTR }; 16 | } 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "packages/harmony-utils" }, 5 | { "path": "packages/harmony-crypto" }, 6 | { "path": "packages/harmony-network" }, 7 | { "path": "packages/harmony-transaction" }, 8 | { "path": "packages/harmony-staking" }, 9 | { "path": "packages/harmony-account" }, 10 | { "path": "packages/harmony-contract" }, 11 | { "path": "packages/harmony-core" } 12 | ], 13 | "toc": ["harmony-account", "harmony-core"] 14 | } 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: true 3 | dist: trusty 4 | node_js: 5 | - 16 6 | branches: 7 | except: 8 | - /^v[0-9]/ 9 | install: 10 | - yarn 11 | - yarn bootstrap 12 | script: 13 | - yarn test:src 14 | - yarn dist 15 | cache: 16 | directories: 17 | - '$HOME/.yarn-cache' 18 | deploy: 19 | provider: pages 20 | skip-cleanup: true 21 | github-token: $GITHUB_TOKEN # Set in the settings page of your repository, as a secure variable 22 | keep-history: true 23 | on: 24 | branch: master 25 | 26 | -------------------------------------------------------------------------------- /packages/harmony-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | }, 7 | "include": ["src", "../../typings/**/*.d.ts", "../harmony-utils/src/core.ts"], 8 | "references": [ 9 | {"path": "../harmony-account"}, 10 | {"path": "../harmony-crypto"}, 11 | {"path": "../harmony-utils"}, 12 | {"path": "../harmony-network"}, 13 | {"path": "../harmony-transaction"}, 14 | {"path": "../harmony-contract"} 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/utils/options.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * @hidden 5 | */ 6 | 7 | export interface ContractOptions { 8 | data?: string; 9 | shardID?: number; 10 | address?: string; 11 | defaultAccount?: string; 12 | defaultBlock?: string; 13 | defaultGas?: string; 14 | defaultGasPrice?: string; 15 | transactionBlockTimeout?: number; 16 | transactionConfirmationBlocks?: string; 17 | transactionPollingTimeout?: number; 18 | transactionSigner?: any; 19 | } 20 | -------------------------------------------------------------------------------- /tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "files": [], 4 | "include": ["./typings/**/*.d.ts"], 5 | "references": [ 6 | { "path": "packages/harmony-utils" }, 7 | { "path": "packages/harmony-crypto" }, 8 | { "path": "packages/harmony-network" }, 9 | { "path": "packages/harmony-transaction" }, 10 | { "path": "packages/harmony-staking" }, 11 | { "path": "packages/harmony-account" }, 12 | { "path": "packages/harmony-contract" }, 13 | { "path": "packages/harmony-core" } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/contractFactory.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | */ 5 | 6 | import { Wallet } from '@harmony-js/account'; 7 | import { Contract } from './contract'; 8 | import { ContractOptions } from './utils/options'; 9 | 10 | export class ContractFactory { 11 | wallet: Wallet | any; 12 | 13 | constructor(wallet: Wallet | any) { 14 | this.wallet = wallet; 15 | } 16 | createContract(abi: any[], address?: string, options?: ContractOptions) { 17 | return new Contract(abi, address, options, this.wallet); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/harmony-crypto/test/rlp.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @ignore 4 | */ 5 | 6 | import * as rlp from '../src/rlp'; 7 | import cases from './fixtures/rlpcoder.json'; 8 | 9 | describe('rlp', () => { 10 | it('should test rlp encoder', () => { 11 | cases.forEach((testcase) => { 12 | expect(rlp.encode(testcase.decoded)).toEqual(testcase.encoded); 13 | }); 14 | }); 15 | it('should test rlp decoder', () => { 16 | cases.forEach((testcase) => { 17 | expect(rlp.decode(testcase.encoded)).toEqual(testcase.decoded); 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/harmony-crypto/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-crypto 4 | * @ignore 5 | */ 6 | 7 | import hdkey from 'hdkey'; 8 | import bip39 from 'bip39'; 9 | import BN from 'bn.js'; 10 | 11 | export * from './random'; 12 | export * from './keyTool'; 13 | export * from './keystore'; 14 | export * from './bytes'; 15 | export * from './rlp'; 16 | export * from './keccak256'; 17 | export * from './errors'; 18 | export * from './bech32'; 19 | 20 | // export types 21 | export * from './types'; 22 | export * from './address'; 23 | 24 | export { hdkey, bip39, BN }; 25 | -------------------------------------------------------------------------------- /packages/harmony-network/src/subscriptions/NewPendingTransactionsSub.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | */ 5 | 6 | import { Messenger } from '../messenger/messenger'; 7 | import { SubscriptionMethod } from './Subscription'; 8 | 9 | /** 10 | * ### Description: 11 | * Subscribes to incoming pending transactions 12 | */ 13 | export class NewPendingTransactions extends SubscriptionMethod { 14 | constructor(messenger: Messenger, shardID: number = 0) { 15 | super('newPendingTransactions', undefined, messenger, shardID); 16 | this.start(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/harmony-network/src/subscriptions/NewHeadersSub.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | */ 5 | 6 | import { Messenger } from '../messenger/messenger'; 7 | import { SubscriptionMethod } from './Subscription'; 8 | 9 | /** 10 | * ### Description: 11 | * Subscribes to incoming block headers. This can be used as timer to check for changes on the blockchain. 12 | */ 13 | export class NewHeaders extends SubscriptionMethod { 14 | constructor(messenger: Messenger, shardID: number = 0) { 15 | super('newHeads', undefined, messenger, shardID); 16 | this.start(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scripts/webpack.ts: -------------------------------------------------------------------------------- 1 | // tslint:disable-next-line: no-implicit-dependencies 2 | import webpack from 'webpack'; 3 | // tslint:disable-next-line: no-implicit-dependencies 4 | 5 | import batch from './webpack/webpack.config'; 6 | 7 | webpack(batch).run((err, stats) => { 8 | if (err) { 9 | console.error(err); 10 | return; 11 | } 12 | console.log( 13 | stats.toString({ 14 | all: false, 15 | modules: false, 16 | errors: true, 17 | warnings: false, 18 | moduleTrace: true, 19 | errorDetails: true, 20 | chunks: true, 21 | colors: true, 22 | }), 23 | ); 24 | }); 25 | -------------------------------------------------------------------------------- /e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src", 6 | "declarationDir": "dist", 7 | "resolveJsonModule": true, 8 | "esModuleInterop": true 9 | }, 10 | "include": ["src", "../typings/**/*.d.ts", "fixtures"], 11 | "references": [ 12 | { "path": "../packages/harmony-account" }, 13 | { "path": "../packages/harmony-crypto" }, 14 | { "path": "../packages/harmony-utils" }, 15 | { "path": "../packages/harmony-network" }, 16 | { "path": "../packages/harmony-transaction" }, 17 | { "path": "../packages/harmony-contract" } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /scripts/webpack/packagesForWP.ts: -------------------------------------------------------------------------------- 1 | // tslint:disable-next-line: no-implicit-dependencies 2 | import camelCase from 'camelcase'; 3 | import {packages} from '../packagesTs'; 4 | 5 | export interface PackageItem { 6 | name: string; 7 | dest: string; 8 | } 9 | 10 | function generatePackageList(rawArray: string[]): PackageItem[] { 11 | const resultArray: PackageItem[] = []; 12 | for (const item of rawArray) { 13 | const name = camelCase(item) 14 | .replace('har', 'Har') 15 | .replace('Core', 'Js'); 16 | const dest = item; 17 | resultArray.push({name, dest}); 18 | } 19 | return resultArray; 20 | } 21 | 22 | export const packageList = generatePackageList(packages); 23 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "baseUrl": ".", 5 | "composite": true, 6 | "declaration": true, 7 | "declarationMap": true, 8 | "downlevelIteration": true, 9 | "emitDecoratorMetadata": true, 10 | "esModuleInterop": true, 11 | "experimentalDecorators": true, 12 | "preserveConstEnums": true, 13 | "importHelpers": true, 14 | "lib": ["esnext", "dom"], 15 | "module": "commonjs", 16 | "moduleResolution": "node", 17 | "sourceMap": true, 18 | "paths": { 19 | "*": ["typings/*", "includes/*"] 20 | }, 21 | "resolveJsonModule": true, 22 | "noUnusedLocals": true, 23 | "strict": true, 24 | "target": "es5" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/harmony-utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@harmony-js/utils", 3 | "version": "0.1.58", 4 | "description": "utils for harmony", 5 | "main": "dist/index.js", 6 | "node": "dist/index.js", 7 | "browser": "dist/index.js", 8 | "module": "dist/index.esm.js", 9 | "jsnext:main": "dist/index.esm.js", 10 | "typings": "dist/index.d.ts", 11 | "types": "dist/index.d.ts", 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "publishConfig": { 16 | "access": "public" 17 | }, 18 | "author": "neeboo@firestack.one", 19 | "license": "MIT", 20 | "dependencies": { 21 | "@types/bn.js": "^4.11.3", 22 | "bn.js": "^4.11.8" 23 | }, 24 | "gitHead": "56606e9365721729a490c27d6a294e0daf90fbdf" 25 | } 26 | -------------------------------------------------------------------------------- /packages/harmony-crypto/src/keccak256.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-crypto 4 | * @ignore 5 | */ 6 | 7 | // this file is ported from 'ether.js' and done some fixes 8 | import * as sha3 from 'js-sha3'; 9 | 10 | import { arrayify, Arrayish } from './bytes'; 11 | 12 | export function keccak256(data: Arrayish): string { 13 | const arrayified = arrayify(data); 14 | if (arrayified) { 15 | return '0x' + sha3.keccak_256(arrayified); 16 | } 17 | throw new Error('arrayify failed'); 18 | } 19 | 20 | // export function sha3_256(data: Arrayish): string { 21 | // const arrayified = arrayify(data); 22 | // if (arrayified) { 23 | // return '0x' + sha3.sha3_256(arrayified); 24 | // } 25 | // throw new Error('arrayify failed'); 26 | // } 27 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:latest", "tslint-config-prettier"], 3 | "rules": { 4 | "interface-name": [true, "never-prefix"], 5 | "member-access": false, 6 | "no-angle-bracket-type-assertion": false, 7 | "no-bitwise": false, 8 | "no-console": false, 9 | "no-default-export": true, 10 | "no-empty-interface": false, 11 | "no-implicit-dependencies": true, 12 | "no-submodule-imports": false, 13 | "ordered-imports": [false], 14 | "object-literal-sort-keys": false, 15 | "object-literal-key-quotes": [true, "as-needed"], 16 | "quotemark": [true, "single"], 17 | "semicolon": [true, "always", "ignore-bound-class-methods"], 18 | "jsx-boolean-value": false 19 | }, 20 | "linterOptions": { 21 | "exclude": ["config/**/*.js", "node_modules/**/*.ts"] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/harmony-network/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@harmony-js/network", 3 | "version": "0.1.58", 4 | "description": "network suites for harmony", 5 | "main": "dist/index.js", 6 | "node": "dist/index.js", 7 | "browser": "dist/index.js", 8 | "module": "dist/index.esm.js", 9 | "jsnext:main": "dist/index.esm.js", 10 | "typings": "dist/index.d.ts", 11 | "types": "dist/index.d.ts", 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "publishConfig": { 16 | "access": "public" 17 | }, 18 | "author": "neeboo@firestack.one", 19 | "license": "MIT", 20 | "dependencies": { 21 | "@harmony-js/utils": "0.1.58", 22 | "cross-fetch": "^3.0.2", 23 | "mitt": "^1.2.0", 24 | "websocket": "^1.0.28" 25 | }, 26 | "gitHead": "56606e9365721729a490c27d6a294e0daf90fbdf" 27 | } 28 | -------------------------------------------------------------------------------- /packages/harmony-transaction/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@harmony-js/transaction", 3 | "version": "0.1.58", 4 | "description": "transaction package for harmony", 5 | "main": "dist/index.js", 6 | "node": "dist/index.js", 7 | "browser": "dist/index.js", 8 | "module": "dist/index.esm.js", 9 | "jsnext:main": "dist/index.esm.js", 10 | "typings": "dist/index.d.ts", 11 | "types": "dist/index.d.ts", 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "publishConfig": { 16 | "access": "public" 17 | }, 18 | "author": "neeboo@firestack.one", 19 | "license": "MIT", 20 | "dependencies": { 21 | "@harmony-js/crypto": "0.1.58", 22 | "@harmony-js/network": "0.1.58", 23 | "@harmony-js/utils": "0.1.58" 24 | }, 25 | "gitHead": "56606e9365721729a490c27d6a294e0daf90fbdf" 26 | } 27 | -------------------------------------------------------------------------------- /packages/harmony-core/src/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-core 4 | * @hidden 5 | */ 6 | 7 | import { HttpProvider, Messenger } from '@harmony-js/network'; 8 | import { TransactionFactory, Transaction } from '@harmony-js/transaction'; 9 | import { Wallet, Account } from '@harmony-js/account'; 10 | import { ChainType, ChainID } from '@harmony-js/utils'; 11 | import { Blockchain } from './blockchain'; 12 | 13 | export interface HarmonyModule { 14 | HttpProvider: HttpProvider; 15 | Messenger: Messenger; 16 | Blockchain: Blockchain; 17 | TransactionFactory: TransactionFactory; 18 | Wallet: Wallet; 19 | Transaction: Transaction; 20 | Account: Account; 21 | } 22 | 23 | export enum UrlType { 24 | http, 25 | ws, 26 | } 27 | 28 | export interface HarmonySetting { 29 | type: T; 30 | id: I; 31 | } 32 | -------------------------------------------------------------------------------- /scripts/jest/jest.e2e.config.js: -------------------------------------------------------------------------------- 1 | const baseConfig = require('./jest.src.config'); 2 | module.exports = { 3 | ...baseConfig, 4 | moduleNameMapper: { 5 | '^@harmony-js/(.*)$': '/packages/harmony-$1/src/index.ts', 6 | 'cross-fetch': 'jest-fetch-mock', 7 | }, 8 | setupTestFrameworkScriptFile: '/scripts/jest/jest.framework-setup.js', 9 | testMatch: ['/e2e/src/?(*.)+(spec|test|e2e).ts'], 10 | coverageThreshold: { 11 | global: { 12 | branches: 10, 13 | functions: 10, 14 | lines: 10, 15 | statements: 10, 16 | }, 17 | }, 18 | collectCoverageFrom: [ 19 | // 'packages/!(harmony-core)/src/**/*.ts', 20 | 'packages/harmony-core/src/**/*.ts', 21 | 'packages/harmony-utils/src/**/*.ts', 22 | 'packages/harmony-crypto/src/**/*.ts', 23 | 'packages/harmony-transaction/src/**/*.ts', 24 | ], 25 | automock: false, 26 | }; 27 | -------------------------------------------------------------------------------- /packages/harmony-staking/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@harmony-js/staking", 3 | "version": "0.1.58", 4 | "description": "staking transaction package for harmony", 5 | "main": "dist/index.js", 6 | "node": "dist/index.js", 7 | "browser": "dist/index.js", 8 | "module": "dist/index.esm.js", 9 | "jsnext:main": "dist/index.esm.js", 10 | "typings": "dist/index.d.ts", 11 | "types": "dist/index.d.ts", 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "publishConfig": { 16 | "access": "public" 17 | }, 18 | "author": "", 19 | "license": "MIT", 20 | "dependencies": { 21 | "@harmony-js/crypto": "0.1.58", 22 | "@harmony-js/network": "0.1.58", 23 | "@harmony-js/transaction": "0.1.58", 24 | "@harmony-js/utils": "0.1.58", 25 | "text-encoding": "^0.7.0" 26 | }, 27 | "gitHead": "56606e9365721729a490c27d6a294e0daf90fbdf" 28 | } 29 | -------------------------------------------------------------------------------- /packages/harmony-crypto/src/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-crypto 4 | * @ignore 5 | */ 6 | 7 | export type KDF = 'pbkdf2' | 'scrypt'; 8 | 9 | export interface PBKDF2Params { 10 | salt: string; 11 | dklen: number; 12 | c: number; 13 | } 14 | 15 | export interface ScryptParams { 16 | salt: string; 17 | dklen: number; 18 | n: number; 19 | r: number; 20 | p: number; 21 | } 22 | 23 | export type KDFParams = PBKDF2Params | ScryptParams; 24 | 25 | export interface EncryptOptions { 26 | kdf?: KDF; 27 | level?: number; 28 | uuid?: number[]; 29 | } 30 | 31 | export interface Keystore { 32 | address?: string; 33 | crypto: { 34 | cipher: string; 35 | cipherparams: { 36 | iv: string; 37 | }; 38 | ciphertext: string; 39 | kdf: KDF; 40 | kdfparams: KDFParams; 41 | mac: string; 42 | }; 43 | id: string; 44 | version: 3; 45 | } 46 | -------------------------------------------------------------------------------- /packages/harmony-contract/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@harmony-js/contract", 3 | "version": "0.1.58", 4 | "description": "contract libraries for harmony", 5 | "main": "dist/index.js", 6 | "node": "dist/index.js", 7 | "browser": "dist/index.js", 8 | "module": "dist/index.esm.js", 9 | "jsnext:main": "dist/index.esm.js", 10 | "typings": "dist/index.d.ts", 11 | "types": "dist/index.d.ts", 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "author": "neeboo@firestack.one", 16 | "publishConfig": { 17 | "access": "public" 18 | }, 19 | "license": "MIT", 20 | "dependencies": { 21 | "@harmony-js/account": "0.1.58", 22 | "@harmony-js/crypto": "0.1.58", 23 | "@harmony-js/network": "0.1.58", 24 | "@harmony-js/transaction": "0.1.58", 25 | "@harmony-js/utils": "0.1.58" 26 | }, 27 | "gitHead": "56606e9365721729a490c27d6a294e0daf90fbdf" 28 | } 29 | -------------------------------------------------------------------------------- /packages/README.md: -------------------------------------------------------------------------------- 1 | # Packages available are: 2 | 3 | 1. [@harmony-js/core](https://github.com/harmony-one/sdk/tree/master/packages/harmony-core) 4 | 2. [@harmony-js/account](https://github.com/harmony-one/sdk/tree/master/packages/harmony-account) 5 | 3. [@harmony-js/crypto](https://github.com/harmony-one/sdk/tree/master/packages/harmony-crypto) 6 | 4. [@harmony-js/network](https://github.com/harmony-one/sdk/tree/master/packages/harmony-network) 7 | 5. [@harmony-js/utils](https://github.com/harmony-one/sdk/tree/master/packages/harmony-utils) 8 | 6. [@harmony-js/transaction](https://github.com/harmony-one/sdk/tree/master/packages/harmony-transaction) 9 | 7. [@harmony-js/contract](https://github.com/harmony-one/sdk/tree/master/packages/harmony-contract) 10 | 8. [@harmony-js/staking](https://github.com/harmony-one/sdk/tree/master/packages/harmony-staking) 11 | 12 | Package level documentation and examples are inside each package -------------------------------------------------------------------------------- /scripts/typedoc/batch.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | // tslint:disable-next-line: no-implicit-dependencies no-var-requires 3 | const {Application} = require('typedoc'); 4 | // tslint:disable-next-line: no-implicit-dependencies no-var-requires 5 | const arg = require('arg'); 6 | 7 | const args = arg({ 8 | '--pkgPath': String, 9 | '-p': '--pkgPath', 10 | '--pkgSrc': String, 11 | '-s': '--pkgSrc', 12 | '--target': String, 13 | '-t': '--target', 14 | }); 15 | 16 | const pkgSrc = args['--pkgSrc']; 17 | const pkgPath = args['--pkgPath']; 18 | const target = args['--target']; 19 | 20 | const app = new Application({ 21 | mode: 'file', 22 | tsconfig: `tsconfig.json`, 23 | theme: target === 'default' ? 'default' : 'markdown', 24 | plugin: path.resolve('node_modules/typedoc-plugin-markdown'), 25 | platform: target, 26 | }); 27 | 28 | const files = [...app.expandInputFiles([pkgSrc])]; 29 | 30 | console.log(files); 31 | -------------------------------------------------------------------------------- /packages/harmony-account/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@harmony-js/account", 3 | "version": "0.1.58", 4 | "description": "account and wallet for harmony", 5 | "main": "dist/index.js", 6 | "node": "dist/index.js", 7 | "browser": "dist/index.js", 8 | "module": "dist/index.esm.js", 9 | "jsnext:main": "dist/index.esm.js", 10 | "typings": "dist/index.d.ts", 11 | "types": "dist/index.d.ts", 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "publishConfig": { 16 | "access": "public" 17 | }, 18 | "author": "neeboo@firestack.one", 19 | "license": "MIT", 20 | "dependencies": { 21 | "@harmony-js/core": "0.1.58", 22 | "@harmony-js/crypto": "0.1.58", 23 | "@harmony-js/network": "0.1.58", 24 | "@harmony-js/staking": "0.1.58", 25 | "@harmony-js/transaction": "0.1.58", 26 | "@harmony-js/utils": "0.1.58" 27 | }, 28 | "gitHead": "56606e9365721729a490c27d6a294e0daf90fbdf" 29 | } 30 | -------------------------------------------------------------------------------- /packages/harmony-core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@harmony-js/core", 3 | "version": "0.1.58", 4 | "description": "harmony core package", 5 | "main": "dist/index.js", 6 | "node": "dist/index.js", 7 | "browser": "dist/index.js", 8 | "module": "dist/index.esm.js", 9 | "jsnext:main": "dist/index.esm.js", 10 | "typings": "dist/index.d.ts", 11 | "types": "dist/index.d.ts", 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "publishConfig": { 16 | "access": "public" 17 | }, 18 | "author": "neeboo@firestack.one", 19 | "license": "MIT", 20 | "dependencies": { 21 | "@harmony-js/account": "0.1.58", 22 | "@harmony-js/contract": "0.1.58", 23 | "@harmony-js/crypto": "0.1.58", 24 | "@harmony-js/network": "0.1.58", 25 | "@harmony-js/staking": "0.1.58", 26 | "@harmony-js/transaction": "0.1.58", 27 | "@harmony-js/utils": "0.1.58" 28 | }, 29 | "gitHead": "56606e9365721729a490c27d6a294e0daf90fbdf" 30 | } 31 | -------------------------------------------------------------------------------- /packages/harmony-crypto/src/random.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-crypto 4 | */ 5 | 6 | /** 7 | * Uses JS-native CSPRNG to generate a specified number of bytes. 8 | * @NOTE 9 | * this method throws if no PRNG is available. 10 | * @param {Number} bytes bytes number to generate 11 | * @return {String} ramdom hex string 12 | */ 13 | export const randomBytes = (bytes: number): string => { 14 | let randBz: number[] | Uint8Array; 15 | 16 | if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) { 17 | randBz = window.crypto.getRandomValues(new Uint8Array(bytes)); 18 | } else if (typeof require !== 'undefined') { 19 | randBz = require('crypto').randomBytes(bytes); 20 | } else { 21 | throw new Error('Unable to generate safe random numbers.'); 22 | } 23 | 24 | let randStr = ''; 25 | for (let i = 0; i < bytes; i += 1) { 26 | randStr += `00${randBz[i].toString(16)}`.slice(-2); 27 | } 28 | 29 | return randStr; 30 | }; 31 | -------------------------------------------------------------------------------- /packages/harmony-network/src/util.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | * @hidden 5 | */ 6 | 7 | import { ResponseMiddleware } from './messenger/responseMiddleware'; 8 | 9 | /** 10 | * @function getResultForData 11 | * @description get result for data by default 12 | * @param {any} data - object get from provider 13 | * @return {any} data result or data 14 | */ 15 | export function getResultForData(data: any): any { 16 | if (data.result) { 17 | return data.getResult; 18 | } 19 | if (data.error) { 20 | return data.getError; 21 | } 22 | return data.getRaw; 23 | } 24 | 25 | export function getRawForData(data: any): any { 26 | return data.getRaw; 27 | } 28 | 29 | export function onResponse(response: ResponseMiddleware) { 30 | if (response.responseType === 'result') { 31 | return response.getResult; 32 | } else if (response.responseType === 'error') { 33 | return response.getError; 34 | } else { 35 | return response.raw; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/harmony-network/README.md: -------------------------------------------------------------------------------- 1 | # @harmony-js/network 2 | 3 | This package provides a collection of apis to create messengers (HTTP, WebSocket) to connect to blockchain networks. 4 | 5 | ## Installation 6 | 7 | ``` 8 | npm install @harmony-js/network 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```javascript 14 | const { Messenger, HttpProvider, WSProvider } = require('@harmony-js/network'); 15 | const { ChainID, ChainType } = require('@harmony-js/utils'); 16 | const testnetHTTP = 'https://api.s0.b.hmny.io'; 17 | const testnetWS = 'wss://ws.s0.b.hmny.io'; 18 | const localHTTP = 'http://localhost:9500/'; 19 | const localWS = 'http://localhost:9800/'; 20 | const http = new HttpProvider(testnetHTTP); // for local use localHTTP 21 | const ws = new WSProvider(testnetWS); // for local use testnetWS 22 | const customHTTPMessenger = new Messenger(http, ChainType.Harmony, ChainID.HmyTestnet); // for local ChainID.HmyLocal 23 | const customWSMessenger = new Messenger(ws, ChainType.Harmony, ChainID.HmyTestnet); // for local ChainID.HmyLocal 24 | ``` -------------------------------------------------------------------------------- /packages/harmony-crypto/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@harmony-js/crypto", 3 | "version": "0.1.58", 4 | "description": "crypto libraries for harmony", 5 | "main": "dist/index.js", 6 | "node": "dist/index.js", 7 | "browser": "dist/index.js", 8 | "module": "dist/index.esm.js", 9 | "jsnext:main": "dist/index.esm.js", 10 | "typings": "dist/index.d.ts", 11 | "types": "dist/index.d.ts", 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "author": "neeboo@firestack.one", 16 | "publishConfig": { 17 | "access": "public" 18 | }, 19 | "license": "MIT", 20 | "dependencies": { 21 | "@harmony-js/utils": "0.1.58", 22 | "aes-js": "^3.1.2", 23 | "bip39": "^2.5.0", 24 | "bn.js": "^4.11.8", 25 | "elliptic": "^6.4.1", 26 | "hdkey": "^1.1.1", 27 | "hmac-drbg": "^1.0.1", 28 | "js-sha3": "^0.8.0", 29 | "pbkdf2": "^3.0.17", 30 | "scrypt.js": "^0.3.0", 31 | "uuid": "^3.3.2" 32 | }, 33 | "gitHead": "56606e9365721729a490c27d6a294e0daf90fbdf" 34 | } 35 | -------------------------------------------------------------------------------- /packages/harmony-network/src/providers/defaultFetcher.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | * @hidden 5 | */ 6 | 7 | import fetch from 'cross-fetch'; 8 | import { RPCRequest, RPCResponseBody, RPCError, RPCResult } from '../types'; 9 | 10 | export const fetchRPC = { 11 | requestHandler: (request: RPCRequest, headers: any) => 12 | fetch(request.url, { 13 | method: request.options && request.options.method ? request.options.method : 'POST', 14 | cache: 'no-cache', 15 | mode: 'cors', 16 | redirect: 'follow', 17 | referrer: 'no-referrer', 18 | body: JSON.stringify(request.payload), 19 | headers: { 20 | ...headers, 21 | ...(request.options && request.options.headers ? request.options.headers : {}), 22 | }, 23 | }), 24 | responseHandler: (response: Response, request: RPCRequest, handler: any) => 25 | response 26 | .json() 27 | .then((body: RPCResponseBody) => { 28 | return { ...body, req: request }; 29 | }) 30 | .then(handler), 31 | }; 32 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/utils/decoder.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * @hidden 5 | */ 6 | 7 | import { AbiItemModel } from '../models/types'; 8 | import { AbiCoderClass } from '../abi/api'; 9 | 10 | export const decode = (abiCoder: AbiCoderClass, abiItemModel: AbiItemModel, response: any) => { 11 | let argumentTopics = response.topics; 12 | 13 | if (!abiItemModel.anonymous) { 14 | argumentTopics = response.topics.slice(1); 15 | } 16 | 17 | if (response.data === '0x') { 18 | response.data = null; 19 | } 20 | 21 | response.returnValues = abiCoder.decodeLog( 22 | abiItemModel.getInputs(), 23 | response.data, 24 | argumentTopics, 25 | ); 26 | response.event = abiItemModel.name; 27 | response.signature = abiItemModel.signature; 28 | response.raw = { 29 | data: response.data, 30 | topics: response.topics, 31 | }; 32 | 33 | if (abiItemModel.anonymous || !response.topics[0]) { 34 | response.signature = null; 35 | } 36 | 37 | delete response.data; 38 | delete response.topics; 39 | 40 | return response; 41 | }; 42 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const { task, src } = require('gulp'); 2 | const del = require('del'); 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | 6 | const packages = [ 7 | 'harmony-core', 8 | 'harmony-crypto', 9 | 'harmony-account', 10 | 'harmony-network', 11 | 'harmony-contract', 12 | 'harmony-utils', 13 | 'harmony-transaction', 14 | 'harmony-staking', 15 | ]; 16 | 17 | task('cleanBrowser', async () => { 18 | await packages.map((p) => { 19 | const pathToLib = `packages/${p}/lib`; 20 | return del.sync([pathToLib]); 21 | }); 22 | }); 23 | 24 | task('cleanServer', async () => { 25 | await packages.map((p) => { 26 | const pathToLib = `packages/${p}/dist`; 27 | return del.sync([pathToLib]); 28 | }); 29 | }); 30 | 31 | task('cleanUnexpected', async () => { 32 | await packages.map((p) => { 33 | const pathToLib = `packages/${p}/tsconfig.tsbuildinfo`; 34 | return del.sync([pathToLib]); 35 | }); 36 | }); 37 | 38 | task('cleanDocs', async () => { 39 | await packages.map((p) => { 40 | const pathToLib = `docs/${p}`; 41 | return del.sync([pathToLib]); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 suwei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/harmony-core/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 suwei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/harmony-crypto/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 suwei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/harmony-utils/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 suwei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/harmony-account/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 suwei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/harmony-contract/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 suwei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/harmony-network/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 suwei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/harmony-staking/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 suwei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/harmony-transaction/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 suwei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /scripts/jest/transformer.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const babel = require('@babel/core') 3 | const createCacheKeyFunction = require('fbjs-scripts/jest/createCacheKeyFunction') 4 | const babelOptions = require('../babel/babel.test.config.js') 5 | 6 | // Use require.resolve to be resilient to file moves, npm updates, etc 7 | const pathToBabel = path.join(require.resolve('@babel/core'), '../', '../', 'package.json') 8 | const pathToBabelrc = path.join(__dirname, '../babel/babel.test.config.js') 9 | 10 | module.exports = { 11 | process(src, filePath) { 12 | if (!filePath.match(/\/third_party\//)) { 13 | const isTestFile = !!filePath.match(/\/__test__\//) 14 | const concatOptions = Object.assign( 15 | babelOptions, 16 | { filename: path.relative(process.cwd(), filePath) }, 17 | isTestFile 18 | ? { 19 | plugins: babelOptions.plugins 20 | } 21 | : {} 22 | ) 23 | const result = babel.transformSync(src, concatOptions) 24 | return result.code 25 | } 26 | return src 27 | }, 28 | getCacheKey: createCacheKeyFunction([__filename, pathToBabel, pathToBabelrc]) 29 | } 30 | -------------------------------------------------------------------------------- /packages/harmony-utils/test/fixture.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-utils 4 | * @ignore 5 | */ 6 | 7 | // import BN from 'bn.js'; 8 | 9 | export const basicType = { 10 | zero: 0, 11 | float: 0.1, 12 | text: 'testString', 13 | jsonString: '{"name":"@harmony-js/utils","version":"0.0.48","description":"utils for harmony"}', 14 | hexNumber: 0x123, 15 | hexString: '0x123', 16 | bool: true, 17 | undefined, 18 | null: null, 19 | // tslint:disable-next-line: no-empty 20 | function: () => {}, 21 | array: [1, 2, 3], 22 | object: {}, 23 | }; 24 | 25 | export const advanceType = { 26 | privateKey: '0x97d2d3a21d829800eeb01aa7f244926f993a1427d9ba79d9dc3bf14fe04d9e37', 27 | publicKey: '0x028fe48b60c4511f31cf58906ddaa8422725d9313d4b994fab598d2cf220146228', 28 | address: '0x84fece7d1f5629bc728c956ffd313dd0c3ac8f17', 29 | hexAddress: '0x84fece7d1f5629bc728c956ffd313dd0c3ac8f17', 30 | checkSumAddress: '0x84fece7d1f5629Bc728c956Ffd313dD0C3AC8f17', 31 | hex: '0x8423', 32 | hash: 'F5A5FD42D16A20302798EF6ED309979B43003D2320D9F0E8EA9831A92759FB4B', 33 | byStrX: '0x84fece7d1f5629bc728c956ffd313dd0c3ac8f17', 34 | url: 'https://www.zilliqa.com', 35 | }; 36 | -------------------------------------------------------------------------------- /packages/harmony-transaction/src/abstractTransaction.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-transaction 4 | * @hidden 5 | */ 6 | 7 | import { Messenger } from '@harmony-js/network'; 8 | import { TxStatus } from './types'; 9 | 10 | export abstract class AbstractTransaction { 11 | abstract setMessenger(messenger: Messenger): void; 12 | abstract setTxStatus(txStatus: TxStatus): void; 13 | abstract getTxStatus(): TxStatus; 14 | abstract isInitialized(): boolean; 15 | abstract isSigned(): boolean; 16 | abstract isPending(): boolean; 17 | abstract isRejected(): boolean; 18 | abstract isConfirmed(): boolean; 19 | abstract async trackTx(txHash: string, shardID: number | string): Promise; 20 | abstract async txConfirm( 21 | txHash: string, 22 | maxAttempts: number | undefined, 23 | interval: number | undefined, 24 | shardID: string | number, 25 | ): Promise; 26 | abstract async socketConfirm( 27 | txHash: string, 28 | maxAttempts: number, 29 | shardID: number | string, 30 | ): Promise; 31 | abstract async getBlockNumber(shardID: number | string): Promise; 32 | abstract async getBlockByNumber(blockNumber: string): Promise; 33 | } 34 | -------------------------------------------------------------------------------- /packages/harmony-network/src/subscriptions/SyncingSub.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | * @hidden 5 | */ 6 | 7 | import { Messenger } from '../messenger/messenger'; 8 | import { SubscriptionMethod } from './Subscription'; 9 | 10 | export class Syncing extends SubscriptionMethod { 11 | isSyncing: boolean | null; 12 | constructor(messenger: Messenger, shardID: number = 0) { 13 | super('syncing', undefined, messenger, shardID); 14 | this.isSyncing = null; 15 | this.start(); 16 | } 17 | 18 | onNewSubscriptionItem(subscriptionItem: any) { 19 | const isSyncing = subscriptionItem.params.result.syncing; 20 | 21 | if (this.isSyncing === null) { 22 | this.isSyncing = isSyncing; 23 | this.emitter.emit('changed', this.isSyncing); 24 | } 25 | 26 | if (this.isSyncing === true && isSyncing === false) { 27 | this.isSyncing = isSyncing; 28 | this.emitter.emit('changed', this.isSyncing); 29 | } 30 | 31 | if (this.isSyncing === false && isSyncing === true) { 32 | this.isSyncing = isSyncing; 33 | this.emitter.emit('changed', this.isSyncing); 34 | } 35 | // todo formatter 36 | return subscriptionItem; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/harmony-account/test/testAccount.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-account 4 | * @ignore 5 | */ 6 | 7 | import fetch from 'jest-fetch-mock'; 8 | import { Account } from '../src/account'; 9 | import { HttpProvider, Messenger } from '@harmony-js/network'; 10 | import { ChainType, ChainID } from '@harmony-js/utils'; 11 | 12 | const provider = new HttpProvider('http://localhost:9500'); 13 | const messenger = new Messenger(provider, ChainType.Harmony, ChainID.HmyLocal); 14 | 15 | describe('test account', () => { 16 | it('test Account.getBalance returns object that implements Balance interface', () => { 17 | fetch.mockResponses( 18 | [ 19 | JSON.stringify({"jsonrpc": "2.0", "id": 1, "result": "0x166c690f33421e"}), 20 | { status: 200 } 21 | ], 22 | [ 23 | JSON.stringify({"jsonrpc": "2.0", "id": 1, "result": "0x106"}), 24 | { status: 200 } 25 | ] 26 | ); 27 | const acc = Account.new(); 28 | acc.setMessenger(messenger); 29 | acc.getBalance().then((res) => { 30 | expect(res).not.toBeNull(); 31 | expect(res.balance).not.toBeNull(); 32 | expect(res.nonce).not.toBeNull(); 33 | expect(res.shardID).not.toBeNull(); 34 | }); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /packages/harmony-network/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | * @ignore 5 | */ 6 | 7 | import mitt from 'mitt'; 8 | export { mitt }; 9 | // provider related 10 | export * from './providers/baseProvider'; 11 | export * from './providers/baseSocket'; 12 | export * from './providers/defaultFetcher'; 13 | export * from './providers/http'; 14 | export * from './providers/ws'; 15 | export * from './providers/emitter'; 16 | export * from './providers/provider'; 17 | // messenger and middlewares 18 | export * from './messenger/messenger'; 19 | export * from './messenger/responseMiddleware'; 20 | // rpc builder and blockchain method 21 | export * from './rpcMethod/builder'; 22 | export * from './rpcMethod/net'; 23 | export * from './rpcMethod/rpc'; 24 | // trackers 25 | export * from './tracker/baseTracker'; 26 | export * from './tracker/pollingTracker'; 27 | export * from './tracker/subscribeTracker'; 28 | 29 | // subscriptinos 30 | export * from './subscriptions/Subscription'; 31 | export * from './subscriptions/LogSub'; 32 | export * from './subscriptions/NewHeadersSub'; 33 | export * from './subscriptions/NewPendingTransactionsSub'; 34 | export * from './subscriptions/SyncingSub'; 35 | // utils 36 | export * from './util'; 37 | // types 38 | export * from './types'; 39 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/models/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * @hidden 5 | */ 6 | 7 | // defined by web3.js 8 | // fixed 9 | export interface AbiModel { 10 | getMethod(name: string): AbiItemModel | false; 11 | getMethods(): AbiItemModel[]; 12 | hasMethod(name: string): boolean; 13 | getEvent(name: string): AbiItemModel | false; 14 | getEvents(): AbiItemModel[]; 15 | getEventBySignature(signature: string): AbiItemModel | undefined; 16 | hasEvent(name: string): boolean; 17 | } 18 | 19 | export interface AbiItemModel { 20 | name: string; 21 | signature: string; 22 | payable: boolean; 23 | anonymous: boolean; 24 | inputs: AbiInput[]; 25 | outputs: AbiOutput[]; 26 | type: string; 27 | stateMutability?: string; 28 | constant?: boolean; 29 | funcName: string; 30 | contractMethodParameters: any[]; 31 | getInputLength(): number; 32 | getInputs(): AbiInput[]; 33 | getIndexedInputs(): AbiInput[]; 34 | getOutputs(): AbiOutput[]; 35 | isOfType(value: string): boolean; 36 | } 37 | 38 | export interface AbiInput { 39 | name: string; 40 | type: string; 41 | indexed?: boolean; 42 | components?: AbiInput[]; 43 | } 44 | 45 | export interface AbiOutput { 46 | name: string; 47 | type: string; 48 | components?: AbiOutput[]; 49 | } 50 | -------------------------------------------------------------------------------- /packages/harmony-crypto/test/keyTool.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @ignore 4 | */ 5 | 6 | import * as keys from '../src/keyTool'; 7 | import { isPrivateKey, isAddress, isPublicKey } from '@harmony-js/utils'; 8 | 9 | describe('test keyTools', () => { 10 | it('test keygen', () => { 11 | const prv = keys.generatePrivateKey(); 12 | const pub = keys.getPubkeyFromPrivateKey(prv); 13 | const addr = keys.getAddressFromPublicKey(pub); 14 | const addrPrv = keys.getAddressFromPrivateKey(prv); 15 | expect(isPrivateKey(prv)).toEqual(true); 16 | expect(isPublicKey(pub)).toEqual(true); 17 | expect(isAddress(addr)).toEqual(true); 18 | expect(isAddress(addrPrv)).toEqual(true); 19 | expect(addr).toEqual(addrPrv); 20 | }); 21 | 22 | it('should test sign', () => { 23 | const unsigned = '0xdc80808080809401234567890123456789012345678901234567898080'; 24 | const privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123'; 25 | const pub = keys.getPubkeyFromPrivateKey(privateKey); 26 | const signature = keys.sign(unsigned, privateKey); 27 | expect(keys.verifySignature(unsigned, signature, pub)).toEqual(true); 28 | try { 29 | keys.sign(unsigned, '111'); 30 | } catch (error) { 31 | expect(error.message).toEqual(`111 is not PrivateKey`); 32 | } 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /e2e/src/harmony.ts: -------------------------------------------------------------------------------- 1 | import fetch from 'jest-fetch-mock'; 2 | // tslint:disable-next-line: no-implicit-dependencies 3 | import { Harmony } from '@harmony-js/core'; 4 | // tslint:disable-next-line: no-implicit-dependencies 5 | import { ChainType } from '@harmony-js/utils'; 6 | // tslint:disable-next-line: no-implicit-dependencies 7 | import { Account } from '@harmony-js/account'; 8 | 9 | const CHAIN_ID: number = 2; 10 | const CHAIN_TYPE: string = 'hmy'; 11 | const HTTP_PROVIDER: string = 'http://localhost:9500'; 12 | const GENESIS_PRIV_KEY: string = '45e497bd45a9049bcb649016594489ac67b9f052a6cdf5cb74ee2427a60bf25e'; 13 | 14 | let chainType: ChainType = ChainType.Harmony; 15 | 16 | if (CHAIN_TYPE === 'hmy') { 17 | chainType = ChainType.Harmony; 18 | } else if (CHAIN_TYPE === 'eth') { 19 | chainType = ChainType.Ethereum; 20 | } 21 | 22 | export const harmony: Harmony = new Harmony(HTTP_PROVIDER, { 23 | chainId: CHAIN_ID, 24 | chainType, 25 | chainUrl: HTTP_PROVIDER, 26 | }); 27 | 28 | export const myAccount: Account = harmony.wallet.addByPrivateKey( 29 | GENESIS_PRIV_KEY, 30 | ); 31 | 32 | export function checkCalledMethod(i: number, s: string) { 33 | let params: (string | undefined) = fetch.mock.calls[i][1]?.body?.toString(); 34 | if (params) { 35 | let method: string = JSON.parse(params).method; 36 | return method === s; 37 | } 38 | return false; 39 | } 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | *.lock 5 | *.tsbuildinfo 6 | .vscode/ 7 | 8 | # babel 9 | packages/*/babel.rc 10 | 11 | # lerna 12 | # lerna.json 13 | lib/ 14 | node/ 15 | *.log 16 | 17 | #cache 18 | .rpt2_cache/ 19 | includes/ 20 | devTestOnly/ 21 | # Xcode 22 | # 23 | build/ 24 | *.pbxuser 25 | !default.pbxuser 26 | *.mode1v3 27 | !default.mode1v3 28 | *.mode2v3 29 | !default.mode2v3 30 | *.perspectivev3 31 | !default.perspectivev3 32 | xcuserdata 33 | *.xccheckout 34 | *.moved-aside 35 | DerivedData 36 | *.hmap 37 | *.ipa 38 | *.xcuserstate 39 | project.xcworkspace 40 | 41 | # Android/IntelliJ 42 | # 43 | build/ 44 | dist/ 45 | .idea 46 | .gradle 47 | local.properties 48 | *.iml 49 | 50 | # node.js 51 | # 52 | node_modules/ 53 | packages/*/node_modules 54 | /packages/*/node_modules 55 | npm-debug.log 56 | lerna-debug.log 57 | yarn-error.log 58 | 59 | 60 | # BUCK 61 | buck-out/ 62 | \.buckd/ 63 | *.keystore 64 | 65 | # fastlane 66 | # 67 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 68 | # screenshots whenever they are needed. 69 | # For more information about the recommended setup visit: 70 | # https://docs.fastlane.tools/best-practices/source-control/ 71 | 72 | */fastlane/report.xml 73 | */fastlane/Preview.html 74 | */fastlane/screenshots 75 | 76 | # Bundle artifact 77 | *.jsbundle 78 | 79 | # Jest coverage 80 | coverage/ 81 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/events/event.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | */ 5 | 6 | import { LogSub } from '@harmony-js/network'; 7 | import { AbiItemModel } from '../models/types'; 8 | import { Contract } from '../contract'; 9 | import { decode as eventLogDecoder } from '../utils/decoder'; 10 | import { inputLogFormatter, outputLogFormatter } from '../utils/formatter'; 11 | export class EventMethod extends LogSub { 12 | params: any; 13 | methodKey: string; 14 | contract: Contract; 15 | abiItem: AbiItemModel; 16 | constructor(methodKey: string, params: any, abiItem: AbiItemModel, contract: Contract) { 17 | super(inputLogFormatter(params), contract.wallet.messenger, contract.shardID); 18 | this.methodKey = methodKey; 19 | this.contract = contract; 20 | this.params = params; 21 | this.abiItem = abiItem; 22 | // this.subscribe(); 23 | } 24 | 25 | // call() {} 26 | // estimateGas() {} 27 | // encodeABI() {} 28 | 29 | onNewSubscriptionItem(subscriptionItem: any) { 30 | const formatted = outputLogFormatter( 31 | subscriptionItem.method !== undefined ? subscriptionItem.params.result : subscriptionItem, 32 | ); 33 | const log = eventLogDecoder(this.contract.abiCoder, this.abiItem, formatted); 34 | 35 | if (log.removed && this.emitter) { 36 | this.emitter.emit('changed', log); 37 | } 38 | 39 | return log; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/harmony-network/src/rpcMethod/net.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | * @ignore 5 | */ 6 | 7 | export const DEFAULT_TIMEOUT: number = 120000; 8 | 9 | export const DEFAULT_HEADERS: object = { 'Content-Type': 'application/json' }; 10 | 11 | function _fetch(fetchPromise: Promise, timeout: number) { 12 | let abortFn: () => void; 13 | 14 | const abortPromise = new Promise((resolve, reject) => { 15 | abortFn = () => reject(new Error(`request Timeout in ${timeout} ms`)); 16 | }); 17 | const abortablePromise = Promise.race([fetchPromise, abortPromise]); 18 | 19 | setTimeout(() => { 20 | abortFn(); 21 | }, timeout); 22 | 23 | return abortablePromise; 24 | } 25 | 26 | export const performRPC = async (request: any, handler: any, fetcher: any) => { 27 | try { 28 | const response = await _fetch( 29 | fetcher.requestHandler(request, DEFAULT_HEADERS), 30 | request.options && request.options.timeout ? request.options.timeout : DEFAULT_TIMEOUT, 31 | ); 32 | return fetcher.responseHandler(response, request, handler); 33 | } catch (err) { 34 | throw err; 35 | } 36 | }; 37 | 38 | export function composeMiddleware(...fns: any[]): any { 39 | if (fns.length === 0) { 40 | return (arg: any) => arg; 41 | } 42 | 43 | if (fns.length === 1) { 44 | return fns[0]; 45 | } 46 | 47 | return fns.reduce((a, b) => (arg: any) => a(b(arg))); 48 | } 49 | -------------------------------------------------------------------------------- /scripts/typedoc/runner.js: -------------------------------------------------------------------------------- 1 | // tslint:disable-next-line: no-var-requires 2 | const path = require('path'); 3 | // tslint:disable-next-line: no-implicit-dependencies no-var-requires 4 | const {Application} = require('typedoc'); 5 | // tslint:disable-next-line: no-implicit-dependencies no-var-requires 6 | const arg = require('arg'); 7 | 8 | const args = arg({ 9 | '--pkgPath': String, 10 | '-p': '--pkgPath', 11 | '--pkgSrc': String, 12 | '-s': '--pkgSrc', 13 | '--target': String, 14 | '-t': '--target', 15 | }); 16 | 17 | const pkgSrc = args['--pkgSrc']; 18 | const pkgPath = args['--pkgPath']; 19 | const target = args['--target']; 20 | 21 | const app = new Application({ 22 | mode: 'file', 23 | tsconfig: `${pkgPath}/tsconfig.json`, 24 | theme: target === 'default' ? 'default' : 'markdown', 25 | plugin: path.resolve('node_modules/typedoc-plugin-markdown'), 26 | platform: target, 27 | }); 28 | 29 | const files = [...app.expandInputFiles([pkgSrc])]; 30 | 31 | const nameArray = pkgPath.split('/'); 32 | const index = nameArray.findIndex( 33 | (value) => value.startsWith('harmony') && !value.startsWith('harmony-js'), 34 | ); 35 | 36 | const docPath = nameArray[index]; //.replace('harmony-', ''); 37 | 38 | // const project = app.convert(); 39 | const outputDir = `${pkgPath}/doc/${target}`; 40 | const outputDirRoot = `docs/${docPath}`; 41 | // console.log({ttt, files, outputDir}); 42 | // // Rendered docs 43 | app.generateDocs(files, outputDirRoot); 44 | -------------------------------------------------------------------------------- /scripts/jest/jest.build.config.js: -------------------------------------------------------------------------------- 1 | const { readdirSync, statSync } = require('fs'); 2 | const { join } = require('path'); 3 | const baseConfig = require('./jest.src.config'); 4 | 5 | // Find all folders in packages/* with package.json 6 | const packagesRoot = join(__dirname, '..', '..', 'packages'); 7 | const packages = readdirSync(packagesRoot).filter((dir) => { 8 | if (dir.charAt(0) === '.') { 9 | return false; 10 | } 11 | if (dir === 'events') { 12 | // There's an actual Node package called "events" 13 | // that's used by jsdom so we don't want to alias that. 14 | return false; 15 | } 16 | const packagePath = join(packagesRoot, dir, 'package.json'); 17 | return statSync(packagePath).isFile(); 18 | }); 19 | // Create a module map to point packages to the build output 20 | const moduleNameMapper = {}; 21 | packages.forEach((name) => { 22 | // Root entry point 23 | moduleNameMapper[`^${name}$`] = `/packages/${name}/dist/index.js`; 24 | // Named entry points 25 | // moduleNameMapper[`^${name}/(.*)$`] = `/dist/node_modules/${name}/$1` 26 | }); 27 | 28 | module.exports = Object.assign({}, baseConfig, { 29 | // Redirect imports to the compiled bundles 30 | moduleNameMapper, 31 | // Don't run bundle tests on blacklisted -test.internal.* files 32 | testPathIgnorePatterns: ['/node_modules/', '-test.internal.js$'], 33 | // Exclude the build output from transforms 34 | transformIgnorePatterns: ['/node_modules/', '/build/'], 35 | }); 36 | -------------------------------------------------------------------------------- /packages/harmony-crypto/test/bytes.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @ignore 4 | */ 5 | 6 | import * as bytes from '../src/bytes'; 7 | 8 | describe('Bytes', () => { 9 | it('hexlify on string of unsafe number', () => { 10 | [9007199254740991, 9985956830000000000].forEach((value) => { 11 | try { 12 | bytes.hexlify(value); 13 | } catch (error) { 14 | expect(error.code).toEqual('NUMERIC_FAULT'); 15 | expect(error.fault).toEqual('out-of-safe-range'); 16 | } 17 | }); 18 | }); 19 | it('splits a canonical signature', () => { 20 | const r = '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef'; 21 | const s = '0xcafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7e'; 22 | for (let v = 27; v <= 28; v++) { 23 | const signature = bytes.concat([r, s, [v]]); 24 | const sig = bytes.splitSignature(signature); 25 | expect(sig.r).toEqual(r); 26 | expect(sig.s).toEqual(s); 27 | expect(sig.v).toEqual(v); 28 | } 29 | }); 30 | 31 | it('splits a legacy signature', () => { 32 | const r = '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef'; 33 | const s = '0xcafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7e'; 34 | for (let v = 27; v <= 28; v++) { 35 | const signature = bytes.concat([r, s, [v - 27]]); 36 | const sig = bytes.splitSignature(signature); 37 | 38 | expect(sig.r).toEqual(r); 39 | expect(sig.s).toEqual(s); 40 | expect(sig.v).toEqual(v); 41 | } 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /packages/harmony-network/src/rpcMethod/builder.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | * @hidden 5 | */ 6 | 7 | import { RPCRequestPayload } from '../types'; 8 | import { RPCMethod } from './rpc'; 9 | /** 10 | * @class JsonRpc 11 | * @description json rpc instance 12 | * @return {JsonRpc} Json RPC instance 13 | */ 14 | class JsonRpc { 15 | messageId: number; 16 | constructor() { 17 | /** 18 | * @var {Number} messageId 19 | * @memberof JsonRpc.prototype 20 | * @description message id, default 0 21 | */ 22 | this.messageId = 0; 23 | } 24 | 25 | /** 26 | * @function toPayload 27 | * @memberof JsonRpc.prototype 28 | * @description convert method and params to payload object 29 | * @param {String} method - RPC method 30 | * @param {Array} params - params that send to RPC 31 | * @return {Object} payload object 32 | */ 33 | toPayload = ( 34 | method: RPCMethod | string, 35 | params: string | undefined | any[], 36 | ): RPCRequestPayload => { 37 | // FIXME: error to be done by shared/errors 38 | if (!method) { 39 | throw new Error('jsonrpc method should be specified!'); 40 | } 41 | 42 | // advance message ID 43 | this.messageId += 1; 44 | 45 | const sendParams = 46 | params === undefined ? [] : typeof params === 'string' ? [params] : [...params]; 47 | 48 | return { 49 | jsonrpc: '2.0', 50 | id: this.messageId, 51 | method, 52 | params: sendParams, 53 | }; 54 | }; 55 | } 56 | 57 | export { JsonRpc }; 58 | -------------------------------------------------------------------------------- /scripts/typings/schema.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as path from 'path'; 3 | // tslint:disable-next-line: no-implicit-dependencies 4 | import * as schemas from 'typescript-json-schema'; 5 | 6 | import { packages } from '../packagesTs'; 7 | import tsConfig from '../../tsconfig.base.json'; 8 | 9 | const outputs = process.argv.slice(2)[0].split(','); 10 | 11 | const rootPath = path.resolve(__dirname, '../..'); 12 | const includesPath = path.join(rootPath, 'includes'); 13 | const packagesPath = path.join(rootPath, 'packages'); 14 | 15 | async function generateSchemas() { 16 | packages 17 | // @ts-ignore 18 | .filter((pkg) => { 19 | return ( 20 | pkg !== 'harmony-' && 21 | outputs.indexOf(pkg.replace('harmony-', '')) !== -1 22 | ); 23 | }) 24 | .forEach((pkg) => { 25 | const pkgPath = path.join(packagesPath, pkg); 26 | const pkgSrc = path.join(pkgPath, 'src'); 27 | const settings = { 28 | ref: false, 29 | }; 30 | // tslint:disable-next-line: no-shadowed-variable 31 | const tsConfig: schemas.CompilerOptions = { 32 | lib: ['es2015'], 33 | }; 34 | 35 | const prog = schemas.getProgramFromFiles( 36 | [path.resolve(path.join(pkgSrc, 'types.ts'))], 37 | tsConfig, 38 | ); 39 | 40 | const schema = schemas.generateSchema(prog, '*', settings); 41 | 42 | // fs.writeFileSync( 43 | // path.join(pkgPath, 'test', 'schema.json'), 44 | // JSON.stringify(schema, undefined, 2), 45 | // ); 46 | }); 47 | } 48 | 49 | generateSchemas(); 50 | -------------------------------------------------------------------------------- /packages/harmony-network/src/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | * @ignore 5 | */ 6 | 7 | import { RPCMethod, RPCErrorCode } from './rpcMethod/rpc'; 8 | 9 | export type ReqMiddleware = Map; 10 | export type ResMiddleware = Map; 11 | 12 | export enum MiddlewareType { 13 | REQ, 14 | RES, 15 | } 16 | 17 | export enum SubscribeReturns { 18 | all = 'all', 19 | id = 'id', 20 | method = 'method', 21 | } 22 | 23 | export interface Middleware { 24 | request: object; 25 | response: object; 26 | } 27 | 28 | export interface RPCRequestPayload { 29 | id: number; 30 | jsonrpc: string; 31 | method: RPCMethod | string; 32 | params: T; 33 | } 34 | 35 | export interface RPCRequestOptions { 36 | headers: []; 37 | method: string; 38 | } 39 | 40 | export interface RPCRequest { 41 | url: string; 42 | payload: RPCRequestPayload; 43 | options: RPCRequestOptions; 44 | } 45 | 46 | export interface RPCResponseBase { 47 | jsonrpc: string; 48 | id: string; 49 | } 50 | 51 | export interface RPCResponseBody extends RPCResponseBase { 52 | result: R; 53 | error: E; 54 | } 55 | 56 | export interface RPCError { 57 | code: RPCErrorCode; 58 | message: string; 59 | data: any; 60 | } 61 | 62 | export interface RPCResult { 63 | resultString: string; 64 | resultMap: Map; 65 | resultList: any[]; 66 | raw: any; 67 | } 68 | 69 | export interface ShardingItem { 70 | current: boolean; 71 | shardID: number | string; 72 | http: string; 73 | ws: string; 74 | } 75 | -------------------------------------------------------------------------------- /packages/harmony-transaction/src/shardingTransaction.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-transaction 4 | * @hidden 5 | */ 6 | 7 | import { Messenger } from '@harmony-js/network'; 8 | import { AddressSuffix } from '@harmony-js/utils'; 9 | import { Transaction } from './transaction'; 10 | import { TxParams, TxStatus } from './types'; 11 | import { defaultMessenger } from './utils'; 12 | 13 | export class ShardingTransaction extends Transaction { 14 | constructor( 15 | params?: TxParams | any, 16 | messenger: Messenger = defaultMessenger, 17 | txStatus = TxStatus.INTIALIZED, 18 | ) { 19 | const fromAddress = params.from; 20 | const toAddress = params.to; 21 | const fromExtraction = 22 | fromAddress !== undefined ? fromAddress.split(AddressSuffix) : ['0x', undefined]; 23 | const toExtraction = 24 | toAddress !== undefined ? toAddress.split(AddressSuffix) : ['0x', undefined]; 25 | const from = fromExtraction[0]; 26 | const shardID = 27 | fromExtraction[1] !== undefined 28 | ? Number.parseInt(fromExtraction[1], 10) 29 | : params.shardID !== undefined 30 | ? params.shardID 31 | : 0; 32 | const to = toExtraction[0]; 33 | const toShardID = 34 | toExtraction[1] !== undefined 35 | ? Number.parseInt(toExtraction[1], 10) 36 | : params.toShardID !== undefined 37 | ? params.toShardID 38 | : 0; 39 | 40 | const reParams = { 41 | ...params, 42 | from, 43 | to, 44 | shardID, 45 | toShardID, 46 | }; 47 | 48 | super(reParams, messenger, txStatus); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Guidelines 2 | ## Before Release 3 | 1. Build source first 4 | ```bash 5 | yarn build:ts 6 | ``` 7 | 2. Run unit tests 8 | ```bash 9 | yarn test:src 10 | ``` 11 | 3. Run e2e tests 12 | ```bash 13 | yarn test:e2e 14 | ``` 15 | 4. Clean and build bundle 16 | ```bash 17 | yarn dist 18 | ``` 19 | ## Publish to npm using `dev:publish` 20 | 21 | The packages is to be published to npm, using `@next` tag using script in `package.json` 22 | 23 | Follow steps below to publish a npm verion using `@next` tag 24 | 25 | 1. Commit all changes to github master 26 | 2. Run publish script 27 | 28 | ```bash 29 | yarn dev:publish 30 | ``` 31 | 32 | 3. Select version and confirm all prompts with `Y` 33 | 4. See version changes in `npmjs.com` 34 | 35 | This will not change the release version of current npm packages(currently 0.0.7), developers have to use `@next` to install from npm. 36 | 37 | For example. 38 | 39 | ```bash 40 | npm install @harmony-js/core@next 41 | ``` 42 | 43 | 44 | 45 | ## Publish to npm with `lerna` 46 | 47 | Follow steps below to publish a npm verion with latest version 48 | 49 | 1. Commit all changes to github master 50 | 2. Run `lerna publish`, `lerna` is required globally. 51 | 52 | ```bash 53 | lerna publish 54 | ``` 55 | 3. Select version and confirm all prompts with `Y` 56 | 4. See version changes in `npmjs.com` 57 | 58 | This will change the release version of current npm packages to the latest version, developers can install from npm directly 59 | 60 | For example. 61 | 62 | ```bash 63 | npm install @harmony-js/core 64 | ``` 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/models/AbiItemModel.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * @hidden 5 | */ 6 | 7 | import { isArray } from '@harmony-js/utils'; 8 | import { AbiItemModel, AbiOutput, AbiInput } from './types'; 9 | 10 | export class AbiItem { 11 | abiItem: AbiItemModel; 12 | signature: string; 13 | name: string; 14 | payable: boolean; 15 | anonymous: boolean; 16 | type?: string; 17 | inputs?: AbiInput[]; 18 | outputs?: AbiOutput[]; 19 | contractMethodParameters: any[]; 20 | 21 | // constructor 22 | constructor(abiItem: AbiItemModel | any) { 23 | this.abiItem = abiItem; 24 | this.signature = this.abiItem.signature; 25 | this.name = this.abiItem.name; 26 | this.payable = this.abiItem.payable; 27 | this.anonymous = this.abiItem.anonymous; 28 | this.type = this.abiItem.type; 29 | this.inputs = this.abiItem.inputs; 30 | this.outputs = this.abiItem.outputs; 31 | this.contractMethodParameters = []; 32 | } 33 | 34 | getInputLength() { 35 | if (isArray(this.abiItem.inputs)) { 36 | return this.abiItem.inputs.length; 37 | } 38 | 39 | return 0; 40 | } 41 | 42 | getInputs() { 43 | if (isArray(this.abiItem.inputs)) { 44 | return this.abiItem.inputs; 45 | } 46 | 47 | return []; 48 | } 49 | 50 | getOutputs() { 51 | if (isArray(this.abiItem.outputs)) { 52 | return this.abiItem.outputs; 53 | } 54 | 55 | return []; 56 | } 57 | 58 | getIndexedInputs() { 59 | return this.getInputs().filter((input) => { 60 | return input.indexed === true; 61 | }); 62 | } 63 | 64 | isOfType(type: string) { 65 | return this.abiItem.type === type; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/methods/methodFactory.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * @hidden 5 | */ 6 | 7 | import { AbiCoderClass } from '../abi/api'; 8 | import { AbiModel } from '../models/types'; 9 | import { Contract } from '../contract'; 10 | import { ContractMethod } from './method'; 11 | 12 | export class MethodFactory { 13 | contract: Contract; 14 | abiModel: any | AbiModel; 15 | abiCoder: AbiCoderClass; 16 | private methodKeys: string[]; 17 | 18 | // constructor 19 | constructor(contract: Contract) { 20 | this.contract = contract; 21 | this.abiModel = this.contract.abiModel; 22 | this.abiCoder = this.contract.abiCoder; 23 | this.methodKeys = this.mapMethodKeys(); 24 | } 25 | 26 | addMethodsToContract() { 27 | this.methodKeys.forEach((key: string) => { 28 | const newObject: any = {}; 29 | newObject[key] = (...params: any[]) => 30 | new ContractMethod(key, params, this.abiModel.getMethod(key), this.contract); 31 | 32 | Object.assign(this.contract.methods, newObject); 33 | }); 34 | if (this.abiModel.hasFallback()) { 35 | this.contract.fallback = (calldata: string) => 36 | new ContractMethod('fallback', [calldata], this.abiModel.getFallback(), this.contract); 37 | } 38 | if (this.abiModel.hasReceive()) { 39 | this.contract.receive = () => 40 | new ContractMethod('receive', [], this.abiModel.getReceive(), this.contract); 41 | } 42 | return this.contract; 43 | } 44 | /** 45 | * @function mapMethodKeys 46 | * @return {string[]} {description} 47 | */ 48 | private mapMethodKeys(): string[] { 49 | return Object.keys(this.abiModel.abi.methods); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/harmony-network/src/messenger/responseMiddleware.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | * @hidden 5 | */ 6 | 7 | import { RPCResponseBody } from '../types'; 8 | import { isObject } from '@harmony-js/utils'; 9 | /** 10 | * @class ResponseMiddleware 11 | * @description Response middleware of RPC 12 | * @param {Object} ResponseBody - response from rpc 13 | * @return {ResponseMiddleware} response middleware instance 14 | */ 15 | class ResponseMiddleware { 16 | result: any; 17 | error: any; 18 | raw: any; 19 | responseType: string; 20 | constructor(ResponseBody: RPCResponseBody) { 21 | this.result = ResponseBody.result; 22 | this.error = ResponseBody.error; 23 | this.raw = ResponseBody; 24 | this.responseType = this.getResponseType(); 25 | } 26 | 27 | get getResult() { 28 | return isObject(this.result) ? { ...this.result, responseType: 'result' } : this.result; 29 | } 30 | 31 | get getError() { 32 | return isObject(this.error) ? { ...this.error, responseType: 'error' } : this.error; 33 | } 34 | 35 | get getRaw() { 36 | return { ...this.raw, responseType: 'raw' }; 37 | } 38 | 39 | getResponseType(): string { 40 | if (this.error) { 41 | return 'error'; 42 | } else if (this.result || (this.result === null && this.result !== undefined)) { 43 | return 'result'; 44 | } else { 45 | return 'raw'; 46 | } 47 | } 48 | 49 | isError(): boolean { 50 | return this.responseType === 'error'; 51 | } 52 | isResult(): boolean { 53 | return this.responseType === 'result'; 54 | } 55 | isRaw(): boolean { 56 | return this.responseType === 'raw'; 57 | } 58 | } 59 | export { ResponseMiddleware }; 60 | -------------------------------------------------------------------------------- /scripts/docs.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import {projects, preProcessFunc, preProcessProjects} from './projects'; 3 | // tslint:disable-next-line: no-implicit-dependencies no-var-requires 4 | import spawn from 'cross-spawn'; 5 | 6 | // tslint:disable-next-line: no-var-requires 7 | const runner = require.resolve('./typedoc/runner'); 8 | const batch = require.resolve('./typedoc/batch'); 9 | const options = {stdio: 'inherit'}; 10 | 11 | const outputs = process.argv.slice(2)[0].split(','); 12 | // docusaurus,vuepress,gitbook,bitbucket 13 | 14 | async function docs() { 15 | await preProcessFunc(preProcessProjects); 16 | for (const pkg of projects) { 17 | if (outputs.indexOf('gitbook') !== -1) { 18 | spawn( 19 | 'node', 20 | [runner, '-p', `${pkg.path}`, '-s', `${pkg.src}`, '-t', 'gitbook'], 21 | options, 22 | ); 23 | } 24 | if (outputs.indexOf('vuepress') !== -1) { 25 | spawn( 26 | 'node', 27 | [runner, '-p', `${pkg.path}`, '-s', `${pkg.src}`, '-t', 'vuepress'], 28 | options, 29 | ); 30 | } 31 | if (outputs.indexOf('docusaurus') !== -1) { 32 | spawn( 33 | 'node', 34 | [runner, '-p', `${pkg.path}`, '-s', `${pkg.src}`, '-t', 'docusaurus'], 35 | options, 36 | ); 37 | } 38 | if (outputs.indexOf('bitbucket') !== -1) { 39 | spawn( 40 | 'node', 41 | [runner, '-p', `${pkg.path}`, '-s', `${pkg.src}`, '-t', 'bitbucket'], 42 | options, 43 | ); 44 | } 45 | if (outputs.indexOf('default') !== -1) { 46 | spawn( 47 | 'node', 48 | [runner, '-p', `${pkg.path}`, '-s', `${pkg.src}`, '-t', 'default'], 49 | options, 50 | ); 51 | } 52 | } 53 | } 54 | 55 | docs(); 56 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/env", 5 | { 6 | "modules": false, 7 | "targets": { 8 | "browsers": [">0.25%"] 9 | }, 10 | "useBuiltIns": "usage" 11 | } 12 | ], 13 | "@babel/typescript" 14 | ], 15 | "env": { 16 | "development": { 17 | "plugins": ["@babel/transform-runtime"] 18 | }, 19 | "production": { 20 | "plugins": ["@babel/transform-runtime", "transform-remove-console"] 21 | }, 22 | "test": { 23 | "presets": [ 24 | [ 25 | "@babel/env", 26 | { 27 | "modules": "commonjs", 28 | "targets": { 29 | "node": "current" 30 | } 31 | } 32 | ], 33 | "@babel/typescript" 34 | ] 35 | } 36 | }, 37 | "plugins": [ 38 | "@babel/plugin-syntax-dynamic-import", 39 | "@babel/plugin-syntax-import-meta", 40 | "@babel/plugin-proposal-class-properties", 41 | "@babel/plugin-proposal-json-strings", 42 | [ 43 | "@babel/plugin-proposal-decorators", 44 | { 45 | "legacy": true 46 | } 47 | ], 48 | "@babel/plugin-proposal-function-sent", 49 | "@babel/plugin-proposal-export-namespace-from", 50 | "@babel/plugin-proposal-numeric-separator", 51 | "@babel/plugin-proposal-throw-expressions", 52 | "@babel/plugin-proposal-export-default-from", 53 | "@babel/plugin-proposal-logical-assignment-operators", 54 | "@babel/plugin-proposal-optional-chaining", 55 | [ 56 | "@babel/plugin-proposal-pipeline-operator", 57 | { 58 | "proposal": "minimal" 59 | } 60 | ], 61 | "@babel/plugin-proposal-nullish-coalescing-operator", 62 | "@babel/plugin-proposal-do-expressions" 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /packages/harmony-utils/README.md: -------------------------------------------------------------------------------- 1 | # @harmony-js/utils 2 | 3 | This package provides a collection of utility apis for unit conversions like `fromWei`, `toWei`, `hexToNumber`, `numberToHex`, `isAddress`, etc. 4 | 5 | ## Installation 6 | 7 | ``` 8 | npm install @harmony-js/utils 9 | ``` 10 | 11 | ## Usage 12 | 13 | Available units 14 | ``` 15 | const { Units } = require('@harmony-js/utils'); 16 | 17 | [Units.wei, '1'], // 1 wei 18 | [Units.Kwei, '1000'], // 1e3 wei 19 | [Units.Mwei, '1000000'], // 1e6 wei 20 | [Units.Gwei, '1000000000'], // 1e9 wei 21 | [Units.szabo, '1000000000000'], // 1e12 wei 22 | [Units.finney, '1000000000000000'], // 1e15 wei 23 | [Units.ether, '1000000000000000000'], // 1e18 wei 24 | [Units.one, '1000000000000000000'], // 1e18 wei 25 | [Units.Kether, '1000000000000000000000'], // 1e21 wei 26 | [Units.Mether, '1000000000000000000000000'], // 1e24 wei 27 | [Units.Gether, '1000000000000000000000000000'], // 1e27 wei 28 | [Units.Tether, '1000000000000000000000000000000'], // 1e30 wei 29 | ``` 30 | 31 | Converting between different units 32 | ```javascript 33 | const { Units, Unit, numberToString, add0xToString, fromWei, toWei, numToStr} = require('@harmony-js/utils'); 34 | const { BN } = require('@harmony-js/crypto'); 35 | 36 | const one = new Unit('1').asOne(); 37 | const oneToGwei = one.toGwei(); 38 | console.log(oneToGwei); 39 | 40 | // numberToString 41 | const num = 123; 42 | const str = numberToString(num) 43 | console.log(str); 44 | 45 | // add0xToString 46 | const str = '12345'; 47 | const expected = add0xToString(str) 48 | console.log(expected); 49 | 50 | // fromWei 51 | const Wei = new BN('1000000000000000000'); 52 | const expected = fromWei(Wei, Units.one); 53 | console.log(expected); 54 | 55 | // toWei 56 | const one = new BN('1'); 57 | const expected = toWei(one, hmy.utils.Units.one); 58 | const num = numToStr(expected); 59 | console.log(num); 60 | ``` -------------------------------------------------------------------------------- /packages/harmony-network/src/subscriptions/LogSub.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | */ 5 | 6 | import { Messenger } from '../messenger/messenger'; 7 | import { SubscriptionMethod } from './Subscription'; 8 | import { RPCMethod } from '../rpcMethod/rpc'; 9 | 10 | export class LogSub extends SubscriptionMethod { 11 | constructor(options: any, messenger: Messenger, shardID: number = 0) { 12 | super('logs', options, messenger, shardID); 13 | this.preprocess(); 14 | } 15 | 16 | async preprocess() { 17 | if ( 18 | (this.options.fromBlock && this.options.fromBlock !== 'latest') || 19 | this.options.fromBlock === 0 || 20 | this.options.fromBlock === '0x' 21 | ) { 22 | try { 23 | const getPastLogs = await this.messenger.send( 24 | RPCMethod.GetPastLogs, 25 | [...this.options], 26 | this.messenger.chainType, 27 | this.shardID, 28 | ); 29 | 30 | if (getPastLogs.isError()) { 31 | this.emitter.emit('error', getPastLogs.error.message); 32 | } else { 33 | const logs = getPastLogs.result; 34 | logs.forEach((log: any) => { 35 | const formattedLog = this.onNewSubscriptionItem(log); 36 | this.emitter.emit('data', formattedLog); 37 | }); 38 | } 39 | delete this.options.fromBlock; 40 | // const sub = this.start(); 41 | return this.start(); 42 | } catch (error) { 43 | this.emitter.emit('error', error); 44 | throw error; 45 | } 46 | } 47 | return this.start(); 48 | } 49 | 50 | onNewSubscriptionItem(subscriptionItem: any) { 51 | // todo log formatter 52 | const log = subscriptionItem; 53 | 54 | if (log.removed) { 55 | this.emitter.emit('changed', log); 56 | } 57 | 58 | return log; 59 | } 60 | // todo formatter 61 | } 62 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/models/AbiModel.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * @hidden 5 | */ 6 | 7 | import { AbiItemModel } from './types'; 8 | 9 | export class AbiModel { 10 | abi: any; 11 | 12 | constructor(mappedAbi: any) { 13 | this.abi = mappedAbi; 14 | } 15 | 16 | getMethod(name: string): AbiItemModel | false { 17 | if (this.hasMethod(name)) { 18 | return this.abi.methods[name]; 19 | } 20 | 21 | return false; 22 | } 23 | 24 | getMethods(): AbiItemModel[] { 25 | return this.abi.methods; 26 | } 27 | 28 | getEvent(name: string): AbiItemModel | false { 29 | if (this.hasEvent(name)) { 30 | return this.abi.events[name]; 31 | } 32 | 33 | return false; 34 | } 35 | 36 | getFallback(): AbiItemModel | false { 37 | if (this.hasFallback()) { 38 | return this.abi.fallback; 39 | } 40 | return false; 41 | } 42 | 43 | getReceive(): AbiItemModel | false { 44 | if (this.hasReceive()) { 45 | return this.abi.receive; 46 | } 47 | return false; 48 | } 49 | 50 | getEvents(): AbiItemModel[] { 51 | return this.abi.events; 52 | } 53 | 54 | getEventBySignature(signature: string): AbiItemModel | undefined { 55 | let event; 56 | 57 | Object.keys(this.abi.events).forEach((key) => { 58 | if (this.abi.events[key].signature === signature) { 59 | event = this.abi.events[key]; 60 | } 61 | }); 62 | 63 | return event; 64 | } 65 | 66 | hasMethod(name: string): boolean { 67 | return typeof this.abi.methods[name] !== 'undefined'; 68 | } 69 | 70 | hasFallback(): boolean { 71 | return typeof this.abi.fallback !== 'undefined'; 72 | } 73 | 74 | hasReceive(): boolean { 75 | return typeof this.abi.receive !== 'undefined'; 76 | } 77 | 78 | hasEvent(name: string): boolean { 79 | return typeof this.abi.events[name] !== 'undefined'; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /packages/harmony-crypto/README.md: -------------------------------------------------------------------------------- 1 | # @harmony-js/crypto 2 | 3 | This package provides a collection of apis related to address management, kestore, encoding, and encrypt/decrypt. 4 | 5 | ## Installation 6 | 7 | ``` 8 | npm install @harmony-js/crypto 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```javascript 14 | const { 15 | encode, 16 | decode, 17 | randomBytes, 18 | toBech32, 19 | fromBech32, 20 | HarmonyAddress, 21 | generatePrivateKey, 22 | getPubkeyFromPrivateKey, 23 | getAddressFromPublicKey, 24 | getAddressFromPrivateKey, 25 | encryptPhrase, 26 | decryptPhrase 27 | } = require('@harmony-js/crypto'); 28 | const { isPrivateKey, isAddress, isPublicKey } = require('@harmony-js/utils'); 29 | ``` 30 | 31 | Address apis 32 | ```javascript 33 | const bytes = randomBytes(20); 34 | const addr = new HarmonyAddress(bytes); 35 | 36 | console.log(addr.checksum); 37 | console.log(addr.bech32); 38 | 39 | console.log(HarmonyAddress.isValidBech32(addr.bech32)); 40 | ``` 41 | 42 | RLP apis 43 | ```javascript 44 | const encoded = '0x89010101010101010101'; 45 | const decoded = '0x010101010101010101'; 46 | console.log(encode(decoded)); 47 | console.log(decode(encoded)); 48 | ``` 49 | 50 | Keystore apis 51 | ```javascript 52 | const prv = generatePrivateKey(); 53 | const pub = getPubkeyFromPrivateKey(prv); 54 | const addr = getAddressFromPublicKey(pub); 55 | const addrPrv = getAddressFromPrivateKey(prv); 56 | console.log(isPrivateKey(prv)); 57 | console.log(isPublicKey(pub)); 58 | console.log(isAddress(addr)); 59 | console.log(isAddress(addrPrv)); 60 | ``` 61 | 62 | Encrypt/decrypt apis 63 | ```javascript 64 | const { Wallet } = require('@harmony-js/account'); 65 | 66 | const myPhrase = new Wallet().newMnemonic(); 67 | console.log(myPhrase); 68 | const pwd = '1234'; 69 | encryptPhrase(myPhrase, pwd).then((value) => { 70 | console.log(value); 71 | decryptPhrase(JSON.parse(value), pwd).then(value => { 72 | console.log(value); 73 | }); 74 | }); 75 | ``` 76 | -------------------------------------------------------------------------------- /packages/harmony-network/src/providers/provider.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | */ 5 | 6 | import { HttpProvider } from './http'; 7 | import { WSProvider } from './ws'; 8 | import { defaultConfig, isHttp, isWs } from '@harmony-js/utils'; 9 | 10 | export enum ProviderType { 11 | http = 'http', 12 | ws = 'ws', 13 | } 14 | 15 | export class Provider { 16 | static getProvider(provider: string | HttpProvider | WSProvider) { 17 | try { 18 | this.getProvider(provider); 19 | return new Provider(provider); 20 | } catch (error) { 21 | throw error; 22 | } 23 | } 24 | public provider: WSProvider | HttpProvider; 25 | public providerType: ProviderType; 26 | constructor(url: string | WSProvider | HttpProvider) { 27 | this.provider = this.onInitSetProvider(url); 28 | this.providerType = this.getType(this.provider); 29 | } 30 | private onInitSetProvider( 31 | providerUrl: string | HttpProvider | WSProvider, 32 | ): HttpProvider | WSProvider { 33 | if (typeof providerUrl === 'string') { 34 | return isHttp(providerUrl) 35 | ? new HttpProvider(providerUrl) 36 | : isWs(providerUrl) 37 | ? new WSProvider(providerUrl) 38 | : new HttpProvider(defaultConfig.Default.Chain_URL); 39 | } 40 | try { 41 | const providerType = this.getType(providerUrl); 42 | if (providerType === ProviderType.http || providerType === ProviderType.ws) { 43 | return providerUrl; 44 | } else { 45 | throw new Error('cannot get provider type'); 46 | } 47 | } catch (error) { 48 | throw error; 49 | } 50 | } 51 | private getType(provider: HttpProvider | WSProvider) { 52 | if (provider instanceof HttpProvider) { 53 | return ProviderType.http; 54 | } 55 | if (provider instanceof WSProvider) { 56 | return ProviderType.ws; 57 | } 58 | throw new Error('provider is not correct'); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/abi/utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * @hidden 5 | */ 6 | 7 | import { isObject, isArray } from '@harmony-js/utils'; 8 | import { BN } from '@harmony-js/crypto'; 9 | 10 | export const jsonInterfaceMethodToString = (json: any): string => { 11 | if (isObject(json) && json.name && json.name.includes('(')) { 12 | return json.name; 13 | } 14 | 15 | return `${json.name}(${flattenTypes(false, json.inputs).join(',')})`; 16 | }; 17 | 18 | export const flattenTypes = (includeTuple: any, puts: any[]) => { 19 | // console.log("entered _flattenTypes. inputs/outputs: " + puts) 20 | const types: any[] = []; 21 | 22 | puts.forEach((param: any) => { 23 | if (typeof param.components === 'object') { 24 | if (param.type.substring(0, 5) !== 'tuple') { 25 | throw new Error('components found but type is not tuple; report on GitHub'); 26 | } 27 | let suffix = ''; 28 | const arrayBracket = param.type.indexOf('['); 29 | if (arrayBracket >= 0) { 30 | suffix = param.type.substring(arrayBracket); 31 | } 32 | const result = flattenTypes(includeTuple, param.components); 33 | // console.log("result should have things: " + result) 34 | if (isArray(result) && includeTuple) { 35 | // console.log("include tuple word, and its an array. joining...: " + result.types) 36 | types.push(`tuple(${result.join(',')})${suffix}`); 37 | } else if (!includeTuple) { 38 | // console.log("don't include tuple, but its an array. joining...: " + result) 39 | types.push(`(${result.join(',')})${suffix}`); 40 | } else { 41 | // console.log("its a single type within a tuple: " + result.types) 42 | types.push(`(${result})`); 43 | } 44 | } else { 45 | // console.log("its a type and not directly in a tuple: " + param.type) 46 | types.push(param.type); 47 | } 48 | }); 49 | 50 | return types; 51 | }; 52 | 53 | export function bnToString(result: any): string | any { 54 | if (BN.isBN(result)) { 55 | return result.toString(); 56 | } else { 57 | return result; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/harmony-network/src/tracker/subscribeTracker.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | * @hidden 5 | */ 6 | 7 | import { Messenger } from '../messenger/messenger'; 8 | import { WSProvider } from '../providers/ws'; 9 | import { BaseBlockTracker } from './baseTracker'; 10 | import { RPCMethod } from '../rpcMethod/rpc'; 11 | 12 | export class SubscribeBlockTracker extends BaseBlockTracker { 13 | messenger: Messenger; 14 | subscriptionId: any; 15 | // tslint:disable-next-line: variable-name 16 | 17 | constructor(messenger: Messenger, opts = {}) { 18 | // parse + validate args 19 | if (!messenger) { 20 | throw new Error('SubscribeBlockTracker - no provider specified.'); 21 | } 22 | if (!(messenger.provider instanceof WSProvider)) { 23 | throw new Error('This provider not supported'); 24 | } 25 | // BaseBlockTracker constructor 26 | super(opts); 27 | // config 28 | this.messenger = messenger; 29 | this.subscriptionId = null; 30 | } 31 | 32 | async checkForLatestBlock() { 33 | const result = await this.getLatestBlock(); 34 | return result; 35 | } 36 | 37 | async _start() { 38 | try { 39 | const blockNumber = await this.messenger.send(RPCMethod.BlockNumber, []); 40 | 41 | if (blockNumber.isError()) { 42 | throw blockNumber.message; 43 | } else if (blockNumber.isResult()) { 44 | const subs = await this.messenger.subscribe(RPCMethod.Subscribe, ['newHeads']); 45 | this.subscriptionId = subs; 46 | subs[0].onData(this._handleSubData); 47 | 48 | this._newPotentialLatest(blockNumber); 49 | } 50 | } catch (error) { 51 | this.emit('error', error); 52 | } 53 | } 54 | 55 | async _end() { 56 | if (this.subscriptionId != null) { 57 | this.messenger.unsubscribe(RPCMethod.UnSubscribe, [this.subscriptionId]); 58 | delete this.subscriptionId; 59 | } 60 | } 61 | 62 | _handleSubData(data: any) { 63 | if ( 64 | // data.method === 'eth_subscription' && 65 | data.params.subscription === this.subscriptionId 66 | ) { 67 | this._newPotentialLatest(data.params.result.number); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /typings/elliptic.d.ts: -------------------------------------------------------------------------------- 1 | import BN from 'bn.js'; 2 | import hash from 'hash.js'; 3 | 4 | declare namespace Elliptic { 5 | type HexEnc = 'hex'; 6 | type Utf8Enc = 'utf8'; 7 | type CurveTypes = 'short' | 'edwards' | 'mont'; 8 | type PrivateKey = 9 | | string 10 | | Buffer 11 | | { x: Buffer; y: Buffer } 12 | | { x: string; y: string }; 13 | 14 | interface Curve { 15 | type: CurveTypes; 16 | n: BN; 17 | g: Point; 18 | decodePoint(msg: Buffer | Array | string, enc?: string): Point; 19 | validate(point: Point): boolean; 20 | } 21 | 22 | interface Point { 23 | x: BN; 24 | y: BN; 25 | inf: boolean; 26 | encode(enc: string, compressed?: boolean): Array; 27 | encodeCompressed(enc?: string): Array; 28 | isInfinity(): boolean; 29 | add(k: BN | Number | Point): Point; 30 | mul(k: BN | Number | Point): Point; 31 | } 32 | 33 | interface EC { 34 | recoverPubKey( 35 | arg0: Uint8Array | null, 36 | rs: { r: Uint8Array | null; s: Uint8Array | null }, 37 | recoveryParam: number | undefined, 38 | ): any; 39 | curve: Curve; 40 | genKeyPair(opt?: GenKeyPairOpt): KeyPair; 41 | keyFromPrivate(priv: string, enc: string): KeyPair; 42 | keyFromPublic(pub: string, enc: string): KeyPair; 43 | } 44 | 45 | interface GenKeyPairOpt { 46 | entropy?: string | Buffer; 47 | entropyEnc?: HexEnc | Utf8Enc; 48 | pers?: string | Buffer; 49 | persEnc?: HexEnc | Utf8Enc; 50 | } 51 | 52 | interface KeyPair { 53 | sign(arg0: Uint8Array | null, arg1: { canonical: boolean }): any; 54 | fromPublic(ec: Curve, pub: BN, enc: string): KeyPair; 55 | fromPrivate(ec: Curve, priv: BN, enc: string): KeyPair; 56 | // this is broken, but we can't fix it without changing the upstream 57 | // library; compact is optional, but optional parameters should always 58 | // _follow_ mandatory ones. 59 | getPublic(compact: boolean, enc: string): string; 60 | getPrivate(enc?: T): T extends HexEnc ? string : BN; 61 | validate(): { result: boolean; reason: string | null }; 62 | } 63 | 64 | export function ec(curve: string): EC; 65 | } 66 | 67 | export = Elliptic; 68 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/utils/encoder.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * @hidden 5 | */ 6 | 7 | import { isArray } from '@harmony-js/utils'; 8 | import { AbiItemModel } from '../models/types'; 9 | import { AbiCoderClass } from '../abi/api'; 10 | 11 | export const methodEncoder = ( 12 | abiCoder: AbiCoderClass, 13 | abiItemModel: AbiItemModel, 14 | deployData: string, 15 | ) => { 16 | if (abiItemModel.isOfType('receive')) { 17 | return undefined; 18 | } 19 | if (abiItemModel.isOfType('fallback')) { 20 | return abiItemModel.contractMethodParameters.length 21 | ? abiItemModel.contractMethodParameters[0] 22 | : undefined; 23 | } 24 | 25 | let encodedParameters = abiCoder.encodeParameters( 26 | abiItemModel.getInputs(), 27 | abiItemModel.contractMethodParameters, 28 | ); 29 | 30 | if (encodedParameters.startsWith('0x')) { 31 | encodedParameters = encodedParameters.slice(2); 32 | } 33 | 34 | if (abiItemModel.isOfType('constructor')) { 35 | if (!deployData) { 36 | throw new Error( 37 | 'The contract has no contract data option set. This is necessary to append the constructor parameters.', 38 | ); 39 | } 40 | 41 | return deployData + encodedParameters; 42 | } 43 | 44 | if (abiItemModel.isOfType('function')) { 45 | return abiItemModel.signature + encodedParameters; 46 | } 47 | 48 | return encodedParameters; 49 | }; 50 | 51 | export const eventFilterEncoder = ( 52 | abiCoder: AbiCoderClass, 53 | abiItemModel: AbiItemModel, 54 | filter: any, 55 | ) => { 56 | const topics: any[] = []; 57 | 58 | abiItemModel.getIndexedInputs().forEach((input) => { 59 | if (filter[input.name]) { 60 | let filterItem = filter[input.name]; 61 | 62 | if (isArray(filterItem)) { 63 | filterItem = filterItem.map((item: any) => { 64 | return abiCoder.encodeParameter(input.type, item); 65 | }); 66 | 67 | topics.push(filterItem); 68 | 69 | return; 70 | } 71 | 72 | topics.push(abiCoder.encodeParameter(input.type, filterItem)); 73 | 74 | return; 75 | } 76 | 77 | topics.push(null); 78 | }); 79 | 80 | return topics; 81 | }; 82 | -------------------------------------------------------------------------------- /packages/harmony-network/src/providers/emitter.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | */ 5 | 6 | import mitt from 'mitt'; 7 | 8 | class Emitter { 9 | handlers?: any = {}; 10 | emitter: mitt.Emitter; 11 | off: (type: string, handler: mitt.Handler) => void; 12 | emit: (type: string, event?: any) => void; 13 | promise: Promise<{}>; 14 | resolve?: any; 15 | reject?: any; 16 | then?: any; 17 | constructor() { 18 | this.emitter = mitt(this.handlers); 19 | this.off = this.emitter.off.bind(this); 20 | this.emit = this.emitter.emit.bind(this); 21 | // tslint:disable-next-line: no-empty 22 | this.promise = new Promise((resolve, reject) => { 23 | this.resolve = resolve; 24 | this.reject = reject; 25 | }); 26 | this.then = this.promise.then.bind(this.promise); 27 | } 28 | 29 | resetHandlers() { 30 | // tslint:disable-next-line: forin 31 | for (const i in this.handlers) { 32 | delete this.handlers[i]; 33 | } 34 | } 35 | on(type: string, handler: mitt.Handler) { 36 | this.emitter.on(type, handler); 37 | return this; 38 | } 39 | once(type: string, handler: mitt.Handler) { 40 | this.emitter.on(type, (e: any) => { 41 | handler(e); 42 | this.removeEventListener(type); 43 | }); 44 | } 45 | 46 | addEventListener(type: string, handler: mitt.Handler) { 47 | this.emitter.on(type, handler); 48 | } 49 | 50 | removeEventListener(type?: string, handler?: mitt.Handler) { 51 | if (!type) { 52 | this.handlers = {}; 53 | return; 54 | } 55 | if (!handler) { 56 | delete this.handlers[type]; 57 | } else { 58 | return this.emitter.off(type, handler); 59 | } 60 | } 61 | onError(error: any) { 62 | this.emitter.on('error', error); 63 | this.removeEventListener('*'); 64 | } 65 | onData(data: any) { 66 | this.emitter.on('data', data); 67 | this.removeEventListener('*'); 68 | } 69 | listenerCount(listenKey: any) { 70 | let count = 0; 71 | Object.keys(this.handlers).forEach((val) => { 72 | if (listenKey === val) { 73 | count += 1; 74 | } 75 | }); 76 | return count; 77 | } 78 | } 79 | 80 | export { Emitter }; 81 | -------------------------------------------------------------------------------- /scripts/jest/jest.src.config.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | transform: { 3 | // '^.+\\.(t|j)s$': require.resolve('./transformer.js') 4 | '^.+\\.(t)s$': 'ts-jest', 5 | }, 6 | globals: { 7 | 'ts-jest': { 8 | babelConfig: true, 9 | tsConfig: './tsconfig.test.json', 10 | }, 11 | }, 12 | testMatch: [ 13 | // '/packages/**/test/?(*.)+(spec|test).js', 14 | '/packages/harmony-core/test/?(*.)+(spec|test).ts', 15 | '/packages/harmony-account/test/?(*.)+(spec|test).ts', 16 | '/packages/harmony-network/test/?(*.)+(spec|test).ts', 17 | '/packages/harmony-crypto/test/?(*.)+(spec|test).ts', 18 | '/packages/harmony-contract/test/?(*.)+(spec|test).ts', 19 | '/packages/harmony-transaction/test/?(*.)+(spec|test).ts', 20 | '/packages/harmony-staking/test/?(*.)+(spec|test).ts', 21 | '/packages/harmony-utils/test/?(*.)+(spec|test).ts', 22 | ], 23 | moduleDirectories: ['src', 'node_modules'], 24 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], 25 | moduleNameMapper: { 26 | 'cross-fetch': 'jest-fetch-mock', 27 | }, 28 | testURL: 'http://localhost', 29 | coverageThreshold: { 30 | global: { 31 | branches: 10, 32 | functions: 10, 33 | lines: 10, 34 | statements: 10, 35 | }, 36 | }, 37 | rootDir: process.cwd(), 38 | roots: ['/packages', '/scripts', '/e2e'], 39 | collectCoverageFrom: [ 40 | // 'packages/!(harmony-core)/src/**/*.ts', 41 | 'packages/harmony-core/src/**/*.ts', 42 | 'packages/harmony-utils/src/**/*.ts', 43 | 'packages/harmony-crypto/src/**/*.ts', 44 | 'packages/harmony-transaction/src/**/*.ts', 45 | 'packages/harmony-staking/src/**/*.ts', 46 | 'packages/harmony-contract/src/**/*.ts', 47 | ], 48 | // timers: 'fake', 49 | setupFiles: ['/scripts/jest/jest.setup.js'], 50 | setupTestFrameworkScriptFile: '/scripts/jest/jest.framework-setup.js', 51 | testEnvironment: process.env.NODE_ENV === 'development' ? 'node' : 'jsdom', 52 | collectCoverage: true, 53 | automock: false, 54 | watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'], 55 | }; 56 | 57 | module.exports = config; 58 | -------------------------------------------------------------------------------- /packages/harmony-network/src/subscriptions/Subscription.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | */ 5 | 6 | import { Messenger } from '../messenger/messenger'; 7 | import { RPCMethod } from '../rpcMethod/rpc'; 8 | import { WSProvider } from '../providers/ws'; 9 | import { RPCRequestPayload } from '../types'; 10 | 11 | export class SubscriptionMethod extends WSProvider { 12 | param: any; 13 | options: any; 14 | shardID: number; 15 | messenger: Messenger; 16 | 17 | subscriptionId: any = null; 18 | constructor(param: any, options: any, messenger: Messenger, shardID: number = 0) { 19 | super(shardID !== 0 ? messenger.getShardProvider(shardID).url : messenger.provider.url); 20 | this.shardID = shardID; 21 | this.param = param; 22 | this.options = options; 23 | this.messenger = messenger; 24 | } 25 | 26 | constructPayload(method: string, param: any, options?: any): RPCRequestPayload { 27 | let rpcMethod = method; 28 | const payload: any = []; 29 | payload.push(param); 30 | if (options) { 31 | payload.push(options); 32 | } 33 | rpcMethod = this.messenger.setRPCPrefix(method, this.messenger.chainPrefix); 34 | return this.jsonRpc.toPayload(rpcMethod, payload); 35 | } 36 | 37 | async start() { 38 | const subscribePayload = this.constructPayload(RPCMethod.Subscribe, this.param, this.options); 39 | try { 40 | const id = await super.subscribe(subscribePayload); 41 | this.subscriptionId = id; 42 | this.on(id, (result: any) => { 43 | const output = this.onNewSubscriptionItem(result); 44 | 45 | this.emitter.emit('data', output); 46 | }); 47 | this.once('error', (error) => { 48 | this.removeEventListener(id); 49 | this.emitter.emit('error', error); 50 | this.removeEventListener('*'); 51 | }); 52 | } catch (error) { 53 | this.emitter.emit('error', error); 54 | this.removeEventListener('*'); 55 | } 56 | return this; 57 | } 58 | unsubscribe() { 59 | const unsubscribePayload = this.constructPayload(RPCMethod.UnSubscribe, this.subscriptionId); 60 | return super.unsubscribe(unsubscribePayload); 61 | } 62 | onNewSubscriptionItem(subscriptionItem: any) { 63 | return subscriptionItem; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /scripts/webpack/webpack.config.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | // tslint:disable-next-line: no-implicit-dependencies 3 | import TerserPlugin from 'terser-webpack-plugin'; 4 | // tslint:disable-next-line: no-implicit-dependencies 5 | import { Configuration } from 'webpack'; 6 | 7 | // // tslint:disable-next-line: no-implicit-dependencies 8 | // import {createVariants} from 'parallel-webpack'; 9 | 10 | import { packageList, PackageItem } from './packagesForWP'; 11 | 12 | function createBatchConfig(list: PackageItem[]) { 13 | return list.map((l: PackageItem) => { 14 | const entryBase = {}; 15 | entryBase[l.name] = [`./packages/${l.dest}/dist/index.js`]; 16 | 17 | const batchBaseConfig = { 18 | entry: entryBase, 19 | mode: 'production', 20 | module: { 21 | rules: [ 22 | { 23 | test: /\.js$/, 24 | // use: { 25 | // loader: 'babel-loader', 26 | // }, 27 | }, 28 | ], 29 | }, 30 | devtool: 'source-map', 31 | resolve: { 32 | symlinks: true, 33 | extensions: ['.js'], 34 | }, 35 | }; 36 | 37 | const batchClientConfig = { 38 | ...batchBaseConfig, 39 | optimization: { 40 | minimize: true, 41 | minimizer: [ 42 | new TerserPlugin({ 43 | terserOptions: { 44 | ecma: 6, 45 | compress: true, 46 | mangle: true, 47 | toplevel: false, 48 | output: { 49 | beautify: false, 50 | comments: false, 51 | }, 52 | }, 53 | parallel: true, 54 | sourceMap: true, 55 | }), 56 | ], 57 | }, 58 | output: { 59 | libraryTarget: 'umd', 60 | library: `${l.name}`, 61 | filename: `${l.name}.browser.js`, 62 | // filename: '[name].browser.js', 63 | path: path.join(__dirname, '../../', 'dist'), 64 | }, 65 | }; 66 | 67 | return [batchBaseConfig, batchClientConfig]; 68 | }); 69 | } 70 | 71 | function reduceDimension(arr: any[]) { 72 | return Array.prototype.concat.apply([], arr); 73 | } 74 | 75 | const batch: Configuration = reduceDimension(createBatchConfig(packageList)); 76 | 77 | // tslint:disable-next-line: no-default-export 78 | export default batch; 79 | -------------------------------------------------------------------------------- /packages/harmony-contract/test/abiCoder.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @ignore 4 | */ 5 | 6 | import { AbiCoder } from '../src/abi/abiCoder'; 7 | import { BN } from '@harmony-js/crypto'; 8 | import { isArray } from '@harmony-js/utils'; 9 | import { abis } from './fixtures/abiv2'; 10 | 11 | function getValues(object: any, format?: any, named?: any): any { 12 | if (isArray(object)) { 13 | // tslint:disable-next-line: no-shadowed-variable 14 | const result: any[] = []; 15 | // tslint:disable-next-line: no-shadowed-variable 16 | object.forEach((object: any) => { 17 | result.push(getValues(object, format, named)); 18 | }); 19 | return result; 20 | } 21 | 22 | switch (object.type) { 23 | case 'number': 24 | return new BN(object.value); 25 | case 'boolean': 26 | case 'string': 27 | return object.value; 28 | 29 | case 'buffer': 30 | return object.value; 31 | 32 | case 'tuple': 33 | const result = getValues(object.value, format, named); 34 | if (named) { 35 | const namedResult: any = {}; 36 | result.forEach((value: any, index: number) => { 37 | namedResult['r' + String(index)] = value; 38 | }); 39 | return namedResult; 40 | } 41 | return result; 42 | 43 | default: 44 | throw new Error('invalid type - ' + object.type); 45 | } 46 | } 47 | 48 | describe('test abiv2', () => { 49 | it('should encode abiv2', () => { 50 | const coder = new AbiCoder(); 51 | for (const abiItem of abis) { 52 | const test: any = abiItem; 53 | const values = getValues(JSON.parse(test.values)); 54 | const types = JSON.parse(test.types); 55 | const expected = test.result; 56 | const encoded = coder.encode(types, values); 57 | 58 | expect(JSON.stringify(encoded)).toEqual(JSON.stringify(expected)); 59 | 60 | const namedEncoded = coder.encode(types, values); 61 | 62 | expect(JSON.stringify(namedEncoded)).toEqual(JSON.stringify(expected)); 63 | } 64 | }); 65 | it('should decode abiv2', () => { 66 | const coder = new AbiCoder(); 67 | for (const abiItem of abis) { 68 | const test = abiItem; 69 | const values = getValues(JSON.parse(test.values)); 70 | const types = JSON.parse(test.types); 71 | const expected = test.result; 72 | const decoded = coder.decode(types, expected); 73 | expect(JSON.stringify(decoded)).toEqual(JSON.stringify(values)); 74 | } 75 | }); 76 | }); 77 | -------------------------------------------------------------------------------- /packages/harmony-crypto/test/address.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @ignore 4 | */ 5 | 6 | import { getAddress, HarmonyAddress } from '../src/address'; 7 | import { randomBytes } from '../src/random'; 8 | import { toBech32, fromBech32, HRP, tHRP } from '../src/bech32'; 9 | import { toChecksumAddress, isValidChecksumAddress } from '../src/keyTool'; 10 | const bytes = randomBytes(20); 11 | const bytesWith0x = '0x' + bytes; 12 | const checksum = toChecksumAddress(bytesWith0x); 13 | const bech32 = toBech32(checksum, HRP); 14 | const bech32Testnet = toBech32(checksum, tHRP); 15 | 16 | describe('test address', () => { 17 | it('should test HamonyAddress', () => { 18 | const hAddress = new HarmonyAddress(bytes); 19 | expect(hAddress.basic).toEqual(bytes); 20 | expect(hAddress.basicHex).toEqual(bytesWith0x); 21 | expect(hAddress.checksum).toEqual(checksum); 22 | expect(hAddress.bech32).toEqual(bech32); 23 | expect(hAddress.bech32TestNet).toEqual(bech32Testnet); 24 | expect(getAddress(bytes).basic).toEqual(bytes); 25 | expect(getAddress(bytes).basicHex).toEqual(bytesWith0x); 26 | expect(getAddress(bytes).checksum).toEqual(checksum); 27 | expect(getAddress(bytes).bech32).toEqual(bech32); 28 | expect(getAddress(bytes).bech32TestNet).toEqual(bech32Testnet); 29 | expect(toBech32(checksum)).toEqual(bech32); 30 | expect(fromBech32(bech32, HRP)).toEqual(checksum); 31 | expect(fromBech32(bech32)).toEqual(checksum); 32 | expect(fromBech32(bech32Testnet, tHRP)).toEqual(checksum); 33 | expect(HarmonyAddress.isValidBasic(bytes)).toEqual(true); 34 | expect(HarmonyAddress.isValidChecksum(checksum)).toEqual(true); 35 | expect(HarmonyAddress.isValidBech32(bech32)).toEqual(true); 36 | expect(HarmonyAddress.isValidBech32TestNet(bech32Testnet)).toEqual(true); 37 | expect(isValidChecksumAddress(checksum)).toEqual(true); 38 | try { 39 | // tslint:disable-next-line: no-unused-expression 40 | getAddress('111').checksum; 41 | } catch (error) { 42 | expect(error.message).toEqual(`"111" is an invalid address format`); 43 | } 44 | try { 45 | fromBech32(bech32, tHRP); 46 | } catch (error) { 47 | expect(error.message).toEqual(`Expected hrp to be ${tHRP} but got ${HRP}`); 48 | } 49 | try { 50 | fromBech32(checksum, tHRP); 51 | } catch (error) { 52 | expect(error.message).toEqual(`Invalid bech32 address`); 53 | } 54 | try { 55 | toBech32('111', tHRP); 56 | } catch (error) { 57 | expect(error.message).toEqual(`Invalid address format.`); 58 | } 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/events/eventFactory.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * @hidden 5 | */ 6 | 7 | import { isArray } from '@harmony-js/utils'; 8 | import { AbiCoderClass } from '../abi/api'; 9 | import { AbiModel, AbiItemModel } from '../models/types'; 10 | import { Contract } from '../contract'; 11 | import { EventMethod } from './event'; 12 | import { inputBlockNumberFormatter } from '../utils/formatter'; 13 | import { eventFilterEncoder } from '../utils/encoder'; 14 | 15 | export class EventFactory { 16 | contract: Contract; 17 | abiModel: any | AbiModel; 18 | abiCoder: AbiCoderClass; 19 | private eventKeys: string[]; 20 | 21 | // constructor 22 | constructor(contract: Contract) { 23 | this.contract = contract; 24 | this.abiModel = this.contract.abiModel; 25 | this.abiCoder = this.contract.abiCoder; 26 | this.eventKeys = this.mapEventKeys(); 27 | } 28 | 29 | addEventsToContract() { 30 | this.eventKeys.forEach((key: string) => { 31 | const newObject: any = {}; 32 | newObject[key] = (params: any) => 33 | new EventMethod( 34 | key, 35 | // params, 36 | this.map(this.abiModel.getEvent(key), this.contract, params), 37 | this.abiModel.getEvent(key), 38 | this.contract, 39 | ); 40 | Object.assign(this.contract.events, newObject); 41 | }); 42 | return this.contract; 43 | } 44 | /** 45 | * @function mapMethodKeys 46 | * @return {string[]} {description} 47 | */ 48 | private mapEventKeys(): string[] { 49 | return Object.keys(this.abiModel.abi.events); 50 | } 51 | 52 | private map(abiItemModel: AbiItemModel, contract: Contract, options: any) { 53 | if (!options) { 54 | options = {}; 55 | } 56 | 57 | if (!isArray(options.topics)) { 58 | options.topics = []; 59 | } 60 | 61 | if (typeof options.fromBlock !== 'undefined') { 62 | options.fromBlock = inputBlockNumberFormatter(options.fromBlock); 63 | } 64 | // else if (contract.defaultBlock !== null) { 65 | // options.fromBlock = contract.defaultBlock; 66 | // } 67 | 68 | if (typeof options.toBlock !== 'undefined') { 69 | options.toBlock = inputBlockNumberFormatter(options.toBlock); 70 | } 71 | 72 | if (typeof options.filter !== 'undefined') { 73 | options.topics = options.topics.concat( 74 | eventFilterEncoder(this.abiCoder, abiItemModel, options.filter), 75 | ); 76 | delete options.filter; 77 | } 78 | 79 | if (!abiItemModel.anonymous) { 80 | options.topics.unshift(abiItemModel.signature); 81 | } 82 | 83 | if (!options.address) { 84 | options.address = contract.address; 85 | } 86 | 87 | return options; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /packages/harmony-network/src/providers/baseProvider.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | * @hidden 5 | */ 6 | 7 | import { ReqMiddleware, ResMiddleware, MiddlewareType } from '../types'; 8 | import { RPCMethod } from '../rpcMethod/rpc'; 9 | 10 | class BaseProvider { 11 | middlewares = { 12 | request: { 13 | use: (fn: ReqMiddleware, match: string | RPCMethod | RegExp = '*') => { 14 | this.pushMiddleware(fn, MiddlewareType.REQ, match); 15 | }, 16 | }, 17 | response: { 18 | use: (fn: ResMiddleware, match: string | RPCMethod | RegExp = '*') => { 19 | this.pushMiddleware(fn, MiddlewareType.RES, match); 20 | }, 21 | }, 22 | }; 23 | protected url: string; 24 | protected reqMiddleware: ReqMiddleware = new Map().set('*', []); 25 | protected resMiddleware: ResMiddleware = new Map().set('*', []); 26 | 27 | constructor( 28 | url: string, 29 | reqMiddleware: ReqMiddleware = new Map(), 30 | resMiddleware: ResMiddleware = new Map(), 31 | ) { 32 | this.reqMiddleware = reqMiddleware; 33 | this.resMiddleware = resMiddleware; 34 | this.url = url; 35 | } 36 | 37 | protected pushMiddleware(fn: any, type: MiddlewareType, match: string | RPCMethod | RegExp) { 38 | if (type !== MiddlewareType.REQ && type !== MiddlewareType.RES) { 39 | throw new Error('Please specify the type of middleware being added'); 40 | } 41 | if (type === MiddlewareType.REQ) { 42 | const current = this.reqMiddleware.get(match) || []; 43 | this.reqMiddleware.set(match, [...current, fn]); 44 | } else { 45 | const current = this.resMiddleware.get(match) || []; 46 | this.resMiddleware.set(match, [...current, fn]); 47 | } 48 | } 49 | protected getMiddleware(method: RPCMethod | string): [ReqMiddleware[], ResMiddleware[]] { 50 | const requests: ReqMiddleware[] = []; 51 | const responses: ResMiddleware[] = []; 52 | 53 | for (const [key, transformers] of this.reqMiddleware.entries()) { 54 | if (typeof key === 'string' && key !== '*' && key === method) { 55 | requests.push(...transformers); 56 | } 57 | 58 | if (key instanceof RegExp && key.test(method)) { 59 | requests.push(...transformers); 60 | } 61 | 62 | if (key === '*') { 63 | requests.push(...transformers); 64 | } 65 | } 66 | 67 | for (const [key, transformers] of this.resMiddleware.entries()) { 68 | if (typeof key === 'string' && key !== '*' && key === method) { 69 | responses.push(...transformers); 70 | } 71 | 72 | if (key instanceof RegExp && key.test(method)) { 73 | responses.push(...transformers); 74 | } 75 | 76 | if (key === '*') { 77 | responses.push(...transformers); 78 | } 79 | } 80 | 81 | return [requests, responses]; 82 | } 83 | } 84 | 85 | export { BaseProvider }; 86 | -------------------------------------------------------------------------------- /scripts/projects.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as fs from 'fs'; 3 | // tslint:disable-next-line: no-implicit-dependencies 4 | import webpack from 'webpack'; 5 | // tslint:disable-next-line: no-implicit-dependencies 6 | import camelCase from 'camelcase'; 7 | 8 | export const rootPath = path.resolve(__dirname, '../'); 9 | export const includesPath = path.join(rootPath, 'includes'); 10 | export const packagesPath = path.join(rootPath, 'packages'); 11 | 12 | export const preProcessProjects = { 13 | preprocess: [ 14 | { 15 | name: 'elliptic', 16 | path: path.resolve(__dirname, '../node_modules/elliptic'), 17 | entry: 'lib/elliptic.js', 18 | outDir: path.join(includesPath, 'elliptic'), 19 | }, 20 | ], 21 | }; 22 | 23 | export function preProcessFunc(project) { 24 | const modules = project.preprocess.map((mod) => { 25 | return new Promise((resolve, reject) => { 26 | const compiler = webpack({ 27 | entry: { 28 | [mod.name]: path.join(mod.path, mod.entry), 29 | }, 30 | output: { 31 | filename: '[name].js', 32 | library: mod.name, 33 | libraryTarget: 'commonjs2', 34 | path: mod.outDir, 35 | }, 36 | mode: 'production', 37 | optimization: { 38 | minimize: false, 39 | }, 40 | }); 41 | 42 | compiler.run((err, stats) => { 43 | if (err) { 44 | reject(err); 45 | } else { 46 | // logPreProcess( 47 | // `Successfully preprocessed ${Object.keys( 48 | // stats.compilation.assets, 49 | // ).join(' ,')}`, 50 | // ); 51 | resolve(stats); 52 | } 53 | }); 54 | }); 55 | }); 56 | 57 | return Promise.all(modules); 58 | } 59 | 60 | export const projects = fs 61 | .readdirSync(packagesPath) 62 | .filter((p) => fs.lstatSync(path.join(packagesPath, p)).isDirectory()) 63 | .map((p) => { 64 | const pkgName = path.basename(p); 65 | const pkgGlobalName = camelCase(pkgName); 66 | const pkgPath = path.join(packagesPath, p); 67 | const pkgSrc = path.join(pkgPath, 'src'); 68 | const pkgScopedName = `@harmony-js/${p.replace('harmony-', '')}`; 69 | const pkgDist = path.join(pkgPath, 'dist'); 70 | 71 | const pkgUmd = path.join(pkgDist, 'index.umd.js'); 72 | const pkgEsm = path.join(pkgDist, 'index.esm.js'); 73 | const pkgSystem = path.join(pkgDist, 'index.system.js'); 74 | const pkgAmd = path.join(pkgDist, 'index.amd.js'); 75 | const pkgCjs = path.join(pkgDist, 'index.cjs.js'); 76 | const pkgIife = path.join(pkgDist, 'index.js'); 77 | return { 78 | name: pkgName, 79 | globalName: pkgGlobalName, 80 | scopedName: pkgScopedName, 81 | path: pkgPath, 82 | src: pkgSrc, 83 | dist: pkgDist, 84 | umd: pkgUmd, 85 | esm: pkgEsm, 86 | cjs: pkgCjs, 87 | amd: pkgAmd, 88 | iife: pkgIife, 89 | system: pkgSystem, 90 | }; 91 | }); 92 | -------------------------------------------------------------------------------- /packages/harmony-staking/README.md: -------------------------------------------------------------------------------- 1 | # @harmony-js/staking 2 | 3 | This package provides a collection of apis to create, sign/send staking transaction, and receive confirm/receipt. 4 | 5 | ## Installation 6 | 7 | ``` 8 | npm install @harmony-js/staking 9 | ``` 10 | 11 | ## Usage 12 | 13 | Create a Harmony instance connecting to testnet 14 | 15 | ```javascript 16 | const { Harmony } = require('@harmony-js/core'); 17 | const { 18 | ChainID, 19 | ChainType, 20 | hexToNumber, 21 | numberToHex, 22 | fromWei, 23 | Units, 24 | Unit, 25 | } = require('@harmony-js/utils'); 26 | 27 | const hmy = new Harmony( 28 | 'https://api.s0.b.hmny.io/', 29 | { 30 | chainType: ChainType.Harmony, 31 | chainId: ChainID.HmyTestnet, 32 | }, 33 | ); 34 | ``` 35 | Below, examples show how to send delegate, undelegate, and collect rewards staking transactions. First, set the chainId, gasLimit, gasPrice for all subsequent staking transactions 36 | ```javascript 37 | hmy.stakings.setTxParams({ 38 | gasLimit: 25000, 39 | gasPrice: numberToHex(new hmy.utils.Unit('1').asGwei().toWei()), 40 | chainId: 2 41 | }); 42 | ``` 43 | Note: create and edit validator transactions are not fully supported in the sdk 44 | 45 | Create delegate staking transaction 46 | ```javascript 47 | const delegate = hmy.stakings.delegate({ 48 | delegatorAddress: 'one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7', 49 | validatorAddress: 'one1vfqqagdzz352mtvdl69v0hw953hm993n6v26yl', 50 | amount: numberToHex(new Unit(1000).asOne().toWei()) 51 | }); 52 | const delegateStakingTx = delegate.build(); 53 | ``` 54 | 55 | Sign and send the delegate transaction and receive confirmation 56 | ```javascript 57 | // key corresponds to one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7, only has testnet balance 58 | hmy.wallet.addByPrivateKey('45e497bd45a9049bcb649016594489ac67b9f052a6cdf5cb74ee2427a60bf25e'); 59 | 60 | hmy.wallet.signStaking(delegateStakingTx).then(signedTxn => { 61 | signedTxn.sendTransaction().then(([tx, hash]) => { 62 | console.log(hash); 63 | signedTxn.confirm(hash).then(response => { 64 | console.log(response.receipt); 65 | }); 66 | }); 67 | }); 68 | ``` 69 | 70 | Similarily, undelegate and collect reward transactions can be composed, signed and sent 71 | Create undelegate staking transaction 72 | ```javascript 73 | const undelegate = hmy.stakings.undelegate({ 74 | delegatorAddress: 'one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7', 75 | validatorAddress: 'one1vfqqagdzz352mtvdl69v0hw953hm993n6v26yl', 76 | amount: numberToHex(new Unit(1000).asOne().toWei()) 77 | }); 78 | const undelegateStakingTx = undelegate.build(); 79 | ``` 80 | 81 | Create collect rewards staking transaction 82 | ```javascript 83 | const collectRewards = hmy.stakings.collectRewards({ 84 | delegatorAddress: 'one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7' 85 | }); 86 | const collectRewardsStakingTx = collectRewards.build(); 87 | ``` 88 | 89 | Also, similar to normal transaction, signing and sending can be performed asynchronously. -------------------------------------------------------------------------------- /packages/harmony-transaction/src/factory.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * ## hhahaha 3 | * 4 | * @packageDocumentation 5 | * @module harmony-transaction 6 | */ 7 | 8 | import { getContractAddress, getAddress } from '@harmony-js/crypto'; 9 | import { Messenger } from '@harmony-js/network'; 10 | import { Transaction } from './transaction'; 11 | import { ShardingTransaction } from './shardingTransaction'; 12 | import { TxParams, TxStatus } from './types'; 13 | 14 | export class TransactionFactory { 15 | static getContractAddress(tx: Transaction) { 16 | const { from, nonce } = tx.txParams; 17 | return getAddress( 18 | getContractAddress(getAddress(from).checksum, Number.parseInt(`${nonce}`, 10)), 19 | ).checksum; 20 | } 21 | 22 | messenger: Messenger; 23 | constructor(messenger: Messenger) { 24 | this.messenger = messenger; 25 | } 26 | setMessenger(messenger: Messenger) { 27 | this.messenger = messenger; 28 | } 29 | 30 | /** 31 | * Create a new Transaction 32 | * @params 33 | * ``` 34 | * // to: Address of the receiver 35 | * // value: value transferred in wei 36 | * // gasLimit: the maximum gas would pay, can use string 37 | * // shardID: send token from shardID 38 | * // toShardId: send token to shardID 39 | * // gasPrice: you can use Unit class, and use Gwei, then remember to use toWei(), which will be transformed to BN 40 | * ``` 41 | * 42 | * @example 43 | * ```javascript 44 | * const txn = hmy.transactions.newTx({ 45 | * to: 'one166axnkjmghkf3df7xfvd0hn4dft8kemrza4cd2', 46 | * value: '10000', 47 | * gasLimit: '210000', 48 | * shardID: 0, 49 | * toShardID: 0, 50 | * gasPrice: new hmy.utils.Unit('100').asGwei().toWei(), 51 | * }); 52 | * ``` 53 | */ 54 | newTx(txParams?: TxParams | any, sharding: boolean = false): Transaction { 55 | if (!sharding) { 56 | return new Transaction(txParams, this.messenger, TxStatus.INTIALIZED); 57 | } 58 | return new ShardingTransaction(txParams, this.messenger, TxStatus.INTIALIZED); 59 | } 60 | 61 | /** 62 | * clone the transaction 63 | * 64 | * @param transaction 65 | * 66 | * @example 67 | * ```javascript 68 | * const cloneTxn = hmy.transactions.clone(txn); 69 | * console.log(cloneTxn) 70 | * ``` 71 | */ 72 | clone(transaction: Transaction): Transaction { 73 | return new Transaction(transaction.txParams, this.messenger, TxStatus.INTIALIZED); 74 | } 75 | 76 | /** 77 | * 78 | * @example 79 | * ```javascript 80 | * txHash = '0xf8698085174876e8008252088080949d72989b68777a1f3ffd6f1db079f1928373ee52830186a08027a0ab8229ff5d5240948098f26372eaed9ab2e9be23e8594b08e358ca56a47f8ae9a0084e5c4d1fec496af444423d8a714f65c079260ff01a1be1de7005dd424adf44' 81 | * 82 | * const recoverTx = hmy.transactions.recover(txHash); 83 | * console.log(recoverTx); 84 | * ``` 85 | */ 86 | recover(txHash: string): Transaction { 87 | const newTxn = new Transaction({}, this.messenger, TxStatus.INTIALIZED); 88 | newTxn.recover(txHash); 89 | return newTxn; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /packages/harmony-network/src/providers/baseSocket.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | * @hidden 5 | */ 6 | 7 | import { isWs } from '@harmony-js/utils'; 8 | import mitt from 'mitt'; 9 | import { BaseProvider } from './baseProvider'; 10 | 11 | export enum SocketConnection { 12 | READY = 'ready', 13 | CONNECT = 'connect', 14 | ERROR = 'error', 15 | CLOSE = 'close', 16 | } 17 | 18 | export enum SocketState { 19 | SOCKET_MESSAGE = 'socket_message', 20 | SOCKET_READY = 'socket_ready', 21 | SOCKET_CLOSE = 'socket_close', 22 | SOCKET_ERROR = 'socket_error', 23 | SOCKET_CONNECT = 'socket_connect', 24 | SOCKET_NETWORK_CHANGED = 'socket_networkChanged', 25 | SOCKET_ACCOUNTS_CHANGED = 'socket_accountsChanged', 26 | } 27 | 28 | export enum EmittType { 29 | INSTANCE = 'instance', 30 | PUBSUB = 'pubsub', 31 | } 32 | 33 | class BaseSocket extends BaseProvider { 34 | url: string; 35 | emitter: mitt.Emitter; 36 | handlers: any = {}; 37 | constructor(url: string) { 38 | super(url); 39 | if (!isWs(url)) { 40 | throw new Error(`${url} is not websocket`); 41 | } 42 | this.url = url; 43 | this.emitter = mitt(this.handlers); 44 | } 45 | resetHandlers() { 46 | // tslint:disable-next-line: forin 47 | for (const i in this.handlers) { 48 | delete this.handlers[i]; 49 | } 50 | } 51 | 52 | once(type: string, handler: mitt.Handler) { 53 | this.emitter.on(type, handler); 54 | this.removeEventListener(type); 55 | } 56 | 57 | addEventListener(type: string, handler: mitt.Handler) { 58 | this.emitter.on(type, handler); 59 | } 60 | 61 | removeEventListener(type?: string, handler?: mitt.Handler) { 62 | if (!type) { 63 | this.handlers = {}; 64 | return; 65 | } 66 | if (!handler) { 67 | delete this.handlers[type]; 68 | } else { 69 | return this.emitter.off(type, handler); 70 | } 71 | } 72 | reset() { 73 | this.removeEventListener('*'); 74 | // this.registerEventListeners(); 75 | } 76 | removeAllSocketListeners() { 77 | this.removeEventListener(SocketState.SOCKET_MESSAGE); 78 | this.removeEventListener(SocketState.SOCKET_READY); 79 | this.removeEventListener(SocketState.SOCKET_CLOSE); 80 | this.removeEventListener(SocketState.SOCKET_ERROR); 81 | this.removeEventListener(SocketState.SOCKET_CONNECT); 82 | } 83 | 84 | onReady(event: any) { 85 | this.emitter.emit(SocketConnection.READY, event); 86 | this.emitter.emit(SocketState.SOCKET_READY, event); 87 | } 88 | onError(error: any) { 89 | this.emitter.emit(SocketConnection.ERROR, error); 90 | this.emitter.emit(SocketState.SOCKET_ERROR, error); 91 | this.removeAllSocketListeners(); 92 | this.removeEventListener('*'); 93 | } 94 | onClose(error = null) { 95 | this.emitter.emit(SocketConnection.CLOSE, error); 96 | this.emitter.emit(SocketState.SOCKET_CLOSE, error); 97 | this.removeAllSocketListeners(); 98 | this.removeEventListener('*'); 99 | } 100 | } 101 | 102 | export { BaseSocket }; 103 | -------------------------------------------------------------------------------- /TYPEDOC.md: -------------------------------------------------------------------------------- 1 | # Harmony JS-SDK Documentation 2 | 3 | ## [CLICK ME!!](https://harmony-js-sdk-doc.s3-us-west-1.amazonaws.com/index.html) to see the documentation 4 | 5 | # metaDocumentation 6 | ## Summary 7 | The following content demonstrate how to generate our documentation! 8 | 9 | ## Step 1: Generate Documentation 10 | 11 | ### Introduction of TypeDoc 12 | [TypeDoc is used to generate HTML](https://typedoc.org/api/index.html) 13 | > See [TypeDoc command line arguments](https://typedoc.org/guides/options/), to understand how to use them. 14 | > Using `typedoc --help` to see them 15 | > 16 | > **For example:** 17 | > `typedoc --name ` to set the name of header 18 | > `typedoc --theme ` to set the theme of documation 19 | > `typedoc --readme ` path to readme file that should be displayed on the index page. 20 | > `typedoc --ignoreCompilerErrors` Should TypeDoc generate documentation pages even after the compiler has returned errors? 21 | 22 | ### Install TypeDoc 23 | Local installation (prefered) 24 | ``` 25 | $ npm install typedoc --save-dev 26 | ``` 27 | 28 | Golbal CLI installation 29 | ``` 30 | $ npm install --global typedoc 31 | ``` 32 | 33 | ### Install Environemnt 34 | ``` 35 | $ npm install 36 | ``` 37 | 38 | ### Generate HTML 39 | ``` 40 | $ cd docs 41 | $ npx typedoc --out ./build ../packages/ --ignoreCompilerErrors --theme default --name Harmony_SDK_Doc --readme ../README.md 42 | ``` 43 | 44 | ### See the generated doc at local 45 | 46 | >open the `index.html` under the path `sdk/docs/build/index.html` 47 | 48 | ## Step 2: Deploy on AWS (harmony core only!) 49 | 50 | ### Create an AWS s3 bucket 51 | Actually, there are just two points needed! 52 | 1. Create an AWS S3 bucket, **UNCHECK** `Block all public access` 53 | 2. Put the files into the bucket, and set the **public permission** to `Grant public read access to this object(s)` 54 | 55 | ### Method 1: Use Console 56 | 57 | [Here](https://docs.aws.amazon.com/AmazonS3/latest/gsg/CreatingABucket.html) is the documentation of AWS, just follow it! 58 | 59 | >Don't forget the two points mentioned above 60 | 61 | ### Method 2: Use AWS CLI 62 | 63 | Reference: [AWS CLI documentation](https://docs.aws.amazon.com/cli/latest/userguide/cli-services-s3-commands.html) 64 | 65 | If you have never used AWS CLI, you need follow these to set up your environment first! 66 | - [Install the AWS CLI version 1](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv1.html) 67 | - [Configuring the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html) 68 | 69 | After that, use AWS CLI to do following 70 | 71 | 1. Create a Bucket 72 | ``` 73 | aws s3 mb s3://harmony-js-sdk-doc 74 | ``` 75 | 76 | 2. List all buckets you have created 77 | ``` 78 | aws s3 ls 79 | ``` 80 | 81 | 3. Uploade the files into bucket 82 | ``` 83 | $ cd build 84 | $ aws s3 cp ./ s3://your-bucket-name --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --recursive 85 | ``` 86 | Here is some explanations 87 | > **./account** 88 | > the path of folder which we want to upload 89 | > 90 | > **s3://harmony-js-sdk-doc** 91 | > the bucket name on AWS S3 92 | > 93 | > **--grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers** 94 | > Grant read access to all user 95 | > 96 | > **--recursive** 97 | > Command is performed on all files or objects under the specified directory or prefix. 98 | 99 | 4. Open the folder in S3 bucket and find `index.html`, get the 100 | `Object URL`, then make it public! -------------------------------------------------------------------------------- /e2e/fixtures/testAccount.json: -------------------------------------------------------------------------------- 1 | { 2 | "Accounts": [ 3 | { 4 | "Address": "0x1a3e7a44ee21101d7D64FBf29B0F6F1fc295F723", 5 | "Private": "27978f895b11d9c737e1ab1623fde722c04b4f9ccb4ab776bf15932cc72d7c66", 6 | "Public": "0x1a3e7a44ee21101d7D64FBf29B0F6F1fc295F723" 7 | }, 8 | { 9 | "Address": "0x10A02A0a6e95a676AE23e2db04BEa3D1B8b7ca2E", 10 | "Private": "371cb68abe6a6101ac88603fc847e0c013a834253acee5315884d2c4e387ebca", 11 | "Public": "0x10A02A0a6e95a676AE23e2db04BEa3D1B8b7ca2E" 12 | }, 13 | { 14 | "Address": "0x3e881F6C36A3A14a2D1816b0A5471d1caBB16F33", 15 | "Private": "3f8af52063c6648be37d4b33559f784feb16d8e5ffaccf082b3657ea35b05977", 16 | "Public": "0x3e881F6C36A3A14a2D1816b0A5471d1caBB16F33" 17 | }, 18 | { 19 | "Address": "0x9d72989b68777a1f3FfD6F1DB079f1928373eE52", 20 | "Private": "df77927961152e6a080ac299e7af2135fc0fb02eb044d0d7bbb1e8c5ad523809", 21 | "Public": "0x9d72989b68777a1f3FfD6F1DB079f1928373eE52" 22 | }, 23 | { 24 | "Address": "0x67957240b6eB045E17B47dcE98102f09aaC03435", 25 | "Private": "fcff43741ad2dd0b232efb159dc47736bbb16f11a79aaeec39b388d06f91116d", 26 | "Public": "0x67957240b6eB045E17B47dcE98102f09aaC03435" 27 | }, 28 | { 29 | "Address": "0xf70fBDB1AD002baDF19024785b1a4bf6F841F558", 30 | "Private": "916d3d78b7f413452434e89f9c1f1d136995ef02d7dc8038e84cc9cef4a02b96", 31 | "Public": "0xf70fBDB1AD002baDF19024785b1a4bf6F841F558" 32 | }, 33 | { 34 | "Address": "0x3f1A559be93C9456Ca75712535Fd522f5EC22c6B", 35 | "Private": "f5967bd87fd2b9dbf51855a2a75ef0a811c84953b3b300ffe90c430a5c856303", 36 | "Public": "0x3f1A559be93C9456Ca75712535Fd522f5EC22c6B" 37 | }, 38 | { 39 | "Address": "0xedD257B4e0F5e7d632c737f4277e93b64DC268FC", 40 | "Private": "f02f7b3bb5aa03aa97f9e030020dd9ca306b209742fafe018104a3207a70a3c9", 41 | "Public": "0xedD257B4e0F5e7d632c737f4277e93b64DC268FC" 42 | }, 43 | { 44 | "Address": "0x66A74477FC1dd0F4924ed943C1d2F1Dece3Ab138", 45 | "Private": "0436864cc15772448f88dd40554592ff6c91a6c1a389d965ad26ee143db1234d", 46 | "Public": "0x66A74477FC1dd0F4924ed943C1d2F1Dece3Ab138" 47 | }, 48 | { 49 | "Address": "0x04178CdbCe3a9Ff9Ea385777aFc4b78B3E745281", 50 | "Private": "dea956e530073ab23d9cae704f5d068482b1977c3173c9efd697c48a7fd3ce83", 51 | "Public": "0x04178CdbCe3a9Ff9Ea385777aFc4b78B3E745281" 52 | }, 53 | { 54 | "Address": "0x46C61d50874A7A06D29FF89a710AbBD0856265be", 55 | "Private": "af539d4ace07a9f601a8d3a6ca6f914d5a9fabe09cfe7d62ebc2348fc95f03a4", 56 | "Public": "0x46C61d50874A7A06D29FF89a710AbBD0856265be" 57 | }, 58 | { 59 | "Address": "0xfE9BABE6904C28E31971337738FBCBAF8c72873e", 60 | "Private": "7d24797eeba0cdac9bf943f0d82c4b18eb206108d6e1b7f610471594c0c94306", 61 | "Public": "0xfE9BABE6904C28E31971337738FBCBAF8c72873e" 62 | }, 63 | { 64 | "Address": "0x3f78622de8D8f87EAa0E8b28C2851e2450E91250", 65 | "Private": "4fa2fecce1becfaf7e5fba5394caacb318333b04071462b5ca850ee5a406dcfe", 66 | "Public": "0x3f78622de8D8f87EAa0E8b28C2851e2450E91250" 67 | }, 68 | { 69 | "Address": "0xd2Cb501B40D3a9a013A38267a4d2A4Cf6bD2CAa8", 70 | "Private": "3c8642f7188e05acc4467d9e2aa7fd539e82aa90a5497257cf0ecbb98ed3b88f", 71 | "Public": "0xd2Cb501B40D3a9a013A38267a4d2A4Cf6bD2CAa8" 72 | }, 73 | { 74 | "Address": "0x2676e6dd2d7618be14cb4c18a355c81bf7aac647", 75 | "Private": "bf29f6a33b2c24a8b5182ef44cc35ce87534ef827c8dfbc1e6bb536aa52f8563", 76 | "Public": "0x2676e6dd2d7618be14cb4c18a355c81bf7aac647" 77 | } 78 | ] 79 | } 80 | -------------------------------------------------------------------------------- /packages/harmony-utils/src/utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-utils 4 | */ 5 | 6 | import { 7 | isNumber, 8 | isString, 9 | isBoolean, 10 | isArray, 11 | isJsonString, 12 | isHex, 13 | isObject, 14 | isFunction, 15 | isPublicKey, 16 | isPrivateKey, 17 | isAddress, 18 | isBech32Address, 19 | isBech32TestNetAddress, 20 | isValidAddress, 21 | isHash, 22 | isBlockNumber, 23 | } from './validators'; 24 | 25 | /** @hidden */ 26 | export enum AssertType { 27 | required = 'required', 28 | optional = 'optional', 29 | } 30 | 31 | /** @hidden */ 32 | export const validatorArray: any = { 33 | isNumber: [isNumber], 34 | isString: [isString], 35 | isBoolean: [isBoolean], 36 | isArray: [isArray], 37 | isJsonString: [isJsonString], 38 | isObject: [isObject], 39 | isFunction: [isFunction], 40 | isHex: [isHex], 41 | isPublicKey: [isPublicKey], 42 | isPrivateKey: [isPrivateKey], 43 | isAddress: [isAddress], 44 | isHash: [isHash], 45 | isBlockNumber: [isBlockNumber], 46 | isBech32Address: [isBech32Address], 47 | isBech32TestNetAddress: [isBech32TestNetAddress], 48 | isValidAddress: [isValidAddress], 49 | }; 50 | 51 | export function validateArgs(args: any, requiredArgs: any, optionalArgs: any): boolean { 52 | for (const key in requiredArgs) { 53 | if (args[key] !== undefined) { 54 | // tslint:disable-next-line: prefer-for-of 55 | for (let i = 0; i < requiredArgs[key].length; i += 1) { 56 | if (typeof requiredArgs[key][i] !== 'function') { 57 | throw new Error('Validator is not a function'); 58 | } 59 | 60 | if (!requiredArgs[key][i](args[key])) { 61 | throw new Error( 62 | `Validation failed for ${key},should be validated by ${requiredArgs[key][i].validator}`, 63 | ); 64 | } 65 | } 66 | } else { 67 | throw new Error(`Key not found: ${key}`); 68 | } 69 | } 70 | 71 | for (const key in optionalArgs) { 72 | if (args[key]) { 73 | // tslint:disable-next-line: prefer-for-of 74 | for (let i = 0; i < optionalArgs[key].length; i += 1) { 75 | if (typeof optionalArgs[key][i] !== 'function') { 76 | throw new Error('Validator is not a function'); 77 | } 78 | 79 | if (!optionalArgs[key][i](args[key])) { 80 | throw new Error( 81 | `Validation failed for ${key},should be validated by ${optionalArgs[key][i].validator}`, 82 | ); 83 | } 84 | } 85 | } 86 | } 87 | return true; 88 | } 89 | 90 | export function generateValidateObjects(validatorObject: { [x: string]: any[] }) { 91 | const requiredArgs: any = {}; 92 | const optionalArgs: any = {}; 93 | for (const index in validatorObject) { 94 | if (index !== undefined) { 95 | const newObjectKey = index; 96 | const newObjectValid = validatorObject[index][0]; 97 | const isRequired = validatorObject[index][1]; 98 | if (isRequired === AssertType.required) { 99 | requiredArgs[newObjectKey] = validatorArray[newObjectValid]; 100 | } else { 101 | optionalArgs[newObjectKey] = validatorArray[newObjectValid]; 102 | } 103 | } 104 | } 105 | return { requiredArgs, optionalArgs }; 106 | } 107 | 108 | const assertObject = (input: any) => (target: any, key: any, descriptor: PropertyDescriptor) => { 109 | const { requiredArgs, optionalArgs } = generateValidateObjects(input); 110 | const original = descriptor.value; 111 | function interceptor(this: any, ...args: any[]) { 112 | validateArgs(args[0], requiredArgs, optionalArgs); 113 | return original.apply(this, args); 114 | } 115 | descriptor.value = interceptor; 116 | return descriptor; 117 | }; 118 | 119 | export { assertObject }; 120 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/utils/mapper.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * @hidden 5 | */ 6 | 7 | import { isArray } from '@harmony-js/utils'; 8 | import { AbiItem } from '../models/AbiItemModel'; 9 | import { AbiModel } from '../models/AbiModel'; 10 | import { AbiItemModel } from '../models/types'; 11 | import { jsonInterfaceMethodToString } from '../abi/utils'; 12 | import { AbiCoderClass } from '../abi/api'; 13 | 14 | export const abiMapper = (abi: any[], abiCoder: AbiCoderClass): AbiModel => { 15 | const mappedAbiItems: any = { 16 | methods: {}, 17 | events: {}, 18 | fallback: undefined, 19 | receive: undefined, 20 | }; 21 | let hasConstructor = false; 22 | 23 | abi.forEach((abiItem: AbiItemModel) => { 24 | abiItem.constant = isConstant(abiItem); 25 | abiItem.payable = isPayable(abiItem); 26 | 27 | if (abiItem.name) { 28 | abiItem.funcName = jsonInterfaceMethodToString(abiItem); 29 | } 30 | 31 | let abiItemModel; 32 | 33 | if (abiItem.type === 'function') { 34 | abiItem.signature = abiCoder.encodeFunctionSignature(abiItem.funcName); 35 | 36 | abiItemModel = new AbiItem(abiItem); 37 | 38 | // Check if an method already exists with this name and if it exists than create an array and push this abiItem 39 | // into it. This will be used if there are methods with the same name but with different arguments. 40 | if (!mappedAbiItems.methods[abiItem.name]) { 41 | mappedAbiItems.methods[abiItem.name] = abiItemModel; 42 | } else { 43 | if (isArray(mappedAbiItems.methods[abiItem.name])) { 44 | mappedAbiItems.methods[abiItem.name].push(abiItemModel); 45 | } else { 46 | mappedAbiItems.methods[abiItem.name] = [ 47 | mappedAbiItems.methods[abiItem.name], 48 | abiItemModel, 49 | ]; 50 | } 51 | } 52 | 53 | mappedAbiItems.methods[abiItem.signature] = abiItemModel; 54 | mappedAbiItems.methods[abiItem.funcName] = abiItemModel; 55 | 56 | return; 57 | } 58 | 59 | if (abiItem.type === 'event') { 60 | abiItem.signature = abiCoder.encodeEventSignature(abiItem.funcName); 61 | 62 | abiItemModel = new AbiItem(abiItem); 63 | 64 | if ( 65 | !mappedAbiItems.events[abiItem.name] || 66 | mappedAbiItems.events[abiItem.name].name === 'bound ' 67 | ) { 68 | mappedAbiItems.events[abiItem.name] = abiItemModel; 69 | } 70 | 71 | mappedAbiItems.events[abiItem.signature] = abiItemModel; 72 | mappedAbiItems.events[abiItem.funcName] = abiItemModel; 73 | } 74 | 75 | if (abiItem.type === 'fallback' || abiItem.type === 'receive') { 76 | abiItem.signature = abiItem.type; 77 | mappedAbiItems[abiItem.type] = new AbiItem(abiItem); 78 | } 79 | 80 | if (abiItem.type === 'constructor') { 81 | abiItem.signature = abiItem.type; 82 | // tslint:disable-next-line: no-string-literal 83 | mappedAbiItems.methods['contractConstructor'] = new AbiItem(abiItem); 84 | 85 | hasConstructor = true; 86 | } 87 | }); 88 | if (!hasConstructor) { 89 | // tslint:disable-next-line: no-string-literal 90 | mappedAbiItems.methods['contractConstructor'] = new AbiItem({ 91 | inputs: [], 92 | payable: false, 93 | constant: false, 94 | type: 'constructor', 95 | }); 96 | } 97 | return new AbiModel(mappedAbiItems); 98 | }; 99 | 100 | export const isConstant = (abiItem: AbiItemModel) => { 101 | return ( 102 | abiItem.stateMutability === 'view' || abiItem.stateMutability === 'pure' || abiItem.constant 103 | ); 104 | }; 105 | 106 | export const isPayable = (abiItem: AbiItemModel) => { 107 | return abiItem.stateMutability === 'payable' || abiItem.payable; 108 | }; 109 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/contract.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * 5 | */ 6 | 7 | import { Wallet } from '@harmony-js/account'; 8 | import { Messenger } from '@harmony-js/network'; 9 | import { Transaction } from '@harmony-js/transaction'; 10 | import { AbiCoder } from './abi/index'; 11 | import { abiMapper } from './utils/mapper'; 12 | import { ContractOptions } from './utils/options'; 13 | import { AbiModel } from './models/types'; 14 | import { AbiCoderClass } from './abi/api'; 15 | import { MethodFactory } from './methods/methodFactory'; 16 | import { EventFactory } from './events/eventFactory'; 17 | import { ContractStatus } from './utils/status'; 18 | 19 | // class Contract 20 | export class Contract { 21 | methods: any; 22 | events: any; 23 | fallback: any = undefined; 24 | receive: any = undefined; 25 | abi: any = []; 26 | abiModel: any | AbiModel; 27 | abiCoder: AbiCoderClass; 28 | options: ContractOptions | any; 29 | wallet: Wallet | any; 30 | transaction?: Transaction; 31 | status: ContractStatus; 32 | shardID: number; 33 | errorFunc: string = 'Error(string)'; 34 | errorFuncSig: string; 35 | 36 | constructor( 37 | abi: any = [], 38 | address: string = '0x', 39 | options: ContractOptions = {}, 40 | wallet: Wallet, 41 | status: ContractStatus = ContractStatus.INITIALISED, 42 | ) { 43 | // super(); 44 | this.abi = abi; 45 | this.abiCoder = AbiCoder(); 46 | this.abiModel = abiMapper(abi, this.abiCoder); 47 | this.options = options; 48 | this.address = this.options.address || address; 49 | this.shardID = this.options.shardID || wallet.messenger.currentShard; 50 | this.wallet = wallet; 51 | this.methods = {}; 52 | this.events = {}; 53 | this.runMethodFactory(); 54 | this.runEventFactory(); 55 | this.status = status; 56 | this.errorFuncSig = this.abiCoder.encodeFunctionSignature(this.errorFunc); 57 | // tslint:disable-next-line: no-unused-expression 58 | } 59 | isInitialised() { 60 | return this.status === ContractStatus.INITIALISED; 61 | } 62 | isSigned() { 63 | return this.status === ContractStatus.SIGNED; 64 | } 65 | isSent() { 66 | return this.status === ContractStatus.SENT; 67 | } 68 | isDeployed() { 69 | return this.status === ContractStatus.DEPLOYED; 70 | } 71 | isRejected() { 72 | return this.status === ContractStatus.REJECTED; 73 | } 74 | isCalled() { 75 | return this.status === ContractStatus.CALLED; 76 | } 77 | setStatus(status: ContractStatus) { 78 | this.status = status; 79 | } 80 | 81 | get jsonInterface(): any[] { 82 | return this.abiModel; 83 | } 84 | 85 | set jsonInterface(value: any[]) { 86 | this.abiModel = abiMapper(value, this.abiCoder); 87 | this.runMethodFactory(); 88 | this.runEventFactory(); 89 | } 90 | 91 | get address() { 92 | return this.options.address || this.address; 93 | } 94 | 95 | set address(value: string) { 96 | this.options.address = value; 97 | } 98 | 99 | get data() { 100 | return this.options.data; 101 | } 102 | 103 | set data(value) { 104 | this.options.data = value; 105 | } 106 | 107 | // deploy 108 | deploy(options: any) { 109 | return this.methods.contractConstructor(options); 110 | } 111 | 112 | runMethodFactory(): Contract { 113 | return new MethodFactory(this).addMethodsToContract(); 114 | } 115 | runEventFactory(): Contract { 116 | return new EventFactory(this).addEventsToContract(); 117 | } 118 | connect(wallet: Wallet): void { 119 | this.wallet = wallet; 120 | } 121 | setMessenger(messenger: Messenger) { 122 | if (this.wallet instanceof Wallet) { 123 | this.wallet.setMessenger(messenger); 124 | } else { 125 | this.wallet.messenger = messenger; 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /packages/harmony-network/src/tracker/pollingTracker.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | * @hidden 5 | */ 6 | 7 | import { BaseBlockTracker } from './baseTracker'; 8 | import { Messenger } from '../messenger/messenger'; 9 | import { RPCMethod } from '../rpcMethod/rpc'; 10 | 11 | const sec = 1000; 12 | 13 | export function timeout(duration: number, unref: any) { 14 | return new Promise((resolve) => { 15 | const timoutRef: any = setTimeout(resolve, duration); 16 | // don't keep process open 17 | if (timoutRef.unref && unref) { 18 | timoutRef.unref(); 19 | } 20 | }); 21 | } 22 | export class PollingBlockTracker extends BaseBlockTracker { 23 | messenger: Messenger; 24 | // tslint:disable-next-line: variable-name 25 | _pollingInterval: number; 26 | // tslint:disable-next-line: variable-name 27 | _retryTimeout: number; 28 | // tslint:disable-next-line: variable-name 29 | _keepEventLoopActive: boolean; 30 | // tslint:disable-next-line: variable-name 31 | _setSkipCacheFlag: boolean; 32 | constructor( 33 | messenger: Messenger, 34 | opts = { 35 | pollingInterval: undefined, 36 | retryTimeout: undefined, 37 | keepEventLoopActive: false, 38 | setSkipCacheFlag: false, 39 | }, 40 | ) { 41 | // parse + validate args 42 | if (!messenger) { 43 | throw new Error('PollingBlockTracker - no provider specified.'); 44 | } 45 | 46 | const pollingInterval: number = opts.pollingInterval || 20 * sec; 47 | const retryTimeout: number = opts.retryTimeout || pollingInterval / 10; 48 | const keepEventLoopActive: boolean = 49 | opts.keepEventLoopActive !== undefined ? opts.keepEventLoopActive : true; 50 | const setSkipCacheFlag = opts.setSkipCacheFlag || false; 51 | // BaseBlockTracker constructor 52 | super({ 53 | blockResetDuration: pollingInterval, 54 | retryTimeout, 55 | keepEventLoopActive, 56 | setSkipCacheFlag, 57 | }); 58 | // config 59 | this.messenger = messenger; 60 | this._pollingInterval = pollingInterval; 61 | this._retryTimeout = retryTimeout; 62 | this._keepEventLoopActive = keepEventLoopActive; 63 | this._setSkipCacheFlag = setSkipCacheFlag; 64 | } 65 | 66 | // 67 | // public 68 | // 69 | 70 | // trigger block polling 71 | async checkForLatestBlock() { 72 | await this._updateLatestBlock(); 73 | const result = await this.getLatestBlock(); 74 | return result; 75 | } 76 | 77 | // 78 | // private 79 | // 80 | 81 | _start() { 82 | this._performSync().catch((err) => this.emit('error', err)); 83 | } 84 | 85 | async _performSync() { 86 | while (this._isRunning) { 87 | try { 88 | await this._updateLatestBlock(); 89 | await timeout(this._pollingInterval, !this._keepEventLoopActive); 90 | } catch (err) { 91 | const newErr = new Error( 92 | `PollingBlockTracker - encountered an error while attempting to update latest block:\n${err.stack}`, 93 | ); 94 | try { 95 | this.emit('error', newErr); 96 | } catch (emitErr) { 97 | console.error(newErr); 98 | } 99 | await timeout(this._retryTimeout, !this._keepEventLoopActive); 100 | } 101 | } 102 | } 103 | 104 | async _updateLatestBlock() { 105 | // fetch + set latest block 106 | const latestBlock = await this._fetchLatestBlock(); 107 | this._newPotentialLatest(latestBlock); 108 | } 109 | 110 | async _fetchLatestBlock() { 111 | try { 112 | const result = await this.messenger.send(RPCMethod.BlockNumber, []); 113 | if (result.isError()) { 114 | throw result.message; 115 | } else if (result.isResult()) { 116 | return result.result; 117 | } 118 | } catch (error) { 119 | throw error; 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /packages/harmony-utils/src/chain.ts: -------------------------------------------------------------------------------- 1 | /** 2 | # @harmony-js/utils 3 | 4 | This package provides a collection of utility apis for unit conversions like `fromWei`, `toWei`, `hexToNumber`, `numberToHex`, `isAddress`, etc. 5 | 6 | ## Installation 7 | 8 | ``` 9 | npm install @harmony-js/utils 10 | ``` 11 | 12 | ## Usage 13 | 14 | Available units 15 | ``` 16 | const { Units } = require('@harmony-js/utils'); 17 | 18 | [Units.wei, '1'], // 1 wei 19 | [Units.Kwei, '1000'], // 1e3 wei 20 | [Units.Mwei, '1000000'], // 1e6 wei 21 | [Units.Gwei, '1000000000'], // 1e9 wei 22 | [Units.szabo, '1000000000000'], // 1e12 wei 23 | [Units.finney, '1000000000000000'], // 1e15 wei 24 | [Units.ether, '1000000000000000000'], // 1e18 wei 25 | [Units.one, '1000000000000000000'], // 1e18 wei 26 | [Units.Kether, '1000000000000000000000'], // 1e21 wei 27 | [Units.Mether, '1000000000000000000000000'], // 1e24 wei 28 | [Units.Gether, '1000000000000000000000000000'], // 1e27 wei 29 | [Units.Tether, '1000000000000000000000000000000'], // 1e30 wei 30 | ``` 31 | 32 | Converting between different units 33 | ```javascript 34 | const { Units, Unit, numberToString, add0xToString, fromWei, toWei, numToStr} = require('@harmony-js/utils'); 35 | const { BN } = require('@harmony-js/crypto'); 36 | 37 | const one = new Unit('1').asOne(); 38 | const oneToGwei = one.toGwei(); 39 | console.log(oneToGwei); 40 | 41 | // numberToString 42 | const num = 123; 43 | const str = numberToString(num) 44 | console.log(str); 45 | 46 | // add0xToString 47 | const str = '12345'; 48 | const expected = add0xToString(str) 49 | console.log(expected); 50 | 51 | // fromWei 52 | const Wei = new BN('1000000000000000000'); 53 | const expected = fromWei(Wei, Units.one); 54 | console.log(expected); 55 | 56 | // toWei 57 | const one = new BN('1'); 58 | const expected = toWei(one, hmy.utils.Units.one); 59 | const num = numToStr(expected); 60 | console.log(num); 61 | ``` 62 | * 63 | * @packageDocumentation 64 | * @module harmony-utils 65 | */ 66 | 67 | export enum ChainType { 68 | Harmony = 'hmy', 69 | Ethereum = 'eth', 70 | } 71 | 72 | export enum ChainID { 73 | Default = 0, 74 | EthMainnet = 1, 75 | Morden = 2, 76 | Ropsten = 3, 77 | Rinkeby = 4, 78 | RootstockMainnet = 30, 79 | RootstockTestnet = 31, 80 | Kovan = 42, 81 | EtcMainnet = 61, 82 | EtcTestnet = 62, 83 | Geth = 1337, 84 | Ganache = 0, 85 | HmyMainnet = 1, 86 | HmyTestnet = 2, 87 | HmyLocal = 2, 88 | HmyPangaea = 3, 89 | } 90 | 91 | /** @hidden */ 92 | export const defaultConfig = { 93 | Default: { 94 | Chain_ID: ChainID.HmyLocal, 95 | Chain_Type: ChainType.Harmony, 96 | Chain_URL: 'http://localhost:9500', 97 | Network_ID: 'Local', 98 | }, 99 | DefaultWS: { 100 | Chain_ID: ChainID.HmyLocal, 101 | Chain_Type: ChainType.Harmony, 102 | Chain_URL: 'ws://localhost:9800', 103 | Network_ID: 'LocalWS', 104 | }, 105 | }; 106 | 107 | /** @hidden */ 108 | export abstract class HarmonyCore { 109 | chainType: ChainType; 110 | chainId: ChainID; 111 | constructor(chainType: ChainType, chainId: ChainID = defaultConfig.Default.Chain_ID) { 112 | this.chainType = chainType; 113 | this.chainId = chainId; 114 | } 115 | get chainPrefix(): string { 116 | switch (this.chainType) { 117 | case ChainType.Ethereum: { 118 | return 'eth'; 119 | } 120 | case ChainType.Harmony: { 121 | return 'hmy'; 122 | } 123 | default: { 124 | return 'hmy'; 125 | } 126 | } 127 | } 128 | get getChainId(): ChainID { 129 | return this.chainId; 130 | } 131 | public setChainId(chainId: ChainID) { 132 | this.chainId = chainId; 133 | } 134 | public setChainType(chainType: ChainType) { 135 | this.chainType = chainType; 136 | } 137 | } 138 | 139 | /** @hidden */ 140 | export const HDPath = `m/44'/1023'/0'/0/`; 141 | 142 | /** @hidden */ 143 | export const AddressSuffix = '-'; 144 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/utils/formatter.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * @hidden 5 | */ 6 | 7 | import { hexlify, isHexString, keccak256, toChecksumAddress } from '@harmony-js/crypto'; 8 | import { 9 | numberToHex, 10 | isArray, 11 | // hexToNumber, 12 | isString, 13 | isAddress, 14 | hexToBN, 15 | } from '@harmony-js/utils'; 16 | import { toUtf8Bytes } from '../abi/abiCoder'; 17 | 18 | export const inputLogFormatter = (options: any) => { 19 | if (options.fromBlock) { 20 | options.fromBlock = inputBlockNumberFormatter(options.fromBlock); 21 | } 22 | 23 | if (options.toBlock) { 24 | options.toBlock = inputBlockNumberFormatter(options.toBlock); 25 | } 26 | 27 | // make sure topics, get converted to hex 28 | options.topics = options.topics || []; 29 | options.topics = options.topics.map((topic: any) => { 30 | return isArray(topic) ? topic.map(toTopic) : toTopic(topic); 31 | }); 32 | 33 | if (options.address) { 34 | if (isArray(options.address)) { 35 | options.address = options.address.map((addr: string) => { 36 | return inputAddressFormatter(addr); 37 | }); 38 | } else { 39 | options.address = inputAddressFormatter(options.address); 40 | } 41 | } 42 | 43 | return options; 44 | }; 45 | 46 | /** 47 | * Formats the output of a log 48 | * 49 | * @method outputLogFormatter 50 | * 51 | * @param {Object} log object 52 | * 53 | * @returns {Object} log 54 | */ 55 | export const outputLogFormatter = (log: any) => { 56 | // generate a custom log id 57 | if ( 58 | typeof log.blockHash === 'string' && 59 | typeof log.transactionHash === 'string' && 60 | typeof log.logIndex === 'string' 61 | ) { 62 | const shaId = keccak256( 63 | '0x' + 64 | log.blockHash.replace('0x', '') + 65 | log.transactionHash.replace('0x', '') + 66 | log.logIndex.replace('0x', ''), 67 | ); 68 | 69 | shaId.replace('0x', '').substr(0, 8); 70 | 71 | log.id = `log_${shaId}`; 72 | } else if (!log.id) { 73 | log.id = null; 74 | } 75 | 76 | if (log.blockNumber !== null) { 77 | log.blockNumber = hexToBN(log.blockNumber).toNumber(); 78 | } 79 | 80 | if (log.transactionIndex !== null) { 81 | log.transactionIndex = hexToBN(log.transactionIndex).toNumber(); 82 | } 83 | 84 | if (log.logIndex !== null) { 85 | log.logIndex = hexToBN(log.logIndex).toNumber(); 86 | } 87 | 88 | if (log.address) { 89 | log.address = toChecksumAddress(log.address); 90 | } 91 | 92 | return log; 93 | }; 94 | 95 | export const inputBlockNumberFormatter = (blockNumber: any) => { 96 | if (blockNumber === undefined || blockNumber === null || isPredefinedBlockNumber(blockNumber)) { 97 | return blockNumber; 98 | } 99 | 100 | if (isHexString(blockNumber)) { 101 | if (isString(blockNumber)) { 102 | return blockNumber.toLowerCase(); 103 | } 104 | 105 | return blockNumber; 106 | } 107 | 108 | return numberToHex(blockNumber); 109 | }; 110 | 111 | export const isPredefinedBlockNumber = (blockNumber: string) => { 112 | return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest'; 113 | }; 114 | 115 | export const inputAddressFormatter = (address: string) => { 116 | if (isAddress(address)) { 117 | return `0x${address.toLowerCase().replace('0x', '')}`; 118 | } 119 | 120 | throw new Error( 121 | `Provided address "${address}" is invalid, the capitalization checksum test failed, or its an indrect IBAN address which can't be converted.`, 122 | ); 123 | }; 124 | 125 | export const toTopic = (value: any) => { 126 | if (value === null || typeof value === 'undefined') { 127 | return null; 128 | } 129 | 130 | value = String(value); 131 | 132 | if (value.indexOf('0x') === 0) { 133 | return value; 134 | } 135 | 136 | return hexlify(toUtf8Bytes(value)); 137 | }; 138 | -------------------------------------------------------------------------------- /scripts/bundle.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as path from 'path'; 3 | // tslint:disable-next-line: no-implicit-dependencies 4 | import * as rollup from 'rollup'; 5 | // tslint:disable-next-line: no-implicit-dependencies 6 | import alias from 'rollup-plugin-alias'; 7 | // tslint:disable-next-line: no-implicit-dependencies 8 | import builtins from 'rollup-plugin-node-builtins'; 9 | // tslint:disable-next-line: no-implicit-dependencies 10 | import commonjs from 'rollup-plugin-commonjs'; 11 | // tslint:disable-next-line: no-implicit-dependencies 12 | import license from 'rollup-plugin-license'; 13 | // tslint:disable-next-line: no-implicit-dependencies 14 | import json from 'rollup-plugin-json'; 15 | // tslint:disable-next-line: no-implicit-dependencies 16 | import globals from 'rollup-plugin-node-globals'; 17 | // tslint:disable-next-line: no-implicit-dependencies 18 | import resolve from 'rollup-plugin-node-resolve'; 19 | // tslint:disable-next-line: no-implicit-dependencies 20 | import typescript2 from 'rollup-plugin-typescript2'; 21 | // tslint:disable-next-line: no-implicit-dependencies 22 | import ts from 'typescript'; 23 | // tslint:disable-next-line: no-implicit-dependencies 24 | 25 | import { projects, preProcessFunc, preProcessProjects } from './projects'; 26 | 27 | function getKeys(p) { 28 | const packageJsonFile = `${process.cwd()}/packages/${p}/package.json`; 29 | const data = fs.readFileSync(packageJsonFile, 'utf-8'); 30 | 31 | const { dependencies } = JSON.parse(data); 32 | 33 | // .filter((d) => !/harmony/.test(d)) 34 | const keys = dependencies ? Object.keys(dependencies) : []; 35 | return keys; 36 | } 37 | 38 | async function bundles() { 39 | await preProcessFunc(preProcessProjects); 40 | 41 | for (const pkg of projects) { 42 | const base = { 43 | input: path.join(pkg.src, 'index.ts'), 44 | plugins: [ 45 | alias({ 46 | elliptic: path.resolve(__dirname, '../', 'includes/elliptic/elliptic.js'), 47 | }), 48 | resolve({ 49 | browser: true, 50 | jsnext: true, 51 | preferBuiltins: true, 52 | }), 53 | // babel(browserConfig), 54 | commonjs(), 55 | globals(), 56 | builtins(), 57 | json(), 58 | typescript2({ 59 | typescript: ts, // ensure we're using the same typescript (3.x) for rollup as for regular builds etc 60 | tsconfig: path.join(pkg.path, 'tsconfig.json'), 61 | tsconfigOverride: { 62 | compilerOptions: { 63 | module: 'es2015', 64 | stripInternal: true, 65 | emitDeclarationOnly: false, 66 | composite: false, 67 | declaration: false, 68 | declarationMap: false, 69 | sourceMap: true, 70 | }, 71 | }, 72 | }), 73 | license({ 74 | banner: `Test Banner`, 75 | }), 76 | ], 77 | external: getKeys(pkg.name), 78 | // external: projects 79 | // .filter((p) => p.name !== pkg.name) 80 | // .map((p) => p.scopedName) 81 | // .concat(['cross-fetch']), 82 | }; 83 | 84 | const pkgBundler = await rollup.rollup(base); 85 | 86 | await pkgBundler.write({ 87 | file: pkg.esm, 88 | name: pkg.globalName, 89 | format: 'esm', 90 | sourcemap: true, 91 | }); 92 | await pkgBundler.write({ 93 | file: pkg.umd, 94 | exports: 'named', 95 | name: pkg.globalName, 96 | globals: { 97 | ...getKeys(pkg.name).reduce((g, packages) => { 98 | if (packages === pkg.name) { 99 | g[pkg.scopedName] = pkg.globalName; 100 | } else { 101 | g[packages] = packages; 102 | } 103 | return g; 104 | }, {}), 105 | tslib: 'tslib', 106 | }, 107 | format: 'umd', 108 | sourcemap: true, 109 | }); 110 | await pkgBundler.write({ 111 | file: pkg.cjs, 112 | name: pkg.globalName, 113 | format: 'cjs', 114 | sourcemap: true, 115 | }); 116 | } 117 | } 118 | 119 | bundles(); 120 | -------------------------------------------------------------------------------- /packages/harmony-crypto/test/keystore.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @ignore 4 | */ 5 | 6 | import * as keys from '../src/keyTool'; 7 | import * as keystore from '../src/keystore'; 8 | 9 | describe('Keystore', () => { 10 | const privateKey = keys.generatePrivateKey(); 11 | const publicKey = keys.getPubkeyFromPrivateKey(privateKey); 12 | const address = keys.getAddressFromPublicKey(publicKey).substring(2); // remove "0x" prefix 13 | const password = 'password123'; 14 | const phrase = 'some phrase'; 15 | 16 | it('check encrypt', async () => { 17 | try { 18 | const encrypted = await keystore.encrypt(privateKey, password); 19 | const parsedData = JSON.parse(encrypted); 20 | expect(parsedData.address).toEqual(address); 21 | expect(parsedData.id.length).toBe(36); 22 | } catch (error) { 23 | expect(error.message).toEqual('privateKey is not correct'); 24 | } 25 | }); 26 | 27 | it('check encrypt (kdf=scrypt)', async () => { 28 | try { 29 | const encrypted = await keystore.encrypt(privateKey, password, { 30 | kdf: 'scrypt', 31 | level: 16, 32 | }); 33 | const parsedData = JSON.parse(encrypted); 34 | expect(parsedData.address).toEqual(address); 35 | expect(parsedData.id.length).toBe(36); 36 | } catch (error) { 37 | expect(error.message).toEqual('privateKey is not correct'); 38 | } 39 | }); 40 | 41 | it('check encrypt (invalid "level" option)', async () => { 42 | try { 43 | await keystore.encrypt(privateKey, password, { 44 | kdf: 'scrypt', 45 | level: 15, 46 | }); 47 | } catch (error) { 48 | expect(error.message).toEqual('N must be > 0 and a power of 2'); 49 | } 50 | }); 51 | 52 | it('check encrypt (kdf=pbkdf2)', async () => { 53 | try { 54 | await keystore.encrypt(privateKey, password, { 55 | kdf: 'pbkdf2', 56 | }); 57 | } catch (error) { 58 | expect(error.message).toEqual('Iterations not a number'); 59 | } 60 | }); 61 | 62 | it('check encrypt (private key and password are undefined)', async () => { 63 | try { 64 | // @ts-ignore 65 | await keystore.encrypt(undefined, undefined); 66 | } catch (error) { 67 | expect(error.message).toEqual("Cannot read properties of undefined (reading 'replace')"); 68 | } 69 | }); 70 | 71 | it('check encryptPhrase', async () => { 72 | try { 73 | const encrypted = await keystore.encryptPhrase(phrase, password); 74 | const parsedData = JSON.parse(encrypted); 75 | expect(parsedData.version).toEqual(3); 76 | expect(parsedData.crypto.cipher).toEqual('aes-128-ctr'); 77 | } catch (error) { 78 | expect(error.message).toEqual('privateKey is not correct'); 79 | } 80 | }); 81 | 82 | it('check encryptPhrase (kdf=scrypt)', async () => { 83 | try { 84 | const encrypted = await keystore.encryptPhrase(phrase, password, { 85 | kdf: 'scrypt', 86 | level: 16, 87 | }); 88 | const parsedData = JSON.parse(encrypted); 89 | expect(parsedData.version).toEqual(3); 90 | expect(parsedData.crypto.cipher).toEqual('aes-128-ctr'); 91 | } catch (error) { 92 | expect(error.message).toEqual('privateKey is not correct'); 93 | } 94 | }); 95 | 96 | it('check decrypt', async () => { 97 | try { 98 | const encrypted = await keystore.encrypt(privateKey, password); 99 | const decrypted = await keystore.decrypt(JSON.parse(encrypted), password); 100 | expect(decrypted).toEqual(privateKey); 101 | } catch (error) { 102 | expect(error.message).toEqual('Failed to decrypt.'); 103 | } 104 | }); 105 | 106 | it('check decrypt (wrong password)', async () => { 107 | try { 108 | const encrypted = await keystore.encrypt(privateKey, password); 109 | await keystore.decrypt(JSON.parse(encrypted), 'wrong_password'); 110 | } catch (error) { 111 | expect(error.message).toEqual('Failed to decrypt.'); 112 | } 113 | }); 114 | 115 | it('check decryptPhrase', async () => { 116 | try { 117 | const encrypted = await keystore.encryptPhrase(phrase, password); 118 | const decrypted = await keystore.decryptPhrase(JSON.parse(encrypted), password); 119 | expect(decrypted).toEqual(phrase); 120 | } catch (error) { 121 | expect(error.message).toEqual('Failed to decrypt.'); 122 | } 123 | }); 124 | }); 125 | -------------------------------------------------------------------------------- /packages/harmony-core/README.md: -------------------------------------------------------------------------------- 1 | # @harmony-js/core 2 | 3 | This package provides a collection of apis to interact with Harmony blockchain. 4 | 5 | ## Installation 6 | 7 | ``` 8 | npm install @harmony-js/core 9 | ``` 10 | 11 | ## Usage 12 | 13 | Create a Harmony instance connecting to testnet 14 | 15 | ```javascript 16 | const { Harmony } = require('@harmony-js/core'); 17 | const { 18 | ChainID, 19 | ChainType, 20 | hexToNumber, 21 | numberToHex, 22 | fromWei, 23 | Units, 24 | Unit, 25 | } = require('@harmony-js/utils'); 26 | 27 | const hmy = new Harmony( 28 | 'https://api.s0.b.hmny.io/', 29 | { 30 | chainType: ChainType.Harmony, 31 | chainId: ChainID.HmyTestnet, 32 | }, 33 | ); 34 | ``` 35 | 36 | Getting balance of account `one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7` 37 | ```javascript 38 | hmy.blockchain 39 | .getBalance({ address: 'one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7' }) 40 | .then((response) => { 41 | console.log('balance in ONEs: ' + fromWei(hexToNumber(response.result), Units.one)); 42 | }); 43 | ``` 44 | 45 | Getting the latest block number 46 | ```javascript 47 | hmy.blockchain.getBlockNumber().then((response) => { 48 | console.log('current block number: ' + hexToNumber(response.result)); 49 | }); 50 | ``` 51 | 52 | Getting the block using block hash 53 | ```javascript 54 | hmy.blockchain 55 | .getBlockByHash({ 56 | blockHash: '0x08c46ae7249362a7d1f602d44c5a81f33ebdab6a7dcb6068f99610b57911aafd', 57 | }) 58 | .then((response) => { 59 | console.log(response.result); 60 | }); 61 | ``` 62 | 63 | Getting the block using block number 64 | ```javascript 65 | hmy.blockchain 66 | .getBlockByNumber({ 67 | blockNumber: numberToHex(422635), 68 | }) 69 | .then((response) => { 70 | console.log(response.result); 71 | }); 72 | ``` 73 | 74 | Getting the transaction using hash 75 | ```javascript 76 | hmy.blockchain 77 | .getTransactionByHash({ 78 | txnHash: '0x56c73eb993b18dc04baacec5c2e9d1292a090f6a978a4a1c461db5255fcbc831', 79 | }) 80 | .then((response) => { 81 | console.log(response.result); 82 | }); 83 | ``` 84 | 85 | Getting the transaction receipt 86 | ```javascript 87 | hmy.blockchain 88 | .getTransactionReceipt({ 89 | txnHash: '0x56c73eb993b18dc04baacec5c2e9d1292a090f6a978a4a1c461db5255fcbc831', 90 | }) 91 | .then((response) => { 92 | console.log(response.result); 93 | }); 94 | ``` 95 | 96 | Getting the cross-shard transaction receipt 97 | ```javascript 98 | hmy.blockchain 99 | .getCxReceiptByHash({ 100 | txnHash: '0xcd36a90ff5d5373285c2896ba7bbcd3f5324263c0cb8ecfb7cad2f5fc2fbdbda', 101 | shardID: 1, 102 | }) 103 | .then((value) => { 104 | console.log(value.result); 105 | }); 106 | ``` 107 | 108 | Getting the deployed smart contract code 109 | ```javascript 110 | hmy.blockchain 111 | .getCode({ 112 | address: '0x08AE1abFE01aEA60a47663bCe0794eCCD5763c19', 113 | blockNumber: 'latest', 114 | }) 115 | .then((response) => { 116 | console.log(response.result); 117 | }); 118 | ``` 119 | 120 | Getting the transaction count of an account 121 | ```javascript 122 | hmy.blockchain 123 | .getTransactionCount({ 124 | address: 'one1pdv9lrdwl0rg5vglh4xtyrv3wjk3wsqket7zxy', 125 | }) 126 | .then((response) => { 127 | console.log(hexToNumber(response.result)); 128 | }); 129 | ``` 130 | 131 | Getting the shard structure and details 132 | ```javascript 133 | hmy.blockchain.getShardingStructure().then((response) => { 134 | console.log(response.result); 135 | }); 136 | ``` 137 | 138 | Transferring funds using `sendTransaction` 139 | ```javascript 140 | // key corresponds to one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7, only has testnet balance 141 | hmy.wallet.addByPrivateKey('45e497bd45a9049bcb649016594489ac67b9f052a6cdf5cb74ee2427a60bf25e'); 142 | 143 | async function transfer() { 144 | const txn = hmy.transactions.newTx({ 145 | to: 'one166axnkjmghkf3df7xfvd0hn4dft8kemrza4cd2', 146 | value: new Unit(1).asOne().toWei(), 147 | // gas limit, you can use string 148 | gasLimit: '21000', 149 | // send token from shardID 150 | shardID: 0, 151 | // send token to toShardID 152 | toShardID: 0, 153 | // gas Price, you can use Unit class, and use Gwei, then remember to use toWei(), which will be transformed to BN 154 | gasPrice: new hmy.utils.Unit('1').asGwei().toWei(), 155 | }); 156 | 157 | // sign the transaction use wallet; 158 | const signedTxn = await hmy.wallet.signTransaction(txn); 159 | const txnHash = await hmy.blockchain.sendTransaction(signedTxn); 160 | console.log(txnHash.result); 161 | } 162 | 163 | transfer(); 164 | ``` -------------------------------------------------------------------------------- /packages/harmony-core/src/util.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-core 4 | * @hidden 5 | */ 6 | 7 | import { ChainType, ChainID, defaultConfig } from '@harmony-js/utils'; 8 | import { Harmony } from './harmony'; 9 | 10 | export interface HarmonyConfig { 11 | chainUrl?: string; 12 | chainType: ChainType; 13 | chainId: ChainID; 14 | shardID?: number; 15 | } 16 | 17 | // tslint:disable-next-line: variable-name 18 | export function createWeb3(_web3: any) { 19 | const url: string = _web3.currentProvider.url; 20 | const harmony = new Harmony(url, { 21 | chainId: defaultConfig.Default.Chain_ID, 22 | chainType: defaultConfig.Default.Chain_Type, 23 | chainUrl: defaultConfig.Default.Chain_URL, 24 | }); 25 | 26 | _web3.setProvider(harmony.messenger.provider); 27 | _web3.messenger = harmony.messenger; 28 | _web3.eth.getRpcResult = harmony.blockchain.getRpcResult; 29 | 30 | // map blockchain to eth 31 | const { blockchain } = harmony; 32 | _web3.eth.getBlockNumber = () => blockchain.getBlockByNumber; 33 | _web3.eth.getBalance = (address: string, blockNumber?: string) => 34 | blockchain.getBalance({ address, blockNumber }); 35 | _web3.eth.getBlockByHash = (blockHash: string, returnObject?: boolean) => 36 | blockchain.getBlockByHash({ blockHash, returnObject }); 37 | _web3.eth.getBlockByNumber = (blockNumber: string, returnObject?: boolean) => 38 | blockchain.getBlockByNumber({ blockNumber, returnObject }); 39 | _web3.eth.getBlockTransactionCountByHash = (blockHash: string) => 40 | blockchain.getBlockTransactionCountByHash({ blockHash }); 41 | _web3.eth.getBlockTransactionCountByNumber = (blockNumber: string) => 42 | blockchain.getBlockTransactionCountByNumber({ blockNumber }); 43 | _web3.eth.getTransactionByBlockHashAndIndex = (blockHash: string, index: string) => 44 | blockchain.getTransactionByBlockHashAndIndex({ blockHash, index }); 45 | _web3.eth.getTransactionByBlockNumberAndIndex = (blockNumber: string, index: string) => 46 | blockchain.getTransactionByBlockNumberAndIndex({ blockNumber, index }); 47 | _web3.eth.getTransactionByHash = (txnHash: string) => 48 | blockchain.getTransactionByHash({ txnHash }); 49 | _web3.eth.getTransactionReceipt = (txnHash: string) => 50 | blockchain.getTransactionReceipt({ txnHash }); 51 | _web3.eth.getCode = (address: string, blockNumber?: string) => 52 | blockchain.getCode({ address, blockNumber }); 53 | _web3.eth.net_peerCount = () => blockchain.net_peerCount(); 54 | _web3.eth.net_version = () => blockchain.net_version(); 55 | _web3.eth.getProtocolVersion = () => blockchain.getProtocolVersion(); 56 | _web3.eth.getStorageAt = (address: string, position: string, blockNumber: string | undefined) => 57 | blockchain.getStorageAt({ address, position, blockNumber }); 58 | _web3.eth.getTransactionCount = (address: string, blockNumber: string | undefined) => 59 | blockchain.getTransactionCount({ address, blockNumber }); 60 | _web3.eth.estimateGas = (to: string, data: string) => blockchain.estimateGas({ to, data }); 61 | _web3.eth.gasPrice = () => blockchain.gasPrice(); 62 | _web3.eth.call = (payload: any, blockNumber: string | undefined) => 63 | blockchain.call({ payload, blockNumber }); 64 | _web3.eth.newPendingTransactions = () => blockchain.newPendingTransactions(); 65 | _web3.eth.newBlockHeaders = () => blockchain.newBlockHeaders(); 66 | _web3.eth.syncing = () => blockchain.syncing(); 67 | _web3.eth.logs = (options: any) => blockchain.logs(options); 68 | 69 | // map subscribe to _web3 70 | _web3.eth.subscribe = harmony.messenger.subscribe; 71 | 72 | // map accounts to _web3 73 | _web3.accounts = harmony.wallet.accounts; 74 | _web3.eth.accounts.create = harmony.wallet.createAccount; 75 | _web3.eth.accounts.privateKeyToAccount = harmony.wallet.addByPrivateKey; 76 | _web3.eth.accounts.encrypt = async (privateKey: string, password: string) => { 77 | const newAcc = new harmony.Modules.Account(privateKey, harmony.messenger); 78 | const result = await newAcc.toFile(password); 79 | return result; 80 | }; 81 | 82 | _web3.eth.accounts.decrypt = async (keystoreJsonV3: any, password: string) => { 83 | const newAcc = new harmony.Modules.Account(); 84 | const result = await newAcc.fromFile(JSON.stringify(keystoreJsonV3), password); 85 | return result; 86 | }; 87 | 88 | _web3.eth.accounts.signTransaction = harmony.wallet.signTransaction; 89 | 90 | // map transaction to web3 91 | _web3.eth.recoverTransaction = harmony.transactions.recover; 92 | 93 | // map contract to web3 94 | _web3.eth.Contract = harmony.contracts.createContract; 95 | 96 | _web3.utils = { ..._web3.utils, ...harmony.utils, ...harmony.crypto }; 97 | } 98 | -------------------------------------------------------------------------------- /packages/harmony-contract/src/abi/api.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-contract 4 | * @hidden 5 | */ 6 | 7 | import { AbiCoder as ABICoder, ParamType, toUtf8Bytes } from './abiCoder'; 8 | import { isObject, isArray } from '@harmony-js/utils'; 9 | import { keccak256, Arrayish } from '@harmony-js/crypto'; 10 | import { jsonInterfaceMethodToString, bnToString } from './utils'; 11 | 12 | export class AbiCoderClass { 13 | coder: ABICoder; 14 | constructor(coder: ABICoder) { 15 | this.coder = coder; 16 | } 17 | encodeFunctionSignature(functionName: any) { 18 | if (isObject(functionName)) { 19 | functionName = jsonInterfaceMethodToString(functionName); 20 | } 21 | const result = keccak256(toUtf8Bytes(functionName)); 22 | return result.slice(0, 10); 23 | } 24 | encodeEventSignature(functionName: any) { 25 | if (isObject(functionName)) { 26 | functionName = jsonInterfaceMethodToString(functionName); 27 | } 28 | const result = keccak256(toUtf8Bytes(functionName)); 29 | return result; 30 | } 31 | encodeParameter(types: string | ParamType, param: any) { 32 | return this.encodeParameters([types], [param]); 33 | } 34 | encodeParameters(types: Array, params: any[]) { 35 | return this.coder.encode(types, params); 36 | } 37 | encodeFunctionCall(jsonInterface: any, params: any[]) { 38 | return ( 39 | this.encodeFunctionSignature(jsonInterface) + 40 | this.encodeParameters(jsonInterface.inputs, params).replace('0x', '') 41 | ); 42 | } 43 | decodeParameter(type: ParamType, bytes: Arrayish) { 44 | return this.decodeParameters([type], bytes)[0]; 45 | } 46 | decodeParameters(outputs: ParamType[], bytes: Arrayish) { 47 | if (isArray(outputs) && outputs.length === 0) { 48 | throw new Error('Empty outputs array given!'); 49 | } 50 | 51 | if (!bytes || bytes === '0x' || bytes === '0X') { 52 | throw new Error(`Invalid bytes string given: ${bytes}`); 53 | } 54 | 55 | const result = this.coder.decode(outputs, bytes); 56 | 57 | const returnValues: any = {}; 58 | let decodedValue; 59 | 60 | if (isArray(result)) { 61 | if (outputs.length > 1) { 62 | outputs.forEach((output: any, i) => { 63 | decodedValue = result[i]; 64 | 65 | if (decodedValue === '0x') { 66 | decodedValue = null; 67 | } 68 | 69 | returnValues[i] = bnToString(decodedValue); 70 | 71 | if (isObject(output) && output.name) { 72 | returnValues[output.name] = bnToString(decodedValue); 73 | } 74 | }); 75 | 76 | return returnValues; 77 | } 78 | 79 | return bnToString(result); 80 | } 81 | 82 | if (isObject(outputs[0]) && outputs[0].name) { 83 | returnValues[outputs[0].name] = bnToString(result); 84 | } 85 | 86 | returnValues[0] = bnToString(result); 87 | 88 | return returnValues; 89 | } 90 | 91 | decodeLog(inputs: any, data = '', topics: any) { 92 | const returnValues: any = {}; 93 | let topicCount = 0; 94 | let value; 95 | const nonIndexedInputKeys: any[] = []; 96 | const nonIndexedInputItems: any[] = []; 97 | 98 | if (!isArray(topics)) { 99 | topics = [topics]; 100 | } 101 | 102 | inputs.forEach((input: any, i: number) => { 103 | if (input.indexed) { 104 | if (input.type === 'string') { 105 | return; 106 | } 107 | 108 | value = topics[topicCount]; 109 | 110 | if (this.isStaticType(input.type)) { 111 | value = this.decodeParameter(input.type, topics[topicCount]); 112 | } 113 | 114 | returnValues[i] = bnToString(value); 115 | returnValues[input.name] = bnToString(value); 116 | topicCount++; 117 | 118 | return; 119 | } 120 | 121 | nonIndexedInputKeys.push(i); 122 | nonIndexedInputItems.push(input); 123 | }); 124 | 125 | if (data) { 126 | const values = this.decodeParameters(nonIndexedInputItems, data); 127 | 128 | let decodedValue; 129 | nonIndexedInputKeys.forEach((itemKey, index) => { 130 | decodedValue = values[index]; 131 | 132 | returnValues[itemKey] = bnToString(decodedValue); 133 | returnValues[nonIndexedInputItems[index].name] = bnToString(decodedValue); 134 | }); 135 | } 136 | 137 | return returnValues; 138 | } 139 | isStaticType(type: any) { 140 | if (type === 'bytes') { 141 | return false; 142 | } 143 | 144 | if (type === 'string') { 145 | return false; 146 | } 147 | 148 | if (type.indexOf('[') && type.slice(type.indexOf('[')).length === 2) { 149 | return false; 150 | } 151 | 152 | return true; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /packages/harmony-crypto/src/rlp.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-crypto 4 | * @hidden 5 | */ 6 | 7 | // this file is ported from https://github.com/ethers-io/ethers.js/blob/master/src.ts/utils/rlp.ts 8 | // and done some fixes 9 | import { arrayify, hexlify, Arrayish } from './bytes'; 10 | 11 | function arrayifyInteger(value: number): number[] { 12 | const result = []; 13 | while (value) { 14 | result.unshift(value & 0xff); 15 | value >>= 8; 16 | } 17 | return result; 18 | } 19 | 20 | function unarrayifyInteger(data: Uint8Array, offset: number, length: number): number { 21 | let result = 0; 22 | for (let i = 0; i < length; i++) { 23 | result = result * 256 + data[offset + i]; 24 | } 25 | return result; 26 | } 27 | 28 | function _encode(object: any[] | string): number[] { 29 | if (Array.isArray(object)) { 30 | let payload: number[] = []; 31 | object.forEach((child) => { 32 | payload = payload.concat(_encode(child)); 33 | }); 34 | 35 | if (payload.length <= 55) { 36 | payload.unshift(0xc0 + payload.length); 37 | return payload; 38 | } 39 | 40 | // tslint:disable-next-line: no-shadowed-variable 41 | const length = arrayifyInteger(payload.length); 42 | length.unshift(0xf7 + length.length); 43 | 44 | return length.concat(payload); 45 | } 46 | 47 | const data: number[] = Array.prototype.slice.call(arrayify(object)); 48 | 49 | if (data.length === 1 && data[0] <= 0x7f) { 50 | return data; 51 | } else if (data.length <= 55) { 52 | data.unshift(0x80 + data.length); 53 | return data; 54 | } 55 | 56 | const length = arrayifyInteger(data.length); 57 | length.unshift(0xb7 + length.length); 58 | 59 | return length.concat(data); 60 | } 61 | 62 | export function encode(object: any): string { 63 | return hexlify(_encode(object)); 64 | } 65 | 66 | interface Decoded { 67 | result: any; 68 | consumed: number; 69 | } 70 | 71 | function _decodeChildren( 72 | data: Uint8Array, 73 | offset: number, 74 | childOffset: number, 75 | length: number, 76 | ): Decoded { 77 | const result = []; 78 | 79 | while (childOffset < offset + 1 + length) { 80 | const decoded = _decode(data, childOffset); 81 | 82 | result.push(decoded.result); 83 | 84 | childOffset += decoded.consumed; 85 | if (childOffset > offset + 1 + length) { 86 | throw new Error('invalid rlp'); 87 | } 88 | } 89 | 90 | return { consumed: 1 + length, result }; 91 | } 92 | 93 | // returns { consumed: number, result: Object } 94 | function _decode(data: Uint8Array, offset: number): { consumed: number; result: any } { 95 | if (data.length === 0) { 96 | throw new Error('invalid rlp data'); 97 | } 98 | 99 | // Array with extra length prefix 100 | if (data[offset] >= 0xf8) { 101 | const lengthLength = data[offset] - 0xf7; 102 | if (offset + 1 + lengthLength > data.length) { 103 | throw new Error('too short'); 104 | } 105 | 106 | const length = unarrayifyInteger(data, offset + 1, lengthLength); 107 | if (offset + 1 + lengthLength + length > data.length) { 108 | throw new Error('to short'); 109 | } 110 | 111 | return _decodeChildren(data, offset, offset + 1 + lengthLength, lengthLength + length); 112 | } else if (data[offset] >= 0xc0) { 113 | const length = data[offset] - 0xc0; 114 | if (offset + 1 + length > data.length) { 115 | throw new Error('invalid rlp data'); 116 | } 117 | 118 | return _decodeChildren(data, offset, offset + 1, length); 119 | } else if (data[offset] >= 0xb8) { 120 | const lengthLength = data[offset] - 0xb7; 121 | if (offset + 1 + lengthLength > data.length) { 122 | throw new Error('invalid rlp data'); 123 | } 124 | 125 | const length = unarrayifyInteger(data, offset + 1, lengthLength); 126 | if (offset + 1 + lengthLength + length > data.length) { 127 | throw new Error('invalid rlp data'); 128 | } 129 | 130 | const result = hexlify( 131 | data.slice(offset + 1 + lengthLength, offset + 1 + lengthLength + length), 132 | ); 133 | return { consumed: 1 + lengthLength + length, result }; 134 | } else if (data[offset] >= 0x80) { 135 | const length = data[offset] - 0x80; 136 | if (offset + 1 + length > data.length) { 137 | throw new Error('invlaid rlp data'); 138 | } 139 | 140 | const result = hexlify(data.slice(offset + 1, offset + 1 + length)); 141 | return { consumed: 1 + length, result }; 142 | } 143 | return { consumed: 1, result: hexlify(data[offset]) }; 144 | } 145 | 146 | export function decode(data: Arrayish): any { 147 | const bytes = arrayify(data) || new Uint8Array(); 148 | const decoded = _decode(bytes, 0); 149 | if (decoded.consumed !== bytes.length) { 150 | throw new Error('invalid rlp data'); 151 | } 152 | return decoded.result; 153 | } 154 | -------------------------------------------------------------------------------- /packages/harmony-transaction/README.md: -------------------------------------------------------------------------------- 1 | # @harmony-js/transaction 2 | 3 | This package provides a collection of apis to create, sign/send transaction, and receive confirm/receipt. 4 | 5 | ## Installation 6 | 7 | ``` 8 | npm install @harmony-js/transaction 9 | ``` 10 | 11 | ## Usage 12 | 13 | Create a Harmony instance connecting to testnet 14 | 15 | ```javascript 16 | const { Harmony } = require('@harmony-js/core'); 17 | const { 18 | ChainID, 19 | ChainType, 20 | hexToNumber, 21 | numberToHex, 22 | fromWei, 23 | Units, 24 | Unit, 25 | } = require('@harmony-js/utils'); 26 | 27 | const hmy = new Harmony( 28 | 'https://api.s0.b.hmny.io/', 29 | { 30 | chainType: ChainType.Harmony, 31 | chainId: ChainID.HmyTestnet, 32 | }, 33 | ); 34 | ``` 35 | 36 | Creating a new transaction using parameters 37 | ```javascript 38 | const txn = hmy.transactions.newTx({ 39 | to: 'one166axnkjmghkf3df7xfvd0hn4dft8kemrza4cd2', 40 | value: new Unit(1).asOne().toWei(), 41 | // gas limit, you can use string 42 | gasLimit: '21000', 43 | // send token from shardID 44 | shardID: 0, 45 | // send token to toShardID 46 | toShardID: 0, 47 | // gas Price, you can use Unit class, and use Gwei, then remember to use toWei(), which will be transformed to BN 48 | gasPrice: new hmy.utils.Unit('1').asGwei().toWei(), 49 | }); 50 | ``` 51 | 52 | Recovering transaction from raw transaction hash 53 | ```javascript 54 | const raw = '0xf86d21843b9aca00825208808094d6ba69da5b45ec98b53e3258d7de756a567b6763880de0b6b3a76400008028a0da8887719f377401963407fc1d82d2ab52404600cf7bea37c27bd2dfd7c86aaaa03c405b0843394442b303256a804bde835821a8a77bd88a2ced9ffdc8b0a409e9'; 55 | const tx = hmy.transactions.recover(raw); 56 | ``` 57 | 58 | Getting the RLP encoding of a transaction (rawTransaction), along with raw transaction field values that were encoded 59 | ```javascript 60 | const [encoded, raw] = txn.getRLPUnsigned() 61 | ``` 62 | 63 | Sign the transaction using a wallet and send the transaction, wait for confirmation and print receipt 64 | ```javascript 65 | // key corresponds to one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7, only has testnet balance 66 | hmy.wallet.addByPrivateKey('45e497bd45a9049bcb649016594489ac67b9f052a6cdf5cb74ee2427a60bf25e'); 67 | 68 | hmy.wallet.signTransaction(txn).then(signedTxn => { 69 | signedTxn.sendTransaction().then(([tx, hash]) => { 70 | console.log('tx hash: ' + hash); 71 | signedTxn.confirm(hash).then(response => { 72 | console.log(response.receipt); 73 | }); 74 | }); 75 | }); 76 | ``` 77 | 78 | Asynchronous transaction sign, send, and confirm 79 | ```javascript 80 | async function transfer() { 81 | hmy.wallet.addByPrivateKey('45e497bd45a9049bcb649016594489ac67b9f052a6cdf5cb74ee2427a60bf25e'); 82 | 83 | const signedTxn = await hmy.wallet.signTransaction(txn); 84 | signedTxn 85 | .observed() 86 | .on('transactionHash', (txnHash) => { 87 | console.log(''); 88 | console.log('--- hash ---'); 89 | console.log(''); 90 | console.log(txnHash); 91 | console.log(''); 92 | }) 93 | .on('receipt', (receipt) => { 94 | console.log(''); 95 | console.log('--- receipt ---'); 96 | console.log(''); 97 | console.log(receipt); 98 | console.log(''); 99 | }) 100 | .on('cxReceipt', (receipt) => { 101 | console.log(''); 102 | console.log('--- cxReceipt ---'); 103 | console.log(''); 104 | console.log(receipt); 105 | console.log(''); 106 | }) 107 | .on('error', (error) => { 108 | console.log(''); 109 | console.log('--- error ---'); 110 | console.log(''); 111 | console.log(error); 112 | console.log(''); 113 | }); 114 | 115 | const [sentTxn, txnHash] = await signedTxn.sendTransaction(); 116 | 117 | const confiremdTxn = await sentTxn.confirm(txnHash); 118 | 119 | // if the transactino is cross-shard transaction 120 | if (!confiremdTxn.isCrossShard()) { 121 | if (confiremdTxn.isConfirmed()) { 122 | console.log('--- Result ---'); 123 | console.log(''); 124 | console.log('Normal transaction'); 125 | console.log(`${txnHash} is confirmed`); 126 | console.log(''); 127 | console.log('please see detail in explorer:'); 128 | console.log(''); 129 | console.log('https://explorer.testnet.harmony.one/#/tx/' + txnHash); 130 | console.log(''); 131 | process.exit(); 132 | } 133 | } 134 | if (confiremdTxn.isConfirmed() && confiremdTxn.isCxConfirmed()) { 135 | console.log('--- Result ---'); 136 | console.log(''); 137 | console.log('Cross-Shard transaction'); 138 | console.log(`${txnHash} is confirmed`); 139 | console.log(''); 140 | console.log('please see detail in explorer:'); 141 | console.log(''); 142 | console.log('https://explorer.testnet.harmony.one/#/tx/' + txnHash); 143 | console.log(''); 144 | process.exit(); 145 | } 146 | } 147 | transfer(); 148 | ``` 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /packages/harmony-network/src/providers/http.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * @module harmony-network 4 | */ 5 | 6 | import { BaseProvider } from './baseProvider'; 7 | import { fetchRPC } from './defaultFetcher'; 8 | import { composeMiddleware, performRPC, DEFAULT_TIMEOUT, DEFAULT_HEADERS } from '../rpcMethod/net'; 9 | 10 | import { RPCRequestPayload } from '../types'; 11 | 12 | /** @hidden */ 13 | const defaultOptions = { 14 | method: 'POST', 15 | timeout: DEFAULT_TIMEOUT, 16 | headers: DEFAULT_HEADERS, 17 | user: null, 18 | password: null, 19 | }; 20 | 21 | class HttpProvider extends BaseProvider { 22 | url: string; 23 | fetcher?: any; 24 | options?: any; 25 | constructor(url: string, options?: any, fetcher?: any) { 26 | super(url); 27 | this.url = url || 'http://localhost:9500'; 28 | this.fetcher = fetcher || fetchRPC; 29 | if (options) { 30 | this.options = { 31 | method: options.method || defaultOptions.method, 32 | timeout: options.timeout || defaultOptions.timeout, 33 | user: options.user || defaultOptions.user, 34 | password: options.password || defaultOptions.password, 35 | headers: options.headers || defaultOptions.headers, 36 | }; 37 | } else { 38 | this.options = defaultOptions; 39 | } 40 | } 41 | 42 | /** 43 | * @function send 44 | * @memberof HttpProvider.prototype 45 | * @param {Object} payload - payload object 46 | * @param {Function} callback - callback function 47 | * @return {any} - RPC Response 48 | */ 49 | send(payload: RPCRequestPayload, callback?: any): Promise { 50 | return this.requestFunc({ payload, callback }); 51 | } 52 | 53 | /** 54 | * @function sendServer 55 | * @memberof HttpProvider.prototype 56 | * @param {String} endpoint - endpoint to server 57 | * @param {Object} payload - payload object 58 | * @param {Function} callback - callback function 59 | * @return {Function} - RPC Response 60 | */ 61 | sendServer(endpoint: string, payload: RPCRequestPayload, callback: any): Promise { 62 | return this.requestFunc({ endpoint, payload, callback }); 63 | } 64 | 65 | requestFunc({ 66 | endpoint, 67 | payload, 68 | callback, 69 | }: { 70 | endpoint?: string; 71 | payload: RPCRequestPayload; 72 | callback?: any; 73 | }): Promise { 74 | const [tReq, tRes] = this.getMiddleware(payload.method); 75 | const reqMiddleware = composeMiddleware( 76 | ...tReq, 77 | (obj: object) => this.optionsHandler(obj), 78 | (obj: object) => this.endpointHandler(obj, endpoint), 79 | this.payloadHandler, 80 | ); 81 | const resMiddleware = composeMiddleware( 82 | (data: object) => this.callbackHandler(data, callback), 83 | ...tRes, 84 | ); 85 | 86 | const req = reqMiddleware(payload); 87 | 88 | return performRPC(req, resMiddleware, this.fetcher); 89 | } 90 | 91 | /** 92 | * @function payloadHandler 93 | * @memberof HttpProvider.prototype 94 | * @param {Object} payload - payload object 95 | * @return {Object} - to payload object 96 | */ 97 | payloadHandler(payload: RPCRequestPayload): object { 98 | return { payload }; 99 | } 100 | 101 | /** 102 | * @function endpointHandler 103 | * @memberof HttpProvider.prototype 104 | * @param {Object} obj - payload object 105 | * @param {String} endpoint - add the endpoint to payload object 106 | * @return {Object} - assign a new object 107 | */ 108 | endpointHandler(obj: object, endpoint?: string): object { 109 | return { 110 | ...obj, 111 | url: endpoint !== null && endpoint !== undefined ? `${this.url}${endpoint}` : this.url, 112 | }; 113 | } 114 | 115 | /** 116 | * @function optionsHandler 117 | * @memberof HttpProvider.prototype 118 | * @param {object} obj - options object 119 | * @return {object} - assign a new option object 120 | */ 121 | optionsHandler(obj: object): object { 122 | if (this.options.user && this.options.password) { 123 | const AUTH_TOKEN = `Basic ${Buffer.from( 124 | `${this.options.user}:${this.options.password}`, 125 | ).toString('base64')}`; 126 | this.options.headers.Authorization = AUTH_TOKEN; 127 | } 128 | 129 | return { ...obj, options: this.options }; 130 | } 131 | 132 | /** 133 | * @function callbackHandler 134 | * @memberof HttpProvider.prototype 135 | * @param {Object} data - from server 136 | * @param {Function} cb - callback function 137 | * @return {Object|Function} - return object or callback function 138 | */ 139 | callbackHandler(data: any, cb: any): any { 140 | if (cb) { 141 | cb(null, data); 142 | } 143 | return data; 144 | } 145 | 146 | subscribe() { 147 | throw new Error('HTTPProvider does not support subscriptions.'); 148 | } 149 | 150 | unsubscribe() { 151 | throw new Error('HTTPProvider does not support subscriptions.'); 152 | } 153 | } 154 | 155 | export { HttpProvider }; 156 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Harmony JavaScript SDK 2 | 3 | [![npm version](https://img.shields.io/npm/v/@harmony-js/core.svg?style=flat-square)](https://www.npmjs.com/package/@harmony-js/core) 4 | [![Build Status](https://travis-ci.com/FireStack-Lab/Harmony-sdk-core.svg?branch=master)](https://travis-ci.com/FireStack-Lab/Harmony-sdk-core) 5 | 6 | This is the Harmony Javascript SDK which provides an easier way to interact with Harmony blockchain. 7 | 8 | Please read the [documentation](https://jssdk.doc.hmny.io/) for full API doc. 9 | 10 | The SDK includes following packages with package-level documentation and examples inside each package. 11 | 12 | 1. [@harmony-js/core](https://github.com/harmony-one/sdk/tree/master/packages/harmony-core) 13 | 2. [@harmony-js/account](https://github.com/harmony-one/sdk/tree/master/packages/harmony-account) 14 | 3. [@harmony-js/crypto](https://github.com/harmony-one/sdk/tree/master/packages/harmony-crypto) 15 | 4. [@harmony-js/network](https://github.com/harmony-one/sdk/tree/master/packages/harmony-network) 16 | 5. [@harmony-js/utils](https://github.com/harmony-one/sdk/tree/master/packages/harmony-utils) 17 | 6. [@harmony-js/transaction](https://github.com/harmony-one/sdk/tree/master/packages/harmony-transaction) 18 | 7. [@harmony-js/contract](https://github.com/harmony-one/sdk/tree/master/packages/harmony-contract) 19 | 8. [@harmony-js/staking](https://github.com/harmony-one/sdk/tree/master/packages/harmony-staking) 20 | 21 | # Examples 22 | 23 | * [A Token Faucet Demo DApp](https://github.com/harmony-one/token-faucet-demo-dapp) 24 | * [Hackathon DApps](https://docs.harmony.one/home/showcases/applications): DApps built during our internal hackathon 25 | * [soccerplayers](https://github.com/gupadhyaya/soccerplayers), [onemoji](https://github.com/peekpi/onemoji), [harmonauts](https://github.com/ivorytowerdds/harmonauts), [good-one](https://github.com/harmony-one/dapp-demo-crowdfunding) 26 | * [Cross-chain Apps](https://docs.harmony.one/home/showcases/crosschain) [the link contains code, demo, and more information] 27 | * [DeFi Apps](https://docs.harmony.one/home/showcases/defi) 28 | * [DevPost Hackathon Apps](https://docs.harmony.one/home/showcases/hackathons) 29 | * Eth<>Harmony Bridge Components: [frontend](https://github.com/harmony-one/ethhmy-bridge.frontend), [backend](https://github.com/harmony-one/ethhmy-bridge.appengine), [smart contracts](https://github.com/harmony-one/ethhmy-bridge), [test scripts](https://github.com/harmony-one/ethhmy-bridge.tests) 30 | * Eth<>Harmony bridge SDKs: [main sdk](https://github.com/harmony-one/ethhmy-bridge.sdk), [bridge UI widget](https://github.com/harmony-one/ethhmy-bridge.ui-sdk) 31 | * Swoop Dex: [interface](https://github.com/harmony-one/swoop-interface), [cli](https://github.com/harmony-one/swoop-cli), [sdk](https://github.com/harmony-one/swoop-sdk), [deployment](https://github.com/harmony-one/swoop-deployment), [misc](https://github.com/harmony-one/swoop-misc), [lib](https://github.com/harmony-one/swoop-lib), [periphery](https://github.com/harmony-one/swoop-periphery), [core](https://github.com/harmony-one/swoop-core), [testing](https://github.com/harmony-one/swoop-testing), [utils](https://github.com/harmony-one/swoop-utils) 32 | * [Iris Bridge](https://github.com/harmony-one/ethhmy-bridge-v2): inspired from near's rainbow bridge 33 | * [Animoca's BeastQuest Game](https://github.com/harmony-one/BeastQuest) 34 | * [Chainlink Testnet Integration Demo](https://github.com/harmony-one/chainlink-demo-project) 35 | * [NFT Store DApp](https://github.com/harmony-one/nft-store) 36 | * [old dapp-examples](https://github.com/harmony-one/dapp-examples): some of them may be outdated! 37 | 38 | 39 | # Installation 40 | 41 | This library works on both nodejs and browser. Please use it according to your use case. 42 | 43 | ## Enviorment requirement 44 | 45 | * Nodejs: 10.0+ 46 | * Browser: Latest Chrome and Firefox 47 | 48 | ## Install from npm/yarn 49 | 50 | **Note: we added a @next tag to npm package, please use the following command to install with npm/yarn** 51 | 52 | ```bash 53 | 54 | # npm 55 | npm install @harmony-js/core@next 56 | 57 | # yarn 58 | yarn add @harmony-js/core@next 59 | 60 | # tslib is required, we'd better install it as well 61 | npm install tslib 62 | yarn add tslib 63 | 64 | ``` 65 | 66 | # Building from source files 67 | 68 | ## Install `lerna` and `typescript` globally 69 | 70 | ```bash 71 | yarn global add lerna && yarn global add typescript 72 | ``` 73 | ## Bootstrap and build 74 | 75 | ```bash 76 | yarn bootstrap 77 | ``` 78 | 79 | ## Bundle 80 | 81 | Build `umd` and `esm` version javascript for each sub-packages, which can be accessed by `import` or `require` 82 | 83 | ```bash 84 | yarn dist 85 | ``` 86 | All files are exported in `packages/dist` folder, use `**.esm.js` or `**.umd.js` format 87 | 88 | 89 | # Running Tests 90 | ## Unit tests 91 | ```bash 92 | yarn test:src 93 | ``` 94 | ## e2e tests 95 | 96 | 1. Remove the `'cross-fetch': 'jest-fetch-mock'` line from `scripts/jest/jest.e2e.config.js` 97 | 1. Run harmony node locally, follow the instructions: https://github.com/harmony-one/harmony 98 | 1. Wait for 1-2 mins, and run this: 99 | ```bash 100 | yarn build && yarn test:e2e 101 | ``` 102 | 103 | 104 | 105 | 106 | --------------------------------------------------------------------------------