UNPKG

@drift-labs/sdk

Version:
122 lines (102 loc) 3.42 kB
import { BN } from '@coral-xyz/anchor'; import { ONE, ZERO } from '../constants/numericConstants'; export function clampBN(x: BN, min: BN, max: BN): BN { return BN.max(min, BN.min(x, max)); } export const squareRootBN = (n: BN): BN => { if (n.lt(new BN(0))) { throw new Error('Sqrt only works on non-negtiave inputs'); } if (n.lt(new BN(2))) { return n; } const smallCand = squareRootBN(n.shrn(2)).shln(1); const largeCand = smallCand.add(new BN(1)); if (largeCand.mul(largeCand).gt(n)) { return smallCand; } else { return largeCand; } }; export const divCeil = (a: BN, b: BN): BN => { const quotient = a.div(b); const remainder = a.mod(b); if (remainder.gt(ZERO)) { return quotient.add(ONE); } else { return quotient; } }; export const sigNum = (x: BN): BN => { return x.isNeg() ? new BN(-1) : new BN(1); }; /** * calculates the time remaining until the next update based on a rounded, "on-the-hour" update schedule * this schedule is used for Perpetual Funding Rate and Revenue -> Insurance Updates * @param now: current blockchain unix timestamp * @param lastUpdateTs: the unix timestamp of the last update * @param updatePeriod: desired interval between updates (in seconds) * @returns: timeRemainingUntilUpdate (in seconds) */ export function timeRemainingUntilUpdate( now: BN, lastUpdateTs: BN, updatePeriod: BN ): BN { const timeSinceLastUpdate = now.sub(lastUpdateTs); // round next update time to be available on the hour let nextUpdateWait = updatePeriod; if (updatePeriod.gt(new BN(1))) { const lastUpdateDelay = lastUpdateTs.umod(updatePeriod); if (!lastUpdateDelay.isZero()) { const maxDelayForNextPeriod = updatePeriod.div(new BN(3)); const twoFundingPeriods = updatePeriod.mul(new BN(2)); if (lastUpdateDelay.gt(maxDelayForNextPeriod)) { // too late for on the hour next period, delay to following period nextUpdateWait = twoFundingPeriods.sub(lastUpdateDelay); } else { // allow update on the hour nextUpdateWait = updatePeriod.sub(lastUpdateDelay); } if (nextUpdateWait.gt(twoFundingPeriods)) { nextUpdateWait = nextUpdateWait.sub(updatePeriod); } } } const timeRemainingUntilUpdate = nextUpdateWait .sub(timeSinceLastUpdate) .isNeg() ? ZERO : nextUpdateWait.sub(timeSinceLastUpdate); return timeRemainingUntilUpdate; } export const checkSameDate = (dateString1: string, dateString2: string) => { const date1 = new Date(dateString1); const date2 = new Date(dateString2); const isSameDate = date1.getDate() === date2.getDate() && date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear(); return isSameDate; }; export function isBNSafe(number: number): boolean { return number <= 0x1fffffffffffff; } /** * Converts a number to BN makes sure the number is safe to convert to BN (that it does not overflow number after multiplying by precision) * @param number the number to convert to BN * @param precision the BN precision to use (i.e. QUOTE_PRECISION and BASE_PRECISION from drift sdk) */ export function numberToSafeBN(number: number, precision: BN): BN { // check if number has decimals const candidate = number * precision.toNumber(); if (isBNSafe(candidate)) { return new BN(candidate); } else { if (number % 1 === 0) { return new BN(number.toString()).mul(precision); } else { return new BN(number).mul(precision); } } }