aboutsummaryrefslogtreecommitdiffstats
path: root/packages/utils/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/utils/src')
-rw-r--r--packages/utils/src/address_utils.ts36
-rw-r--r--packages/utils/src/class_utils.ts18
-rw-r--r--packages/utils/src/configured_bignumber.ts9
-rw-r--r--packages/utils/src/index.ts6
-rw-r--r--packages/utils/src/interval_utils.ts37
-rw-r--r--packages/utils/src/promisify.ts11
6 files changed, 108 insertions, 9 deletions
diff --git a/packages/utils/src/address_utils.ts b/packages/utils/src/address_utils.ts
new file mode 100644
index 000000000..f94985441
--- /dev/null
+++ b/packages/utils/src/address_utils.ts
@@ -0,0 +1,36 @@
+import * as jsSHA3 from 'js-sha3';
+
+const BASIC_ADDRESS_REGEX = /^(0x)?[0-9a-f]{40}$/i;
+const SAME_CASE_ADDRESS_REGEX = /^(0x)?([0-9a-f]{40}|[0-9A-F]{40})$/;
+
+export const addressUtils = {
+ isChecksumAddress(address: string): boolean {
+ // Check each case
+ const unprefixedAddress = address.replace('0x', '');
+ const addressHash = jsSHA3.keccak256(unprefixedAddress.toLowerCase());
+
+ for (let i = 0; i < 40; i++) {
+ // The nth letter should be uppercase if the nth digit of casemap is 1
+ if (
+ (parseInt(addressHash[i], 16) > 7 && unprefixedAddress[i].toUpperCase() !== unprefixedAddress[i]) ||
+ (parseInt(addressHash[i], 16) <= 7 && unprefixedAddress[i].toLowerCase() !== unprefixedAddress[i])
+ ) {
+ return false;
+ }
+ }
+ return true;
+ },
+ isAddress(address: string): boolean {
+ if (!BASIC_ADDRESS_REGEX.test(address)) {
+ // Check if it has the basic requirements of an address
+ return false;
+ } else if (SAME_CASE_ADDRESS_REGEX.test(address)) {
+ // If it's all small caps or all all caps, return true
+ return true;
+ } else {
+ // Otherwise check each case
+ const isValidChecksummedAddress = addressUtils.isChecksumAddress(address);
+ return isValidChecksummedAddress;
+ }
+ },
+};
diff --git a/packages/utils/src/class_utils.ts b/packages/utils/src/class_utils.ts
new file mode 100644
index 000000000..04e60ee57
--- /dev/null
+++ b/packages/utils/src/class_utils.ts
@@ -0,0 +1,18 @@
+import * as _ from 'lodash';
+
+export const classUtils = {
+ // This is useful for classes that have nested methods. Nested methods don't get bound out of the box.
+ bindAll(self: any, exclude: string[] = ['contructor'], thisArg?: any): void {
+ for (const key of Object.getOwnPropertyNames(self)) {
+ const val = self[key];
+ if (!_.includes(exclude, key)) {
+ if (_.isFunction(val)) {
+ self[key] = val.bind(thisArg || self);
+ } else if (_.isObject(val)) {
+ classUtils.bindAll(val, exclude, self);
+ }
+ }
+ }
+ return self;
+ },
+};
diff --git a/packages/utils/src/configured_bignumber.ts b/packages/utils/src/configured_bignumber.ts
new file mode 100644
index 000000000..e44c062c2
--- /dev/null
+++ b/packages/utils/src/configured_bignumber.ts
@@ -0,0 +1,9 @@
+import { BigNumber } from 'bignumber.js';
+
+// By default BigNumber's `toString` method converts to exponential notation if the value has
+// more then 20 digits. We want to avoid this behavior, so we set EXPONENTIAL_AT to a high number
+BigNumber.config({
+ EXPONENTIAL_AT: 1000,
+});
+
+export { BigNumber };
diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts
index a61f04ad2..2768e49ab 100644
--- a/packages/utils/src/index.ts
+++ b/packages/utils/src/index.ts
@@ -1 +1,5 @@
-export {promisify} from './promisify';
+export { promisify } from './promisify';
+export { addressUtils } from './address_utils';
+export { classUtils } from './class_utils';
+export { intervalUtils } from './interval_utils';
+export { BigNumber } from './configured_bignumber';
diff --git a/packages/utils/src/interval_utils.ts b/packages/utils/src/interval_utils.ts
new file mode 100644
index 000000000..ebecc7015
--- /dev/null
+++ b/packages/utils/src/interval_utils.ts
@@ -0,0 +1,37 @@
+import * as _ from 'lodash';
+
+export const intervalUtils = {
+ setAsyncExcludingInterval(fn: () => Promise<void>, intervalMs: number, onError: (err: Error) => void) {
+ let locked = false;
+ const intervalId = setInterval(async () => {
+ if (locked) {
+ return;
+ } else {
+ locked = true;
+ try {
+ await fn();
+ } catch (err) {
+ onError(err);
+ }
+ locked = false;
+ }
+ }, intervalMs);
+ return intervalId;
+ },
+ clearAsyncExcludingInterval(intervalId: NodeJS.Timer): void {
+ clearInterval(intervalId);
+ },
+ setInterval(fn: () => void, intervalMs: number, onError: (err: Error) => void) {
+ const intervalId = setInterval(() => {
+ try {
+ fn();
+ } catch (err) {
+ onError(err);
+ }
+ }, intervalMs);
+ return intervalId;
+ },
+ clearInterval(intervalId: NodeJS.Timer): void {
+ clearInterval(intervalId);
+ },
+};
diff --git a/packages/utils/src/promisify.ts b/packages/utils/src/promisify.ts
index c114cf32f..29d626b61 100644
--- a/packages/utils/src/promisify.ts
+++ b/packages/utils/src/promisify.ts
@@ -5,16 +5,11 @@ import * as _ from 'lodash';
* Promisify provides a default callback of the form (error, result) and rejects when `error` is not null. You can also
* supply thisArg object as the second argument which will be passed to `apply`.
*/
-export function promisify<T>(
- originalFn: (
- ...args: any[],
- // HACK: This can't be properly typed without variadic kinds https://github.com/Microsoft/TypeScript/issues/5453
- ) => void,
- thisArg?: any,
-): (...callArgs: any[]) => Promise<T> {
+// HACK: This can't be properly typed without variadic kinds https://github.com/Microsoft/TypeScript/issues/5453
+export function promisify<T>(originalFn: (...args: any[]) => void, thisArg?: any): (...callArgs: any[]) => Promise<T> {
const promisifiedFunction = async (...callArgs: any[]): Promise<T> => {
return new Promise<T>((resolve, reject) => {
- const callback = (err: Error|null, data?: T) => {
+ const callback = (err: Error | null, data?: T) => {
_.isNull(err) ? resolve(data) : reject(err);
};
originalFn.apply(thisArg, [...callArgs, callback]);