[WIP] update blockchain and rpcs

@types
neeboo 6 years ago
parent aad1b492cb
commit b2f659a7d0
  1. 184
      examples/testNode.js
  2. 1
      package.json
  3. 1
      packages/harmony-account/package.json
  4. 18
      packages/harmony-account/src/account.ts
  5. 3
      packages/harmony-account/src/wallet.ts
  6. 24
      packages/harmony-core/src/harmony.ts
  7. 2
      packages/harmony-core/src/index.ts
  8. 5
      packages/harmony-core/src/types.ts
  9. 2
      packages/harmony-core/tsconfig.json
  10. 1
      packages/harmony-network/package.json
  11. 63
      packages/harmony-network/src/blockchain/blockchain.ts
  12. 2
      packages/harmony-network/src/blockchain/rpc.ts
  13. 2
      packages/harmony-network/src/blockchain/rpcBuilder.ts
  14. 33
      packages/harmony-network/src/messenger/messenger.ts
  15. 2
      packages/harmony-network/src/providers/baseProvider.ts
  16. 2
      packages/harmony-network/src/types.ts
  17. 3
      packages/harmony-network/tsconfig.json
  18. 1
      packages/harmony-transaction/package.json
  19. 3
      packages/harmony-transaction/src/factory.ts
  20. 81
      packages/harmony-transaction/src/transaction.ts
  21. 20
      packages/harmony-transaction/src/types.ts
  22. 5
      packages/harmony-transaction/src/utils.ts
  23. 26
      packages/harmony-utils/src/chain.ts
  24. 1
      packages/harmony-utils/src/index.ts
  25. 2
      packages/harmony-utils/src/utils.ts
  26. 23
      packages/harmony-utils/src/validators.ts

@ -1,132 +1,66 @@
const { Account, Wallet } = require('@harmony/account');
const {
isAddress,
isPrivateKey,
numberToHex,
numToStr,
hexToNumber,
Unit,
strip0x,
} = require('@harmony/utils');
const { HttpProvider, Messenger } = require('@harmony/network');
const { Transaction, TransactionFactory } = require('@harmony/transaction');
const {
arrayify,
hexlify,
BN,
encode,
decode,
getContractAddress,
recoverAddress,
recoverPublicKey,
keccak256,
hexZeroPad,
getAddressFromPublicKey,
} = require('@harmony/crypto');
const { Harmony } = require('@harmony/core');
const ganache = require('ganache-cli');
const msgr = new Messenger(new HttpProvider('https://dev-api.zilliqa.com'));
const wallet = new Wallet(msgr);
const transactions = new TransactionFactory(msgr);
async function testEncrypt() {
const mne = wallet.generateMnemonic();
console.log('---hint: please write these down');
console.log(`${mne}`);
const newAcc = wallet.addByMnemonic(mne);
const password = '123456';
console.log('---hint: we use this dump password to encrypt, lol');
console.log(`${password}`);
var port = 18545;
await wallet.encryptAccount(newAcc.address, password);
var privateKey =
'0xe19d05c5452598e24caad4a0d85a49146f7be089515c905ae6a19e8a578a6930';
console.log('---hint: Encrypting...');
console.log('---hint: Done!');
console.log('---hint: Your account address is:');
const encrypted = wallet.getAccount(newAcc.address);
console.log(`${encrypted.address}`);
console.log('---hint: here is your keyStore file:');
console.log(`${encrypted.privateKey}`);
}
var sendTo = '0xccaed3f53bd0a55db215cc58182969e59d2242fe';
// testEncrypt();
async function testSign(prvKey, data) {
const newAcc = wallet.addByPrivateKey(prvKey);
const result = await newAcc.sign(data);
console.log(result);
}
// testSign(
// '0x0123456789012345678901234567890123456789012345678901234567890123',
// '0x06',
// );
const txn = new Transaction({
to: '0xaa4cf82d745c3ead6c8275d782d6cb0a6beac617',
data: '0x',
gasLimit: '0xbfa8a6d03fa6',
gasPrice: '0x',
value: '0x7a92fecc67512737',
nonce: '0xf8',
chainId: 0,
var server = ganache.server({
accounts: [{ secretKey: privateKey, balance: '0x21e19e0c9bab2400000' }],
default_balance_ether: 10000,
});
const acc = wallet.addByPrivateKey(
'0xc3886f791236bf31fe8fd7522a7b12808700deb9c159826fc99236c74614118b',
);
// console.log(txn.getRLPUnsigned()[0]);
// const signed = wallet
// .getAccount(acc.address)
// .signTransaction(txn, false)
// .then((tx) => {
// const newTx = tx.recover(tx.unsignedTxnHash);
// // console.log(newTx);
// acc.signTransaction(newTx, false, 'rlp').then((signed) => {
// const ttt = transactions.recover(signed.txnHash);
// console.log(ttt);
// });
// });
// recoverAddress();
// console.log(wallet.messenger);
// console.log(hexlify(0));
// 0xda8003049401234567890123456789012345678901234567890580;
// 0xda8003049401234567890123456789012345678901234567890580;
/**
* { name: 'nonce', length: 32, fix: false },
{ name: 'gasPrice', length: 32, fix: false, transform: 'hex' },
{ name: 'gasLimit', length: 32, fix: false, transform: 'hex' },
{ name: 'to', length: 20, fix: true },
{ name: 'value', length: 32, fix: false, transform: 'hex' },
{ name: 'data', fix: false },
*/
// const [nonce, gasPrice, gasLimit, to, value, data] = decode(
// txn.getRLPUnsigned()[0],
// );
// console.log({
// nonce: new BN(strip0x(hexToNumber(nonce))).toNumber(),
// gasPrice: hexToNumber(gasPrice !== '0x' ? gasPrice : '0x00'),
// gasLimit: hexToNumber(gasLimit !== '0x' ? gasLimit : '0x00'),
// to: hexToNumber(to !== '0x' ? to : '0x00'),
// value: hexToNumber(value !== '0x' ? value : '0x00'),
// data: hexToNumber(data !== '0x' ? data : '0x00'),
// });
// console.log(getContractAddress(acc.publicKey, 248));
// const harmony = new Harmony('https://dev-api.zilliqa.com');
// const file =
// '{"version":3,"id":"05D302EE-23DC-48C4-B89C-CAAAC1C780C4","x-ethers":{"gethFilename":"UTC--2018-01-26T20-25-02.0Z--15db397ed5f682acb22b0afc6c8de4cdfbda7cbc","mnemonicCiphertext":"b92c7c3da540ae7beee55365fb330c33","mnemonicCounter":"a65d689a73c096025f2acae3f7068510","client":"ethers/iOS","version":"0.1"},"Crypto":{"ciphertext":"fa6ff2374087a089ec9fcba3bc21389f5e26ec2932c95b608ebe0218efab83c6","cipherparams":{"iv":"5ddca45b254406516ca2c97d18d5dfd9"},"kdf":"scrypt","kdfparams":{"r":8,"p":1,"n":262144,"dklen":32,"salt":"864a474f8586ab0fa97ed9240ae6227b2b22b48bdf298137c355e4a07eb19831"},"mac":"eaa89325acedbf88c0893e53c8c8d426b590655746c66da9cd76e4f72d84084f","cipher":"aes-128-ctr"},"address":"15db397ed5f682acb22b0afc6c8de4cdfbda7cbc"}';
// const acc2 = new Account().fromFile(file, 'password').then(console.log);
server.listen(port, function(err, blockchain) {
const harmony = new Harmony(`http://localhost:${port}`, 1);
const acc = harmony.wallet.addByPrivateKey(privateKey);
// // console.log(acc.address);
acc.getBalance().then((c) => {
console.log(c);
});
const txn = harmony.transactions.newTx({
nonce: 1,
to: sendTo,
value: 1,
gasLimit: new harmony.utils.Unit('21000').asWei().toWei(),
gasPrice: new harmony.utils.Unit('100000000000').asWei().toWei(),
});
// console.log(blockchain);
acc.signTransaction(txn, true).then((signed) => {
// console.log(signed.txPayload);
harmony.messenger
.send('hmy_sendTransaction', [signed.txPayload])
.then((res) => {
console.log(res);
txn.confirm(res).then((result) => {
harmony.blockchain
.getBlockByHash({
hash: result.receipt.blockHash,
returnObject: false,
})
.then((obj) => {
console.log(obj);
});
});
// harmony.blockchain.getBlockByHash({ hash: res }).then((obj) => {
// console.log(obj);
// });
});
// signed.sendTransaction().then((msg) => {
// const [txn, result] = msg;
// txn.confirm(result).then((result) => {
// console.log(`--------------`);
// console.log(result);
// });
// });
});
// console.log(harmony.messenger.setRPCPrefix('eth_getPPP'));
});

@ -71,6 +71,7 @@
"dotenv": "^6.0.0",
"fancy-log": "^1.3.2",
"fbjs-scripts": "^0.8.3",
"ganache-cli": "^6.4.3",
"glob": "^7.1.3",
"glob-parent": "^3.1.0",
"gulp": "^4.0.0",

@ -14,6 +14,7 @@
"author": "neeboo@firestack.one",
"license": "ISC",
"dependencies": {
"@harmony/core": "^0.0.1",
"@harmony/crypto": "^0.0.1",
"@harmony/network": "^0.0.1",
"@harmony/transaction": "^0.0.1",

@ -101,14 +101,17 @@ class Account {
*/
async getBalance(): Promise<object> {
if (this.messenger) {
const result = await this.messenger.send(RPCMethod.GetBalance, [
const balance = await this.messenger.send(RPCMethod.GetBalance, [
this.address,
'latest',
]);
if (result.responseType === 'result') {
this.balance = hexToNumber(result.balance);
this.nonce = Number.parseInt(hexToNumber(result.nonce), 10);
}
const nonce = await this.messenger.send(RPCMethod.GetTransactionCount, [
this.address,
'latest',
]);
this.balance = balance;
this.nonce = Number.parseInt(hexToNumber(nonce), 10);
}
return {
balance: this.balance,
@ -127,7 +130,7 @@ class Account {
async signTransaction(
transaction: Transaction,
updateNonce: boolean = true,
updateNonce: boolean = false,
encodeMode: string = 'rlp',
): Promise<Transaction> {
if (!this.privateKey || !isPrivateKey(this.privateKey)) {
@ -139,7 +142,8 @@ class Account {
transaction.setParams({
...transaction.txParams,
from: this.address || '0x',
nonce: balanceObject.nonce + 1,
// nonce is different from Zilliqa's setting, would be current nonce, not nonce + 1
nonce: balanceObject.nonce,
});
}
if (encodeMode === 'rlp') {

@ -184,6 +184,9 @@ class Wallet {
this.accountMap.delete(address);
}
setMessenger(messenger: Messenger) {
this.messenger = messenger;
}
/**
* @function isValidMnemonic
* @memberof Wallet

@ -5,7 +5,7 @@ import { HttpProvider, Messenger, Blockchain } from '@harmony/network';
import { TransactionFactory, Transaction } from '@harmony/transaction';
import { Wallet, Account } from '@harmony/account';
class Harmony {
class Harmony extends utils.HarmonyCore {
Modules = {
HttpProvider,
Messenger,
@ -23,15 +23,31 @@ class Harmony {
utils: any;
private provider: HttpProvider;
constructor(url: string) {
constructor(
url: string,
chainType: utils.ChainType = utils.ChainType.Harmony,
) {
super(chainType);
this.provider = new HttpProvider(url);
this.messenger = new Messenger(this.provider);
this.blockchain = new Blockchain(this.messenger);
this.messenger = new Messenger(this.provider, this.chainType);
this.blockchain = new Blockchain(this.messenger, this.chainType);
this.transactions = new TransactionFactory(this.messenger);
this.wallet = new Wallet(this.messenger);
this.crypto = crypto;
this.utils = utils;
}
setProvider(provider: string | HttpProvider): void {
if (utils.isHttp(provider) && typeof provider === 'string') {
this.provider = new HttpProvider(provider);
} else if (provider instanceof HttpProvider) {
this.provider = provider;
}
this.messenger.setProvider(this.provider);
this.blockchain.setMessenger(this.messenger);
this.wallet.setMessenger(this.messenger);
this.transactions.setMessenger(this.messenger);
}
}
export { Harmony };

@ -1,2 +1,2 @@
export * from './core';
export * from './harmony';
// export * from './types';

@ -11,3 +11,8 @@ export interface HarmonyModule {
Transaction: Transaction;
Account: Account;
}
export const enum UrlType {
http,
ws,
}

@ -4,7 +4,7 @@
"outDir": "dist",
"rootDir": "src"
},
"include": ["src", "../../typings/**/*.d.ts"],
"include": ["src", "../../typings/**/*.d.ts", "../harmony-utils/src/core.ts"],
"references": [
{ "path": "../harmony-account" },
{ "path": "../harmony-crypto" },

@ -15,6 +15,7 @@
"license": "ISC",
"dependencies": {
"cross-fetch": "^3.0.2",
"@harmony/core": "^0.0.1",
"@harmony/utils": "^0.0.1"
}
}

@ -1,14 +1,28 @@
import { RPCMethod } from './rpc';
import { Messenger } from '../messenger/messenger';
import { assertObject, AssertType } from '@harmony/utils';
import {
assertObject,
AssertType,
HarmonyCore,
ChainType,
} from '@harmony/utils';
class Blockchain {
class Blockchain extends HarmonyCore {
messenger: Messenger;
chainType: ChainType;
constructor(messenger: Messenger) {
constructor(messenger: Messenger, chainType: ChainType = ChainType.Harmony) {
super(chainType);
this.messenger = messenger;
this.chainType = chainType;
}
setMessenger(messenger: Messenger) {
this.messenger = messenger;
}
/**
*
*/
@assertObject({
address: ['isAddress', AssertType.required],
blockNumber: ['isHex', AssertType.optional],
@ -23,10 +37,45 @@ class Blockchain {
blockNumber: string;
tag: string;
}) {
const result = await this.messenger.send(RPCMethod.GetBalance, [
address,
blockNumber || tag,
]);
const result = await this.messenger.send(
RPCMethod.GetBalance,
[address, blockNumber || tag],
this.chainPrefix,
);
return result;
}
@assertObject({
hash: ['isHash', AssertType.required],
returnObject: ['isBoolean', AssertType.optional],
})
async getBlockByHash({
hash,
returnObject = true,
}: {
hash: string;
returnObject: boolean;
}) {
const result = await this.messenger.send(
RPCMethod.GetBlockByHash,
[hash, returnObject],
this.chainPrefix,
);
return result;
}
/**
*
*/
@assertObject({
hash: ['isString', AssertType.required],
})
async getTransactionReceipt({ hash }: { hash: string }) {
const result = await this.messenger.send(
RPCMethod.GetTransactionReceipt,
[hash],
this.chainPrefix,
);
return result;
}
}

@ -15,6 +15,8 @@ export const enum RPCMethod {
GetTransactionByBlockNumberAndIndex = 'hmy_getTransactionByBlockNumberAndIndex',
// 8. hmy_getTransactionByHash
GetTransactionByHash = 'hmy_getTransactionByHash',
GetTransactionReceipt = 'hmy_getTransactionReceipt',
// 9. hmy_syncing
Syncing = 'hmy_syncing',
// 10. net_peerCount

@ -25,7 +25,7 @@ class JsonRpc {
* @return {Object} payload object
*/
toPayload = (
method: RPCMethod,
method: RPCMethod | string,
params: string | undefined | any[],
): RPCRequestPayload<object> => {
// FIXME: error to be done by shared/errors

@ -1,3 +1,4 @@
import { HarmonyCore, ChainType, isString } from '@harmony/utils';
import { JsonRpc } from '../blockchain/rpcbuilder';
import { ResponseMiddleware } from './responseMiddleware';
import { HttpProvider } from '../providers/http';
@ -34,14 +35,19 @@ const defaultConfig = {
* @param {Object} config config object
* @return {Messenger} Messenger instance
*/
class Messenger {
class Messenger extends HarmonyCore {
provider: HttpProvider;
config?: object;
// tslint:disable-next-line: variable-name
Network_ID: string = 'Default';
JsonRpc: JsonRpc;
constructor(provider: HttpProvider, config?: object) {
constructor(
provider: HttpProvider,
chainType: ChainType = ChainType.Harmony,
config?: object,
) {
super(chainType);
/**
* @var {Provider} provider
* @memberof Messenger.prototype
@ -79,10 +85,20 @@ class Messenger {
* @param {Object} params - RPC method params
* @return {Object} RPC result
*/
send = async (method: RPCMethod, params?: string | any[] | undefined) => {
send = async (
method: RPCMethod | string,
params?: string | any[] | undefined,
rpcPrefix?: string,
) => {
this.providerCheck();
let rpcMethod = method;
if (rpcPrefix && isString(rpcPrefix) && rpcPrefix !== this.chainPrefix) {
rpcMethod = this.setRPCPrefix(method, rpcPrefix);
} else if (!rpcPrefix || rpcPrefix === this.chainPrefix) {
rpcMethod = this.setRPCPrefix(method, this.chainPrefix);
}
try {
const payload = this.JsonRpc.toPayload(method, params);
const payload = this.JsonRpc.toPayload(rpcMethod, params);
this.setResMiddleware((data: any) => new ResponseMiddleware(data));
const result = await this.provider.send(payload);
return getResultForData(result); // getResultForData(result)
@ -144,5 +160,14 @@ class Messenger {
setNetworkID(id: string) {
this.Network_ID = id;
}
setRPCPrefix(method: RPCMethod | string, prefix: string): string {
const stringArray: string[] = method.split('_');
if (stringArray.length !== 2) {
throw new Error(`could not set prefix with ${method}`);
}
stringArray[0] = prefix;
return stringArray.join('_');
}
}
export { Messenger };

@ -45,7 +45,7 @@ class BaseProvider {
}
}
protected getMiddleware(
method: RPCMethod,
method: RPCMethod | string,
): [ReqMiddleware[], ResMiddleware[]] {
const requests: ReqMiddleware[] = [];
const responses: ResMiddleware[] = [];

@ -16,7 +16,7 @@ export interface Middleware {
export interface RPCRequestPayload<T> {
id: number;
jsonrpc: string;
method: RPCMethod;
method: RPCMethod | string;
params: T;
}

@ -4,5 +4,6 @@
"outDir": "dist",
"rootDir": "src"
},
"include": ["src", "../../typings/**/*.d.ts"]
"include": ["src", "../../typings/**/*.d.ts"],
"references": [{ "path": "../harmony-utils" }]
}

@ -14,6 +14,7 @@
"author": "neeboo@firestack.one",
"license": "ISC",
"dependencies": {
"@harmony/core": "^0.0.1",
"@harmony/crypto": "^0.0.1",
"@harmony/utils": "^0.0.1",
"@harmony/network":"^0.0.1"

@ -8,6 +8,9 @@ class TransactionFactory {
constructor(messenger: Messenger) {
this.messenger = messenger;
}
setMessenger(messenger: Messenger) {
this.messenger = messenger;
}
getContractAddress(tx: Transaction) {
const { from, nonce } = tx.txParams;
return getContractAddress(from, Number.parseInt(`${nonce}`, 10));

@ -7,14 +7,15 @@ import {
Signature,
splitSignature,
} from '@harmony/crypto';
import { add0xToString } from '@harmony/utils';
import { add0xToString, numberToHex } from '@harmony/utils';
import { Messenger, RPCMethod } from '@harmony/network';
import { TxParams, TxStatus } from './types';
import { recover, transactionFields } from './utils';
import { TxParams, TxStatus, TransasctionReceipt } from './types';
import { recover, transactionFields, sleep } from './utils';
class Transaction {
messenger?: Messenger;
txStatus: TxStatus;
receipt?: TransasctionReceipt;
private id: string;
private from: string;
private nonce: number | string;
@ -53,10 +54,15 @@ class Transaction {
recoveryParam: 0,
v: 0,
};
this.receipt = params ? params.receipt : undefined;
this.messenger = messenger;
this.txStatus = txStatus;
}
setMessenger(messenger: Messenger) {
this.messenger = messenger;
}
getRLPUnsigned(): [string, any[]] {
const raw: Array<string | Uint8Array> = [];
@ -64,9 +70,7 @@ class Transaction {
let value = (<any>this.txParams)[field.name] || [];
value = arrayify(
hexlify(
field.transform === 'hex'
? add0xToString(value.toString('hex'))
: value,
field.transform === 'hex' ? add0xToString(value.toString(16)) : value,
),
);
// Fixed-width field
@ -120,6 +124,18 @@ class Transaction {
this.setParams(recover(txnHash));
return this;
}
// use when using eth_sendTransaction
get txPayload() {
return {
from: this.from,
to: this.to,
gas: numberToHex(this.gasLimit),
gasPrice: numberToHex(this.gasPrice),
value: numberToHex(this.value),
data: this.data || '0x',
nonce: numberToHex(this.nonce),
};
}
get txParams(): TxParams {
return {
@ -205,7 +221,7 @@ class Transaction {
throw new Error('Messenger not found');
}
const result = await this.messenger.send(
RPCMethod.SendTransaction,
RPCMethod.SendRawTransaction,
this.txnHash,
);
@ -214,10 +230,59 @@ class Transaction {
this.id = result;
this.setTxStatus(TxStatus.PENDING);
return [this, result];
} else {
} else if (typeof result !== 'string' && result.responseType === 'error') {
this.setTxStatus(TxStatus.REJECTED);
return [this, `transaction failed:${result.message}`];
} else {
throw new Error('transaction failed');
}
}
async trackTx(txHash: string) {
if (!this.messenger) {
throw new Error('Messenger not found');
}
// TODO: regex validation for txHash so we don't get garbage
const res: TransasctionReceipt = await this.messenger.send(
RPCMethod.GetTransactionReceipt,
txHash,
);
if (res.responseType === 'error') {
return false;
}
this.receipt = res;
this.id = res.transactionHash;
this.txStatus =
this.receipt.status && this.receipt.status === '0x1'
? TxStatus.CONFIRMED
: TxStatus.REJECTED;
return true;
}
async confirm(
txHash: string,
maxAttempts: number = 20,
interval: number = 1000,
) {
this.txStatus = TxStatus.PENDING;
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
try {
if (await this.trackTx(txHash)) {
return this;
}
} catch (err) {
this.txStatus = TxStatus.REJECTED;
throw err;
}
if (attempt + 1 < maxAttempts) {
await sleep(interval * attempt);
}
}
this.txStatus = TxStatus.REJECTED;
throw new Error(
`The transaction is still not confirmed after ${maxAttempts} attempts.`,
);
}
}
export { Transaction };

@ -12,6 +12,7 @@ export interface TxParams {
txnHash: string;
unsignedTxnHash: string;
signature: Signature;
receipt?: TransasctionReceipt;
}
export const enum TxStatus {
@ -21,3 +22,22 @@ export const enum TxStatus {
CONFIRMED = 'CONFIRMED',
REJECTED = 'REJECTED',
}
export interface TransasctionReceipt {
transactionHash: string;
transactionIndex: string;
blockHash: string;
blockNumber: string; // 11
from: string;
to: string;
gasUsed: string;
cumulativeGasUsed: string; // 13244
contractAddress?: string | null; // or null, if none was created
logs: any[];
status: string;
logsBloom: string; // 256 byte bloom filter
v: string;
r: string;
s: string;
responseType?: string;
}

@ -122,3 +122,8 @@ export const recover = (rawTransaction: string) => {
return tx;
};
export const sleep = async (ms: number) =>
new Promise((resolve) => {
setTimeout(() => resolve(), ms);
});

@ -0,0 +1,26 @@
const enum ChainType {
Harmony,
Ethereum,
}
abstract class HarmonyCore {
chainType: ChainType;
constructor(chainType: ChainType) {
this.chainType = chainType;
}
get chainPrefix(): string {
switch (this.chainType) {
case ChainType.Ethereum: {
return 'eth';
}
case ChainType.Harmony: {
return 'hmy';
}
default: {
return 'hmy';
}
}
}
}
export { HarmonyCore, ChainType };

@ -1,3 +1,4 @@
export * from './validators';
export * from './transformers';
export * from './utils';
export * from './chain';

@ -10,6 +10,7 @@ import {
isPublicKey,
isPrivateKey,
isAddress,
isHash,
} from './validators';
export const enum AssertType {
@ -29,6 +30,7 @@ export const validatorArray: any = {
isPublicKey: [isPublicKey],
isPrivateKey: [isPrivateKey],
isAddress: [isAddress],
isHash: [isHash],
};
export function validateArgs(

@ -18,6 +18,11 @@ export const isPublicKey = (publicKey: string): boolean => {
};
isPublicKey.validator = 'isPublicKey';
export const isHash = (hash: string): boolean => {
return isKeyString(hash, 64);
};
isHash.validator = 'isHash';
/**
* [isNumber verify param is a Number]
* @param {any} obj [value]
@ -115,3 +120,21 @@ export const isHex = (obj: any): boolean => {
};
isHex.validator = 'isHex';
export const isHttp = (obj: any): boolean => {
if (!isString(obj)) {
throw new Error(`${obj} is not valid url`);
} else {
return obj.startsWith('http://') || obj.startsWith('https://');
}
};
isHttp.validator = 'isHttp';
export const isWs = (obj: any): boolean => {
if (!isString(obj)) {
throw new Error(`${obj} is not valid url`);
} else {
return obj.startsWith('ws://') || obj.startsWith('websocket://');
}
};
isWs.validator = 'isWs';

Loading…
Cancel
Save