import BigNumber from "bignumber.js"; import formatNumber, { IFormatNumberOptions } from "format-number"; import invariant from "tiny-invariant"; import { BigNumberString } from "../constants"; import { SerializedToken, Token } from "./Token"; export interface SerializedTokenAmount { _type: "TokenAmount"; token: SerializedToken; amount: BigNumberString; } class CurrencyAmount { public readonly token: Token; public readonly amount: BigNumber; public readonly scaledAmount: number; // amount _must_ be raw, i.e. in the native representation protected constructor(token: Token, amount: BigNumber) { this.amount = amount; this.token = token; this.scaledAmount = amount .dividedBy(new BigNumber("10").pow(token.decimals)) .toNumber(); } public get raw(): BigNumber { return this.amount; } public toSignificant( significantDigits = 6, format?: IFormatNumberOptions ): string { const formatFunction = formatNumber(format); return formatFunction( parseFloat(this.scaledAmount.toPrecision(significantDigits)) ); } public toFixed( decimalPlaces: number = this.token.decimals, format?: IFormatNumberOptions ): string { const formatFunction = formatNumber({ ...format, round: decimalPlaces, padRight: decimalPlaces, }); const result = formatFunction(this.scaledAmount); return result; } public toExact(format?: IFormatNumberOptions): string { const formatFunction = formatNumber(format); return formatFunction(this.scaledAmount); } } export class TokenAmount extends CurrencyAmount { public readonly token: Token; // amount _must_ be raw, i.e. in the native representation public constructor(token: Token, amount: BigNumber | string) { super(token, typeof amount === "string" ? new BigNumber(amount) : amount); this.token = token; } public add(other: TokenAmount): TokenAmount { invariant(this.token.equals(other.token), "TOKEN"); return new TokenAmount(this.token, this.amount.plus(other.amount)); } public subtract(other: TokenAmount): TokenAmount { invariant(this.token.equals(other.token), "TOKEN"); return new TokenAmount(this.token, this.amount.minus(other.amount)); } toJSON = () => ({ _type: "TokenAmount", amount: this.amount.toFixed(0), token: this.token.toJSON(), }); public static isSerializedTokenAmount = ( obj: Record ): obj is SerializedTokenAmount => obj?._type === "TokenAmount"; public static parseJson = (ta: SerializedTokenAmount) => new TokenAmount(Token.parseJson(ta.token), ta.amount); }