UNPKG

@powrldgr/raydium-sdk-v2

Version:

An SDK for building applications on top of Raydium.

247 lines (210 loc) 7.06 kB
import _Big from "big.js"; import BN from "bn.js"; import { BigNumberish, BN_TEN } from "../common/bignumber"; import { createLogger, Logger } from "../common/logger"; import { parseBigNumberish, Rounding } from "../common"; import { Currency } from "./currency"; import toFormat, { WrappedBig } from "./formatter"; import { Fraction } from "./fraction"; import { Token } from "./token"; const logger = createLogger("Raydium_amount"); const Big = toFormat(_Big); type Big = WrappedBig; export function splitNumber(num: string, decimals: number): [string, string] { let integral = "0"; let fractional = "0"; if (num.includes(".")) { const splited = num.split("."); if (splited.length === 2) { [integral, fractional] = splited; fractional = fractional.padEnd(decimals, "0"); } else { logger.logWithError(`invalid number string, num: ${num}`); } } else { integral = num; } // fix decimals is 0 return [integral, fractional.slice(0, decimals) || fractional]; } export class TokenAmount extends Fraction { public readonly token: Token; protected logger: Logger; public constructor(token: Token, amount: BigNumberish, isRaw = true, name?: string) { let parsedAmount = new BN(0); const multiplier = BN_TEN.pow(new BN(token.decimals)); if (isRaw) { parsedAmount = parseBigNumberish(amount); } else { let integralAmount = new BN(0); let fractionalAmount = new BN(0); // parse fractional string if (typeof amount === "string" || typeof amount === "number" || typeof amount === "bigint") { const [integral, fractional] = splitNumber(amount.toString(), token.decimals); integralAmount = parseBigNumberish(integral); fractionalAmount = parseBigNumberish(fractional); } integralAmount = integralAmount.mul(multiplier); parsedAmount = integralAmount.add(fractionalAmount); } super(parsedAmount, multiplier); this.logger = createLogger(name || "TokenAmount"); this.token = token; } public get raw(): BN { return this.numerator; } public isZero(): boolean { return this.raw.isZero(); } public gt(other: TokenAmount): boolean { if (!this.token.equals(other.token)) this.logger.logWithError("gt token not equals"); return this.raw.gt(other.raw); } /** * a less than b */ public lt(other: TokenAmount): boolean { if (!this.token.equals(other.token)) this.logger.logWithError("lt token not equals"); return this.raw.lt(other.raw); } public add(other: TokenAmount): TokenAmount { if (!this.token.equals(other.token)) this.logger.logWithError("add token not equals"); return new TokenAmount(this.token, this.raw.add(other.raw)); } public subtract(other: TokenAmount): TokenAmount { if (!this.token.equals(other.token)) this.logger.logWithError("sub token not equals"); return new TokenAmount(this.token, this.raw.sub(other.raw)); } public toSignificant( significantDigits = this.token.decimals, format?: object, rounding: Rounding = Rounding.ROUND_DOWN, ): string { return super.toSignificant(significantDigits, format, rounding); } /** * To fixed * * @example * ``` * 1 -> 1.000000000 * 1.234 -> 1.234000000 * 1.123456789876543 -> 1.123456789 * ``` */ public toFixed( decimalPlaces = this.token.decimals, format?: object, rounding: Rounding = Rounding.ROUND_DOWN, ): string { if (decimalPlaces > this.token.decimals) this.logger.logWithError("decimals overflow"); return super.toFixed(decimalPlaces, format, rounding); } /** * To exact * * @example * ``` * 1 -> 1 * 1.234 -> 1.234 * 1.123456789876543 -> 1.123456789 * ``` */ public toExact(format: object = { groupSeparator: "" }): string { Big.DP = this.token.decimals; return new Big(this.numerator.toString()).div(this.denominator.toString()).toFormat(format); } } export class CurrencyAmount extends Fraction { public readonly currency: Currency; protected logger: Logger; public constructor(currency: Currency, amount: BigNumberish, isRaw = true, name?: string) { let parsedAmount = new BN(0); const multiplier = BN_TEN.pow(new BN(currency.decimals)); if (isRaw) { parsedAmount = parseBigNumberish(amount); } else { let integralAmount = new BN(0); let fractionalAmount = new BN(0); // parse fractional string if (typeof amount === "string" || typeof amount === "number" || typeof amount === "bigint") { const [integral, fractional] = splitNumber(amount.toString(), currency.decimals); integralAmount = parseBigNumberish(integral); fractionalAmount = parseBigNumberish(fractional); } integralAmount = integralAmount.mul(multiplier); parsedAmount = integralAmount.add(fractionalAmount); } super(parsedAmount, multiplier); this.logger = createLogger(name || "TokenAmount"); this.currency = currency; } public get raw(): BN { return this.numerator; } public isZero(): boolean { return this.raw.isZero(); } /** * a greater than b */ public gt(other: CurrencyAmount): boolean { if (!this.currency.equals(other.currency)) this.logger.logWithError("gt currency not equals"); return this.raw.gt(other.raw); } /** * a less than b */ public lt(other: CurrencyAmount): boolean { if (!this.currency.equals(other.currency)) this.logger.logWithError("lt currency not equals"); return this.raw.lt(other.raw); } public add(other: CurrencyAmount): CurrencyAmount { if (!this.currency.equals(other.currency)) this.logger.logWithError("add currency not equals"); return new CurrencyAmount(this.currency, this.raw.add(other.raw)); } public sub(other: CurrencyAmount): CurrencyAmount { if (!this.currency.equals(other.currency)) this.logger.logWithError("sub currency not equals"); return new CurrencyAmount(this.currency, this.raw.sub(other.raw)); } public toSignificant( significantDigits = this.currency.decimals, format?: object, rounding: Rounding = Rounding.ROUND_DOWN, ): string { return super.toSignificant(significantDigits, format, rounding); } /** * To fixed * * @example * ``` * 1 -> 1.000000000 * 1.234 -> 1.234000000 * 1.123456789876543 -> 1.123456789 * ``` */ public toFixed( decimalPlaces = this.currency.decimals, format?: object, rounding: Rounding = Rounding.ROUND_DOWN, ): string { if (decimalPlaces > this.currency.decimals) this.logger.logWithError("decimals overflow"); return super.toFixed(decimalPlaces, format, rounding); } /** * To exact * * @example * ``` * 1 -> 1 * 1.234 -> 1.234 * 1.123456789876543 -> 1.123456789 * ``` */ public toExact(format: object = { groupSeparator: "" }): string { Big.DP = this.currency.decimals; return new Big(this.numerator.toString()).div(this.denominator.toString()).toFormat(format); } }