aboutsummaryrefslogtreecommitdiffstats
path: root/packages/website/ts/utils/utils.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/website/ts/utils/utils.ts')
-rw-r--r--packages/website/ts/utils/utils.ts483
1 files changed, 0 insertions, 483 deletions
diff --git a/packages/website/ts/utils/utils.ts b/packages/website/ts/utils/utils.ts
deleted file mode 100644
index e84f9d0cc..000000000
--- a/packages/website/ts/utils/utils.ts
+++ /dev/null
@@ -1,483 +0,0 @@
-import { ContractWrappersError } from '@0x/contract-wrappers';
-import { assetDataUtils, OrderError } from '@0x/order-utils';
-import { constants as sharedConstants, Networks } from '@0x/react-shared';
-import { ExchangeContractErrs } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as bowser from 'bowser';
-import deepEqual from 'deep-equal';
-import * as _ from 'lodash';
-import * as moment from 'moment';
-import * as numeral from 'numeral';
-
-import { Provider } from 'ethereum-types';
-import {
- AccountState,
- BlockchainCallErrs,
- BrowserType,
- Environments,
- OperatingSystemType,
- PortalOrder,
- Providers,
- ProviderType,
- ScreenWidths,
- Side,
- SideToAssetToken,
- Token,
- TokenByAddress,
- TokenState,
-} from 'ts/types';
-import { configs } from 'ts/utils/configs';
-import { constants } from 'ts/utils/constants';
-import * as u2f from 'ts/vendor/u2f_api';
-
-export const utils = {
- assert(condition: boolean, message: string): void {
- if (!condition) {
- throw new Error(message);
- }
- },
- isNumeric(n: string): boolean {
- return !isNaN(parseFloat(n)) && isFinite(Number(n));
- },
- // This default unix timestamp is used for orders where the user does not specify an expiry date.
- // It is a fixed constant so that both the redux store's INITIAL_STATE and components can check for
- // whether a user has set an expiry date or not. It is set unrealistically high so as not to collide
- // with actual values a user would select.
- initialOrderExpiryUnixTimestampSec(): BigNumber {
- const m = moment('2050-01-01');
- return new BigNumber(m.unix());
- },
- convertToUnixTimestampSeconds(date: moment.Moment, time?: moment.Moment): BigNumber {
- const finalMoment = date;
- if (!_.isUndefined(time)) {
- finalMoment.hours(time.hours());
- finalMoment.minutes(time.minutes());
- }
- return new BigNumber(finalMoment.unix());
- },
- convertToMomentFromUnixTimestamp(unixTimestampSec: BigNumber): moment.Moment {
- return moment.unix(unixTimestampSec.toNumber());
- },
- convertToReadableDateTimeFromUnixTimestamp(unixTimestampSec: BigNumber): string {
- const m = utils.convertToMomentFromUnixTimestamp(unixTimestampSec);
- const formattedDate: string = m.format('h:MMa MMMM D YYYY');
- return formattedDate;
- },
- generateOrder(
- exchangeAddress: string,
- sideToAssetToken: SideToAssetToken,
- expirationTimeSeconds: BigNumber,
- orderTakerAddress: string,
- orderMakerAddress: string,
- makerFee: BigNumber,
- takerFee: BigNumber,
- feeRecipientAddress: string,
- signature: string,
- tokenByAddress: TokenByAddress,
- orderSalt: BigNumber,
- ): PortalOrder {
- const makerToken = tokenByAddress[sideToAssetToken[Side.Deposit].address];
- const takerToken = tokenByAddress[sideToAssetToken[Side.Receive].address];
- const order = {
- signedOrder: {
- senderAddress: constants.NULL_ADDRESS,
- makerAddress: orderMakerAddress,
- takerAddress: orderTakerAddress,
- makerFee,
- takerFee,
- makerAssetAmount: sideToAssetToken[Side.Deposit].amount,
- takerAssetAmount: sideToAssetToken[Side.Receive].amount,
- makerAssetData: assetDataUtils.encodeERC20AssetData(makerToken.address),
- takerAssetData: assetDataUtils.encodeERC20AssetData(takerToken.address),
- expirationTimeSeconds,
- feeRecipientAddress,
- salt: orderSalt,
- signature,
- exchangeAddress,
- },
- metadata: {
- makerToken: {
- name: makerToken.name,
- symbol: makerToken.symbol,
- decimals: makerToken.decimals,
- },
- takerToken: {
- name: takerToken.name,
- symbol: takerToken.symbol,
- decimals: takerToken.decimals,
- },
- },
- };
- return order;
- },
- async sleepAsync(ms: number): Promise<NodeJS.Timer> {
- return new Promise<NodeJS.Timer>(resolve => setTimeout(resolve, ms));
- },
- deepEqual(actual: any, expected: any, opts?: { strict: boolean }): boolean {
- return deepEqual(actual, expected, opts);
- },
- getColSize(items: number): number {
- const bassCssGridSize = 12; // Source: http://basscss.com/#basscss-grid
- const colSize = bassCssGridSize / items;
- if (!_.isInteger(colSize)) {
- throw new Error(`Number of cols must be divisible by ${bassCssGridSize}`);
- }
- return colSize;
- },
- getScreenWidth(): ScreenWidths {
- const documentEl = document.documentElement;
- const body = document.getElementsByTagName('body')[0];
- const widthInPx = window.innerWidth || documentEl.clientWidth || body.clientWidth;
- const bodyStyles: any = window.getComputedStyle(document.querySelector('body'));
- const widthInEm = widthInPx / parseFloat(bodyStyles['font-size']);
-
- // This logic mirrors the CSS media queries in BassCSS for the `lg-`, `md-` and `sm-` CSS
- // class prefixes. Do not edit these.
- if (widthInEm > ScreenWidths.Lg) {
- return ScreenWidths.Lg;
- } else if (widthInEm > ScreenWidths.Md) {
- return ScreenWidths.Md;
- } else {
- return ScreenWidths.Sm;
- }
- },
- async isU2FSupportedAsync(): Promise<boolean> {
- const w = window as any;
- return new Promise((resolve: (isSupported: boolean) => void) => {
- if (w.u2f && !w.u2f.getApiVersion) {
- // u2f object was found (Firefox with extension)
- resolve(true);
- } else {
- // u2f object was not found. Using Google polyfill
- // HACK: u2f.getApiVersion will simply not return a version if the
- // U2F call fails for any reason. Because of this, we set a hard 3sec
- // timeout to the request on our end.
- const getApiVersionTimeoutMs = 3000;
- const intervalId = setTimeout(() => {
- resolve(false);
- }, getApiVersionTimeoutMs);
- u2f.getApiVersion((_version: number) => {
- clearTimeout(intervalId);
- resolve(true);
- });
- }
- });
- },
- // This checks the error message returned from an injected Web3 instance on the page
- // after a user was prompted to sign a message or send a transaction and decided to
- // reject the request.
- didUserDenyWeb3Request(errMsg: string): boolean {
- const metamaskDenialErrMsg = 'User denied';
- const paritySignerDenialErrMsg = 'Request has been rejected';
- const ledgerDenialErrMsg = 'Invalid status 6985';
- const isUserDeniedErrMsg =
- _.includes(errMsg, metamaskDenialErrMsg) ||
- _.includes(errMsg, paritySignerDenialErrMsg) ||
- _.includes(errMsg, ledgerDenialErrMsg);
- return isUserDeniedErrMsg;
- },
- getAddressBeginAndEnd(address: string): string {
- const truncatedAddress = `${address.substring(0, 6)}...${address.substr(-4)}`; // 0x3d5a...b287
- return truncatedAddress;
- },
- getReadableAccountState(accountState: AccountState, userAddress: string): string {
- switch (accountState) {
- case AccountState.Loading:
- return 'Loading...';
- case AccountState.Ready:
- return utils.getAddressBeginAndEnd(userAddress);
- case AccountState.Locked:
- return 'Please Unlock';
- case AccountState.Disconnected:
- return 'Connect a Wallet';
- default:
- return '';
- }
- },
- getAccountState(
- isBlockchainReady: boolean,
- providerType: ProviderType,
- injectedProviderName: string,
- userAddress?: string,
- ): AccountState {
- const isAddressAvailable = !_.isUndefined(userAddress) && !_.isEmpty(userAddress);
- const isExternallyInjectedProvider = utils.isExternallyInjected(providerType, injectedProviderName);
- if (!isBlockchainReady) {
- return AccountState.Loading;
- } else if (isAddressAvailable) {
- return AccountState.Ready;
- // tslint:disable-next-line: prefer-conditional-expression
- } else if (isExternallyInjectedProvider) {
- return AccountState.Locked;
- } else {
- return AccountState.Disconnected;
- }
- },
- hasUniqueNameAndSymbol(tokens: Token[], token: Token): boolean {
- if (token.isRegistered) {
- return true; // Since it's registered, it is the canonical token
- }
- const registeredTokens = _.filter(tokens, t => t.isRegistered);
- const tokenWithSameNameIfExists = _.find(registeredTokens, {
- name: token.name,
- });
- const isUniqueName = _.isUndefined(tokenWithSameNameIfExists);
- const tokenWithSameSymbolIfExists = _.find(registeredTokens, {
- name: token.symbol,
- });
- const isUniqueSymbol = _.isUndefined(tokenWithSameSymbolIfExists);
- return isUniqueName && isUniqueSymbol;
- },
- zeroExErrToHumanReadableErrMsg(error: ContractWrappersError | ExchangeContractErrs, takerAddress: string): string {
- const ContractWrappersErrorToHumanReadableError: { [error: string]: string } = {
- [BlockchainCallErrs.UserHasNoAssociatedAddresses]: 'User has no addresses available',
- [OrderError.InvalidSignature]: 'Order signature is not valid',
- [ContractWrappersError.ContractNotDeployedOnNetwork]: 'Contract is not deployed on the detected network',
- [ContractWrappersError.InvalidJump]: 'Invalid jump occured while executing the transaction',
- [ContractWrappersError.OutOfGas]: 'Transaction ran out of gas',
- };
- const exchangeContractErrorToHumanReadableError: {
- [error: string]: string;
- } = {
- [ExchangeContractErrs.OrderFillExpired]: 'This order has expired',
- [ExchangeContractErrs.OrderCancelExpired]: 'This order has expired',
- [ExchangeContractErrs.OrderCancelled]: 'This order has been cancelled',
- [ExchangeContractErrs.OrderFillAmountZero]: "Order fill amount can't be 0",
- [ExchangeContractErrs.OrderRemainingFillAmountZero]: 'This order has already been completely filled',
- [ExchangeContractErrs.OrderFillRoundingError]:
- 'Rounding error will occur when filling this order. Please try filling a different amount.',
- [ExchangeContractErrs.InsufficientTakerBalance]:
- 'Taker no longer has a sufficient balance to complete this order',
- [ExchangeContractErrs.InsufficientTakerAllowance]:
- 'Taker no longer has a sufficient allowance to complete this order',
- [ExchangeContractErrs.InsufficientMakerBalance]:
- 'Maker no longer has a sufficient balance to complete this order',
- [ExchangeContractErrs.InsufficientMakerAllowance]:
- 'Maker no longer has a sufficient allowance to complete this order',
- [ExchangeContractErrs.InsufficientTakerFeeBalance]: 'Taker no longer has a sufficient balance to pay fees',
- [ExchangeContractErrs.InsufficientTakerFeeAllowance]:
- 'Taker no longer has a sufficient allowance to pay fees',
- [ExchangeContractErrs.InsufficientMakerFeeBalance]: 'Maker no longer has a sufficient balance to pay fees',
- [ExchangeContractErrs.InsufficientMakerFeeAllowance]:
- 'Maker no longer has a sufficient allowance to pay fees',
- [ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker]: `This order can only be filled by ${takerAddress}`,
- [ExchangeContractErrs.InsufficientRemainingFillAmount]: 'Insufficient remaining fill amount',
- };
- const humanReadableErrorMsg =
- exchangeContractErrorToHumanReadableError[error] || ContractWrappersErrorToHumanReadableError[error];
- return humanReadableErrorMsg;
- },
- isParityNode(nodeVersion: string): boolean {
- return _.includes(nodeVersion, 'Parity');
- },
- isTestRpc(nodeVersion: string): boolean {
- return _.includes(nodeVersion, 'TestRPC');
- },
- isTestNetwork(networkId: number): boolean {
- const isTestNetwork = _.includes(
- [
- sharedConstants.NETWORK_ID_BY_NAME[Networks.Kovan],
- sharedConstants.NETWORK_ID_BY_NAME[Networks.Rinkeby],
- sharedConstants.NETWORK_ID_BY_NAME[Networks.Ropsten],
- ],
- networkId,
- );
- return isTestNetwork;
- },
- getCurrentBaseUrl(): string {
- const port = window.location.port;
- const hasPort = !_.isUndefined(port);
- const baseUrl = `https://${window.location.hostname}${hasPort ? `:${port}` : ''}`;
- return baseUrl;
- },
- onPageLoadPromise: new Promise<void>((resolve, _reject) => {
- if (document.readyState === 'complete') {
- resolve();
- return;
- }
- window.onload = () => resolve();
- }),
- getProviderType(provider: Provider): Providers | string {
- const constructorName = provider.constructor.name;
- let parsedProviderName = constructorName;
- // https://ethereum.stackexchange.com/questions/24266/elegant-way-to-detect-current-provider-int-web3-js
- switch (constructorName) {
- case 'EthereumProvider':
- parsedProviderName = Providers.Mist;
- break;
-
- default:
- parsedProviderName = constructorName;
- break;
- }
- if ((provider as any).isParity) {
- parsedProviderName = Providers.Parity;
- } else if ((provider as any).isMetaMask) {
- parsedProviderName = Providers.Metamask;
- } else if (!_.isUndefined(_.get(window, 'SOFA'))) {
- parsedProviderName = Providers.CoinbaseWallet;
- } else if (!_.isUndefined(_.get(window, '__CIPHER__'))) {
- parsedProviderName = Providers.Cipher;
- }
- return parsedProviderName;
- },
- getBackendBaseUrl(): string {
- return utils.isDogfood() ? configs.BACKEND_BASE_STAGING_URL : configs.BACKEND_BASE_PROD_URL;
- },
- isDevelopment(): boolean {
- return _.includes(configs.DOMAINS_DEVELOPMENT, window.location.host);
- },
- isStaging(): boolean {
- return _.includes(window.location.href, configs.DOMAIN_STAGING);
- },
- isExternallyInjected(providerType: ProviderType, injectedProviderName: string): boolean {
- return providerType === ProviderType.Injected && injectedProviderName !== constants.PROVIDER_NAME_PUBLIC;
- },
- isDogfood(): boolean {
- return _.includes(window.location.href, configs.DOMAIN_DOGFOOD);
- },
- isProduction(): boolean {
- return _.includes(window.location.href, configs.DOMAIN_PRODUCTION);
- },
- getEnvironment(): Environments {
- if (utils.isDogfood()) {
- return Environments.Dogfood;
- }
- if (utils.isDevelopment()) {
- return Environments.Development;
- }
- if (utils.isStaging()) {
- return Environments.Staging;
- }
- if (utils.isProduction()) {
- return Environments.Production;
- }
- return Environments.Unknown;
- },
- getEthToken(tokenByAddress: TokenByAddress): Token {
- return utils.getTokenBySymbol(constants.ETHER_TOKEN_SYMBOL, tokenByAddress);
- },
- getZrxToken(tokenByAddress: TokenByAddress): Token {
- return utils.getTokenBySymbol(constants.ZRX_TOKEN_SYMBOL, tokenByAddress);
- },
- getTokenBySymbol(symbol: string, tokenByAddress: TokenByAddress): Token {
- const tokens = _.values(tokenByAddress);
- const token = _.find(tokens, { symbol });
- return token;
- },
- getTrackedTokens(tokenByAddress: TokenByAddress): Token[] {
- const allTokens = _.values(tokenByAddress);
- const trackedTokens = _.filter(allTokens, t => utils.isTokenTracked(t));
- return trackedTokens;
- },
- getFormattedAmountFromToken(token: Token, tokenState: TokenState): string {
- return utils.getFormattedAmount(tokenState.balance, token.decimals);
- },
- format(value: BigNumber, format: string): string {
- const formattedAmount = numeral(value).format(format);
- if (_.isNaN(formattedAmount)) {
- // https://github.com/adamwdraper/Numeral-js/issues/596
- return numeral(new BigNumber(0)).format(format);
- }
- return formattedAmount;
- },
- getFormattedAmount(amount: BigNumber, decimals: number): string {
- const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals);
- // if the unit amount is less than 1, show the natural number of decimal places with a max of 4
- // if the unit amount is greater than or equal to 1, show only 2 decimal places
- const lessThanOnePrecision = Math.min(constants.TOKEN_AMOUNT_DISPLAY_PRECISION, unitAmount.decimalPlaces());
- const greaterThanOnePrecision = 2;
- const precision = unitAmount.lt(1) ? lessThanOnePrecision : greaterThanOnePrecision;
- const format = `0,0.${_.repeat('0', precision)}`;
- return utils.format(unitAmount, format);
- },
- getUsdValueFormattedAmount(amount: BigNumber, decimals: number, price: BigNumber): string {
- const unitAmount = Web3Wrapper.toUnitAmount(amount, decimals);
- const value = unitAmount.multipliedBy(price);
- return utils.format(value, constants.NUMERAL_USD_FORMAT);
- },
- openUrl(url: string): void {
- window.open(url, '_blank');
- },
- isMobileWidth(screenWidth: ScreenWidths): boolean {
- return screenWidth === ScreenWidths.Sm;
- },
- isMobileOperatingSystem(): boolean {
- return bowser.mobile;
- },
- getBrowserType(): BrowserType {
- if (bowser.chrome) {
- return BrowserType.Chrome;
- } else if (bowser.firefox) {
- return BrowserType.Firefox;
- } else if (bowser.opera) {
- return BrowserType.Opera;
- } else if (bowser.msedge) {
- return BrowserType.Edge;
- } else if (bowser.safari) {
- return BrowserType.Safari;
- } else {
- return BrowserType.Other;
- }
- },
- getOperatingSystem(): OperatingSystemType {
- if (bowser.android) {
- return OperatingSystemType.Android;
- } else if (bowser.ios) {
- return OperatingSystemType.iOS;
- } else if (bowser.mac) {
- return OperatingSystemType.Mac;
- } else if (bowser.windows) {
- return OperatingSystemType.Windows;
- } else if (bowser.windowsphone) {
- return OperatingSystemType.WindowsPhone;
- } else if (bowser.linux) {
- return OperatingSystemType.Linux;
- } else {
- return OperatingSystemType.Other;
- }
- },
- isTokenTracked(token: Token): boolean {
- return !_.isUndefined(token.trackedTimestamp);
- },
- // Returns a [downloadLink, isOnMobile] tuple.
- getBestWalletDownloadLinkAndIsMobile(): [string, boolean] {
- const browserType = utils.getBrowserType();
- const isOnMobile = utils.isMobileOperatingSystem();
- const operatingSystem = utils.getOperatingSystem();
- let downloadLink;
- if (isOnMobile) {
- switch (operatingSystem) {
- case OperatingSystemType.Android:
- downloadLink = constants.URL_COINBASE_WALLET_ANDROID_APP_STORE;
- break;
- case OperatingSystemType.iOS:
- downloadLink = constants.URL_COINBASE_WALLET_IOS_APP_STORE;
- break;
- default:
- // Coinbase wallet is only supported on these mobile OSes - just default to iOS
- downloadLink = constants.URL_COINBASE_WALLET_IOS_APP_STORE;
- }
- } else {
- switch (browserType) {
- case BrowserType.Chrome:
- downloadLink = constants.URL_METAMASK_CHROME_STORE;
- break;
- case BrowserType.Firefox:
- downloadLink = constants.URL_METAMASK_FIREFOX_STORE;
- break;
- case BrowserType.Opera:
- downloadLink = constants.URL_METAMASK_OPERA_STORE;
- break;
- default:
- downloadLink = constants.URL_METAMASK_HOMEPAGE;
- }
- }
- return [downloadLink, isOnMobile];
- },
- getTokenIconUrl(symbol: string): string {
- const result = `/images/token_icons/${symbol}.png`;
- return result;
- },
-};