import { Result } from "@ethersproject/abi"; import { getAddress } from "@ethersproject/address"; import { parseUnits } from "@ethersproject/units"; import BigNumber from "bignumber.js"; import invariant from "tiny-invariant"; import warning from "tiny-warning"; import Web3 from "web3"; import { Token, TokenAmount } from "../Tokens"; import { Address, TimeFrame } from "../constants"; /** * * @param address string to check if an address is valid and checksummed * @returns checksummed address, or undefined if address is invalid */ export function validateAndParseAddress(address: string): string { try { const checksummedAddress = getAddress(address); warning(address === checksummedAddress, `${address} is not checksummed.`); return checksummedAddress; } catch (error) { invariant(false, `${address} is not a valid address.`); } } /** * * @param result Result object from multicall * @param i index of value within Result, default 0 * @returns string representation of ith value in Result */ export const convertResultToString = (result?: Result, i = 0) => result?.[i].toString(); /** * * @param result Result object from multicall * @param i index of value within Result, default 0 * @returns address of ith value in Result */ export const convertResultToAddress = (result?: Result, i = 0): Address => validateAndParseAddress(convertResultToString(result, i)); /** * * @param result Result object from multicall * @param i index of value within Result, default 0 * @returns BigNumber of ith value in Result */ export const convertResultToBigNumber = (result?: Result, i = 0): BigNumber => new BigNumber(convertResultToString(result, i)); /** * * @param result Result object from multicall * @param i index of value within Result, default 0 * @returns Number of ith value in Result */ export const convertResultToNumber = (result?: Result, i = 0) => parseInt(convertResultToString(result, i)); /** * * @param txnHash Hash of transaction waiting to be mined * @param web3 web3 object * @returns status of the transaction (true = success, false = revert) */ export async function waitForMinedTransaction(txnHash: string, web3: Web3) { let receipt = await web3.eth.getTransactionReceipt(txnHash); while (!receipt) { await new Promise((r) => setTimeout(r, 5000)); receipt = await web3.eth.getTransactionReceipt(txnHash); } return receipt.status; } /** * * Merges two sorted arrays. * * @param arr1 sorted array * @param arr2 sorted array * @param comparator how to compare entries in the arrays * @returns One array in sorted order */ export function mergeArrays( arr1: t[], arr2: t[], comparator: (t1: t, t2: t) => number ) { const merged: t[] = []; let i = 0; let j = 0; while (i < arr1.length && j < arr2.length) { const comparison = comparator(arr1[i], arr2[j]); if (comparison > 0) { merged.push(arr2[j++]); } else { merged.push(arr1[i++]); } } while (i < arr1.length) merged.push(arr1[i++]); while (j < arr2.length) merged.push(arr2[j++]); return merged; } export const applySlippage = (amount: BigNumber, slippage: number) => amount.minus(amount.div(slippage)); /** * * @param value string value to parse into a token value, this is the decimal adjusted value (i.e. in eth, not wei) * @param currency the corresponding token for the token amount * @returns TokenAmount object with the value parsed, or undefined if unable to parse */ export function tryParseTokenAmount( value?: string, currency?: Token ): TokenAmount | undefined { if (!value || !currency) { return undefined; } try { const typedValueParsed = parseUnits(value, currency.decimals).toString(); if (typedValueParsed !== "0") { return new TokenAmount( currency as Token, new BigNumber(typedValueParsed) ); } } catch (error) { // should fail if the user specifies too many decimal places of precision (or maybe exceed max uint?) console.debug(`Failed to parse input amount: "${value}"`, error); } // necessary for all paths to return a value return undefined; } type T = "hour" | "day" | "week" | "month" | "year"; type Time = T | `${T}s`; /** * * @param timeframe * @returns Unix seconds of given timeframe. If parsing error, will return current timestamp in Unix seconds. */ export function convertTimeframeToUnixSeconds(timeframe: TimeFrame) { let [magnitude, unit] = timeframe.split(" ") as [ number | Time, Time | undefined ]; if (!unit) { unit = magnitude as Time; magnitude = 1; } switch (unit) { case "days": case "day": return 60 * 60 * 24 * +magnitude; case "hours": case "hour": return 60 * 60 * +magnitude; case "weeks": case "week": return 60 * 60 * 24 * 7 * +magnitude; case "months": case "month": return 60 * 60 * 24 * 30 * +magnitude; default: return Math.floor(Date.now() / 1000); } } export * from "./multicall";