date-fns#getUnixTime TypeScript Examples

The following examples show how to use date-fns#getUnixTime. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: hooks.ts    From glide-frontend with GNU General Public License v3.0 6 votes vote down vote up
useTokenPriceData = (
  address: string,
  interval: number,
  timeWindow: Duration,
): PriceChartEntry[] | undefined => {
  const dispatch = useDispatch<AppDispatch>()
  const token = useSelector((state: AppState) => state.info.tokens.byAddress[address])
  const priceData = token.priceData[interval]
  const [error, setError] = useState(false)

  // construct timestamps and check if we need to fetch more data
  const oldestTimestampFetched = token.priceData.oldestFetchedTimestamp
  const utcCurrentTime = getUnixTime(new Date()) * 1000
  const startTimestamp = getUnixTime(startOfHour(sub(utcCurrentTime, timeWindow)))

  useEffect(() => {
    const fetch = async () => {
      const { data, error: fetchingError } = await fetchTokenPriceData(address, interval, startTimestamp)
      if (data) {
        dispatch(
          updateTokenPriceData({
            tokenAddress: address,
            secondsInterval: interval,
            priceData: data,
            oldestFetchedTimestamp: startTimestamp,
          }),
        )
      }
      if (fetchingError) {
        setError(true)
      }
    }
    if (!priceData && !error) {
      fetch()
    }
  }, [address, dispatch, error, interval, oldestTimestampFetched, priceData, startTimestamp, timeWindow])

  return priceData
}
Example #2
Source File: helper.ts    From ngx-gantt with MIT License 6 votes vote down vote up
export function randomItems(length: number, parent?: GanttItem, group?: string) {
    const items = [];
    for (let i = 0; i < length; i++) {
        const start = addDays(new Date(), random(-200, 200));
        const end = addDays(start, random(0, 100));
        items.push({
            id: `${parent?.id || group || ''}00000${i}`,
            title: `${parent?.title || 'Task'}-${i}`,
            start: getUnixTime(start),
            end: getUnixTime(end),
            group_id: group
        });
    }
    return items;
}
Example #3
Source File: QuestProgress.tsx    From mStable-apps with GNU Lesser General Public License v3.0 6 votes vote down vote up
QuestTimeRemaining: FC<{ expiry?: number }> = ({ expiry }) => {
  const expired = expiry && expiry > 0 && getUnixTime(Date.now()) > expiry
  return (
    <Container progressType={ProgressType.TimeRemaining} questType={QuestType.Seasonal}>
      <div>
        {typeof expiry !== 'number' ? (
          <ThemedSkeleton height={20} />
        ) : expired ? (
          <span>Expired</span>
        ) : (
          <Typist>
            Time remaining
            <span>{formatDistanceToNow(expiry * 1000)}</span>
          </Typist>
        )}
      </div>
    </Container>
  )
}
Example #4
Source File: 4-fix-ttl.ts    From office-booker with MIT License 6 votes vote down vote up
async function* getCorrectedTtls(mapper: DataMapper, model: { new (): any }) {
  for await (const booking of mapper.scan(model)) {
    if (timestampTooHigh(booking.ttl)) {
      const ttl = new Date(booking.ttl);
      booking.ttl = getUnixTime(ttl);
      yield booking;
    }
  }
}
Example #5
Source File: bookings.ts    From office-booker with MIT License 6 votes vote down vote up
createBooking = async (
  config: Config,
  booking: CreateBookingModel
): Promise<BookingsModel | undefined> => {
  const mapper = buildMapper(config);
  try {
    const created = await mapper.put(
      Object.assign(new BookingsModel(), booking, {
        ttl: getUnixTime(addDays(new Date(booking.date), config.dataRetentionDays)),
      }),
      {
        condition: new FunctionExpression('attribute_not_exists', new AttributePath('id')),
      }
    );
    return created;
  } catch (err) {
    if (err.code === 'ConditionalCheckFailedException') {
      return undefined;
    }
    throw err;
  }
}
Example #6
Source File: useBlockTimestampsDocument.ts    From mStable-apps with GNU Lesser General Public License v3.0 6 votes vote down vote up
useBlockTimestampsDocument = (dates: Date[]): DocumentNode =>
  useMemo(
    () => gql`query BlockTimestamps {
      ${dates
        .map(ts => {
          const unixTs = getUnixTime(ts)
          return `t${unixTs}: blocks(first: 1, orderBy: timestamp, orderDirection: asc, where: {timestamp_gt: ${unixTs}, timestamp_lt: ${
            unixTs + 60000
          } }) { number }`
        })
        .join('\n')}
  }`,
    [dates],
  )
Example #7
Source File: questsUpdater.ts    From mStable-apps with GNU Lesser General Public License v3.0 6 votes vote down vote up
QuestsUpdater = (): null => {
  const account = useAccount()
  const clients = useApolloClients()
  const addQuestNotification = useAddQuestNotification()

  // Update all quests when the user changes
  const [updateUserQuests] = useUpdateQuestsMutation({
    client: clients.questbook,
    onCompleted: data => {
      if (!data.updateQuests) return

      const nowUnix = getUnixTime(Date.now())

      data.updateQuests.forEach(({ title, objectives, userQuest }) => {
        if (userQuest?.completedAt && nowUnix - userQuest.completedAt < 30) {
          addQuestNotification(title)
        }

        ;(userQuest?.objectives ?? [])
          .filter(obj => obj.completedAt && nowUnix - obj.completedAt < 30)
          .forEach(obj => {
            const obj_ = objectives.find(_obj => _obj.id === obj.id)
            if (obj_) addQuestNotification(obj_.title, obj_.points)
          })
      })
    },
  })

  useEffect(() => {
    if (account) {
      updateUserQuests({ variables: { userId: account ?? '', hasUser: !!account } }).catch(error => {
        console.error(error)
      })
    }
  }, [updateUserQuests, account])

  return null
}
Example #8
Source File: date.ts    From ngx-gantt with MIT License 5 votes vote down vote up
getUnixTime(): number {
        return getUnixTime(this.value);
    }
Example #9
Source File: updateLPsAPR.ts    From glide-frontend with GNU General Public License v3.0 5 votes vote down vote up
getWeekAgoTimestamp = () => {
  const weekAgo = sub(new Date(), { weeks: 1 })
  return getUnixTime(weekAgo)
}
Example #10
Source File: infoQueryHelpers.ts    From vvs-ui with GNU General Public License v3.0 5 votes vote down vote up
getDeltaTimestamps = (): [number, number, number, number] => {
  const utcCurrentTime = getUnixTime(new Date()) * 1000
  const t24h = getUnixTime(startOfMinute(subDays(utcCurrentTime, 1)))
  const t48h = getUnixTime(startOfMinute(subDays(utcCurrentTime, 2)))
  const t7d = getUnixTime(startOfMinute(subWeeks(utcCurrentTime, 1)))
  const t14d = getUnixTime(startOfMinute(subWeeks(utcCurrentTime, 2)))
  return [t24h, t48h, t7d, t14d]
}
Example #11
Source File: helpers.ts    From vvs-ui with GNU General Public License v3.0 5 votes vote down vote up
fetchChartData = async (
  getEntityDayDatas: PoolOrTokenFetchFn | OverviewFetchFn,
  address?: string,
): Promise<{ data?: ChartEntry[]; error: boolean }> => {
  let chartEntries: ChartEntry[] = []
  let error = false
  let skip = 0
  let allFound = false

  while (!allFound) {
    // eslint-disable-next-line no-await-in-loop
    const { data, error: fetchError } = await getEntityDayDatas(skip, address)
    skip += 1000
    allFound = data.length < 1000
    error = fetchError
    if (data) {
      chartEntries = chartEntries.concat(data)
    }
  }

  if (error || chartEntries.length === 0) {
    return {
      error: true,
    }
  }

  const formattedDayDatas = chartEntries.reduce((accum: { [date: number]: ChartEntry }, dayData) => {
    // At this stage we track unix day ordinal for each data point to check for empty days later
    const dayOrdinal = parseInt((dayData.date / ONE_DAY_UNIX).toFixed(0))
    return {
      [dayOrdinal]: dayData,
      ...accum,
    }
  }, {})

  const availableDays = Object.keys(formattedDayDatas).map((dayOrdinal) => parseInt(dayOrdinal, 10))

  const firstAvailableDayData = formattedDayDatas[availableDays[0]]
  // fill in empty days ( there will be no day datas if no trades made that day )
  let timestamp = firstAvailableDayData?.date ?? VVS_FINANCE_START
  let latestLiquidityUSD = firstAvailableDayData?.liquidityUSD ?? 0
  const endTimestamp = getUnixTime(new Date())
  while (timestamp < endTimestamp - ONE_DAY_UNIX) {
    timestamp += ONE_DAY_UNIX
    const dayOrdinal = parseInt((timestamp / ONE_DAY_UNIX).toFixed(0), 10)
    if (!Object.keys(formattedDayDatas).includes(dayOrdinal.toString())) {
      formattedDayDatas[dayOrdinal] = {
        date: timestamp,
        volumeUSD: 0,
        liquidityUSD: latestLiquidityUSD,
      }
    } else {
      latestLiquidityUSD = formattedDayDatas[dayOrdinal].liquidityUSD
    }
  }

  return {
    data: Object.values(formattedDayDatas),
    error: false,
  }
}
Example #12
Source File: updateLPsAPR.ts    From vvs-ui with GNU General Public License v3.0 5 votes vote down vote up
getWeekAgoTimestamp = () => {
  const weekAgo = sub(new Date(), { weeks: 1 })
  return getUnixTime(weekAgo)
}
Example #13
Source File: userBookings.ts    From office-booker with MIT License 5 votes vote down vote up
incrementUserBookingCount = async (
  config: Config,
  userEmail: string,
  userQuota: number,
  weekCommencing: string
) => {
  const mapper = buildMapper(config);

  try {
    await mapper.put(
      Object.assign(new UserBookingsModel(), {
        email: userEmail,
        weekCommencing,
        bookingCount: 0,
        ttl: getUnixTime(addDays(new Date(weekCommencing), config.dataRetentionDays + 7)),
      }),
      {
        condition: {
          type: 'And',
          conditions: [
            new FunctionExpression('attribute_not_exists', new AttributePath('email')),
            new FunctionExpression('attribute_not_exists', new AttributePath('date')),
          ],
        },
      }
    );
  } catch (err) {
    if (err.code !== 'ConditionalCheckFailedException') {
      throw err;
    }
  }

  const attributes = new ExpressionAttributes();
  const updateExpression = new UpdateExpression();
  updateExpression.set(
    'bookingCount',
    new MathematicalExpression(new AttributePath('bookingCount'), '+', 1)
  );

  const quotaValue = attributes.addValue(userQuota);
  const client = new DynamoDB(config.dynamoDB);
  try {
    await client
      .updateItem({
        Key: { email: { S: userEmail }, weekCommencing: { S: weekCommencing } },
        TableName: (config.dynamoDBTablePrefix || '') + userTableName,
        UpdateExpression: updateExpression.serialize(attributes),
        ExpressionAttributeNames: attributes.names,
        ExpressionAttributeValues: attributes.values,
        ConditionExpression: `bookingCount < ${quotaValue}`,
      })
      .promise();
  } catch (err) {
    if (err.code === 'ConditionalCheckFailedException') {
      return false;
    } else {
      throw err;
    }
  }

  return true;
}
Example #14
Source File: officeBookings.ts    From office-booker with MIT License 5 votes vote down vote up
incrementOfficeBookingCount = async (
  config: Config,
  office: OfficeQuota,
  date: string,
  includeParking: boolean
) => {
  const mapper = buildMapper(config);

  try {
    await mapper.put(
      Object.assign(new OfficeBookingModel(), {
        name: office.id,
        date,
        bookingCount: 0,
        parkingCount: 0,
        ttl: getUnixTime(addDays(new Date(date), config.dataRetentionDays)),
      }),
      {
        condition: {
          type: 'And',
          conditions: [
            new FunctionExpression('attribute_not_exists', new AttributePath('name')),
            new FunctionExpression('attribute_not_exists', new AttributePath('date')),
          ],
        },
      }
    );
  } catch (err) {
    if (err.code !== 'ConditionalCheckFailedException') {
      throw err;
    }
  }

  const attributes = new ExpressionAttributes();
  const updateExpression = new UpdateExpression();
  updateExpression.set(
    'bookingCount',
    new MathematicalExpression(new AttributePath('bookingCount'), '+', 1)
  );

  let parkingQuotaValue;

  if (includeParking) {
    updateExpression.set(
      'parkingCount',
      new MathematicalExpression(new AttributePath('parkingCount'), '+', 1)
    );
    parkingQuotaValue = attributes.addValue(office.parkingQuota);
  }

  const quotaValue = attributes.addValue(office.quota);
  const client = new DynamoDB(config.dynamoDB);
  try {
    const checkParkingQuota = includeParking ? `AND parkingCount < ${parkingQuotaValue}` : '';
    await client
      .updateItem({
        Key: { name: { S: office.id }, date: { S: date } },
        TableName: (config.dynamoDBTablePrefix || '') + 'office-bookings',
        UpdateExpression: updateExpression.serialize(attributes),
        ExpressionAttributeNames: attributes.names,
        ExpressionAttributeValues: attributes.values,
        ConditionExpression: `bookingCount < ${quotaValue} ${checkParkingQuota}`,
      })
      .promise();
  } catch (err) {
    if (err.code === 'ConditionalCheckFailedException') {
      return false;
    } else {
      throw err;
    }
  }

  return true;
}
Example #15
Source File: LiquidityChart.tsx    From mStable-apps with GNU Lesser General Public License v3.0 5 votes vote down vote up
nowUnix = getUnixTime(new Date())
Example #16
Source File: useDailyApysForBlockTimes.ts    From mStable-apps with GNU Lesser General Public License v3.0 5 votes vote down vote up
nowUnix = getUnixTime(Date.now())
Example #17
Source File: RewardStreamsProvider.tsx    From mStable-apps with GNU Lesser General Public License v3.0 5 votes vote down vote up
nowUnix = getUnixTime(Date.now())
Example #18
Source File: VolumeChart.tsx    From mStable-apps with GNU Lesser General Public License v3.0 5 votes vote down vote up
nowUnix = getUnixTime(new Date())
Example #19
Source File: AggregateChart.tsx    From mStable-apps with GNU Lesser General Public License v3.0 5 votes vote down vote up
nowUnix = getUnixTime(new Date())
Example #20
Source File: createRewardsEarnedContext.ts    From mStable-apps with GNU Lesser General Public License v3.0 5 votes vote down vote up
createRewardsEarnedContext = (): Readonly<[() => RewardsEarned, FC, Context<RewardsEarned>]> => {
  const context = createContext<RewardsEarned>(null as never)

  const RewardEarnedProvider: FC = ({ children }) => {
    const stakedTokenQuery = useStakedTokenQuery()
    const stakedTokenData = stakedTokenQuery.data?.stakedToken
    const stakedToken = useTokenSubscription(stakedTokenData?.id)
    const stakedTokenBalance = stakedToken?.balance

    const [value, setValue] = useState<RewardsEarned>({ rewards: 0 })

    useInterval(() => {
      if (!(stakedTokenBalance && stakedTokenData?.stakingRewards && stakedTokenData.accounts?.[0])) {
        return setValue({ rewards: 0 })
      }

      const {
        stakingRewards: { lastUpdateTime, periodFinish, rewardPerTokenStored: _rewardPerTokenStored, rewardRate },
        token: {
          totalSupply: { bigDecimal: totalTokens },
        },
        accounts: [{ rewards: _rewards, rewardPerTokenPaid }],
      } = stakedTokenData

      // TODO as @client Apollo fields
      const rewardPerTokenStored = BigNumber.from(_rewardPerTokenStored)
      const rewards = BigNumber.from(_rewards)

      const rewardPerToken = (() => {
        if (totalTokens.exact.eq(0)) {
          // If there is no StakingToken liquidity, avoid div(0)
          return rewardPerTokenStored
        }

        const lastTimeRewardApplicable = Math.min(periodFinish, getUnixTime(Date.now()))

        const timeSinceLastUpdate = lastTimeRewardApplicable - lastUpdateTime

        // New reward units to distribute = rewardRate * timeSinceLastUpdate
        const rewardUnitsToDistribute = BigNumber.from(rewardRate).mul(timeSinceLastUpdate)

        // New reward units per token = (rewardUnitsToDistribute * 1e18) / totalTokens
        const unitsToDistributePerToken = rewardUnitsToDistribute.mul(SCALE).div(totalTokens.exact)

        return rewardPerTokenStored.add(unitsToDistributePerToken)
      })()

      // Current rate per token - rate user previously received
      const userRewardDelta = rewardPerToken.sub(rewardPerTokenPaid)

      if (userRewardDelta.eq(0)) {
        return { rewards: new BigDecimal(rewards).simple, canClaim: rewards.gt(0) }
      }

      // New reward = staked tokens * difference in rate
      const userNewReward = stakedTokenBalance.mulTruncate(userRewardDelta)

      // Add to previous rewards
      const summedRewards = rewards.add(userNewReward.exact)

      return setValue({
        canClaim: summedRewards.gt(0),
        rewards: new BigDecimal(summedRewards).simple,
      })
    }, 5e3)

    return providerFactory(context, { value }, children)
  }

  return [createUseContextFn(context), RewardEarnedProvider, context] as const
}
Example #21
Source File: TimeMultiplierImpact.tsx    From mStable-apps with GNU Lesser General Public License v3.0 5 votes vote down vote up
useSimulatedTimeMultiplier = (isStaking: boolean, stakeDelta?: BigNumber) => {
  const stakedTokenQuery = useStakedTokenQuery()

  return useMemo<{ simulatedTimeMultiplier: number; timeMultiplier: number }>(() => {
    if (!stakedTokenQuery.data?.stakedToken?.accounts?.[0]?.balance || !stakeDelta) {
      return {
        simulatedTimeMultiplier: 0,
        timeMultiplier: 0,
      }
    }

    const {
      accounts: [
        {
          balance: { raw, weightedTimestamp: oldWeightedTimestamp },
        },
      ],
    } = stakedTokenQuery.data?.stakedToken

    if (!raw || !oldWeightedTimestamp)
      return {
        simulatedTimeMultiplier: 0,
        timeMultiplier: 0,
      }

    const oldStakedBalance = BigNumber.from(raw)
    const currentTimestamp = BigNumber.from(getUnixTime(Date.now()))

    const oldWeightedSeconds = currentTimestamp.sub(oldWeightedTimestamp)

    const adjustedStakedBalanceDelta = isStaking ? stakeDelta.div(2) : stakeDelta.div(8)

    const adjustedNewStakedBalance = isStaking
      ? oldStakedBalance.add(adjustedStakedBalanceDelta)
      : oldStakedBalance.sub(adjustedStakedBalanceDelta)

    const newWeightedSeconds = isStaking
      ? oldStakedBalance.mul(oldWeightedSeconds).div(adjustedNewStakedBalance)
      : adjustedNewStakedBalance.mul(oldWeightedSeconds).div(oldStakedBalance)

    // const newWeightedTimestamp = currentTimestamp.sub(newWeightedSeconds)
    const simulatedTimeMultiplier = getTimeMultiplier(newWeightedSeconds)
    const timeMultiplier = getTimeMultiplier(oldWeightedSeconds)

    return { simulatedTimeMultiplier, timeMultiplier }
  }, [stakeDelta, isStaking, stakedTokenQuery.data])
}
Example #22
Source File: ClaimButtons.tsx    From mStable-apps with GNU Lesser General Public License v3.0 5 votes vote down vote up
nowUnix = getUnixTime(new Date())
Example #23
Source File: infoQueryHelpers.ts    From glide-frontend with GNU General Public License v3.0 5 votes vote down vote up
getDeltaTimestamps = (): [number, number, number, number] => {
  const utcCurrentTime = getUnixTime(new Date()) * 1000
  const t24h = getUnixTime(startOfMinute(subDays(utcCurrentTime, 1)))
  const t48h = getUnixTime(startOfMinute(subDays(utcCurrentTime, 2)))
  const t7d = getUnixTime(startOfMinute(subWeeks(utcCurrentTime, 1)))
  const t14d = getUnixTime(startOfMinute(subWeeks(utcCurrentTime, 2)))
  return [t24h, t48h, t7d, t14d]
}
Example #24
Source File: helpers.ts    From glide-frontend with GNU General Public License v3.0 5 votes vote down vote up
fetchChartData = async (
  getEntityDayDatas: PoolOrTokenFetchFn | OverviewFetchFn,
  address?: string,
): Promise<{ data?: ChartEntry[]; error: boolean }> => {
  let chartEntries: ChartEntry[] = []
  let error = false
  let skip = 0
  let allFound = false

  while (!allFound) {
    // eslint-disable-next-line no-await-in-loop
    const { data, error: fetchError } = await getEntityDayDatas(skip, address)
    skip += 1000
    allFound = data.length < 1000
    error = fetchError
    if (data) {
      chartEntries = chartEntries.concat(data)
    }
  }

  if (error || chartEntries.length === 0) {
    return {
      error: true,
    }
  }

  const formattedDayDatas = chartEntries.reduce((accum: { [date: number]: ChartEntry }, dayData) => {
    // At this stage we track unix day ordinal for each data point to check for empty days later
    const dayOrdinal = parseInt((dayData.date / ONE_DAY_UNIX).toFixed(0))
    return {
      [dayOrdinal]: dayData,
      ...accum,
    }
  }, {})

  const availableDays = Object.keys(formattedDayDatas).map((dayOrdinal) => parseInt(dayOrdinal, 10))

  const firstAvailableDayData = formattedDayDatas[availableDays[0]]
  // fill in empty days ( there will be no day datas if no trades made that day )
  let timestamp = firstAvailableDayData?.date ?? PCS_V2_START
  let latestLiquidityUSD = firstAvailableDayData?.liquidityUSD ?? 0
  const endTimestamp = getUnixTime(new Date())
  while (timestamp < endTimestamp - ONE_DAY_UNIX) {
    timestamp += ONE_DAY_UNIX
    const dayOrdinal = parseInt((timestamp / ONE_DAY_UNIX).toFixed(0), 10)
    if (!Object.keys(formattedDayDatas).includes(dayOrdinal.toString())) {
      formattedDayDatas[dayOrdinal] = {
        date: timestamp,
        volumeUSD: 0,
        liquidityUSD: latestLiquidityUSD,
      }
    } else {
      latestLiquidityUSD = formattedDayDatas[dayOrdinal].liquidityUSD
    }
  }

  return {
    data: Object.values(formattedDayDatas),
    error: false,
  }
}
Example #25
Source File: RewardStreamsProvider.tsx    From mStable-apps with GNU Lesser General Public License v3.0 4 votes vote down vote up
RewardStreamsProvider: FC<{
  refreshInterval?: number
  vault?: BoostedVaultState
}> = ({ children, refreshInterval = 15e3, vault }) => {
  const [currentTime, setCurrentTime] = useState<number>(nowUnix)
  const account = useAccount()
  const signer = useSigner()
  const [claimRange, setClaimRange] = useState<[number, number] | undefined>(undefined)
  const vaultContract = useRef<BoostedVault>()

  useEffect(() => {
    if (!signer || !account || !vault) return

    if (!vaultContract.current) {
      vaultContract.current = BoostedVault__factory.connect(vault.address, signer)
    }

    vaultContract.current
      .unclaimedRewards(account)
      .catch(error => {
        console.error(error)
      })
      .then(result => {
        if (result) {
          const { first, last } = result
          setClaimRange([first.toNumber(), last.toNumber()])
        } else {
          setClaimRange([0, 0])
        }
      })
  }, [signer, vault, account, setClaimRange])

  useInterval(() => {
    setCurrentTime(getUnixTime(Date.now()))
  }, refreshInterval)

  const rewardStreams = useMemo(() => {
    if (vault?.account) {
      const {
        lockupDuration,
        account: { rewardEntries, lastClaim, lastAction },
        account,
      } = vault

      const [unlockedStreams, lockedStreams] = rewardEntries
        // Remove fully claimed entries
        .filter(entry => (lastClaim ? entry.finish > lastClaim : true))
        // Split entries based on start/finish and now;
        // this helps to visualise it
        .reduce<[RewardEntry[], RewardEntry[]]>(
          ([_unlocked, _locked], entry) => {
            const { start, finish, index } = entry

            if (start <= currentTime && finish >= currentTime) {
              // Unlocked portion and locked portion
              return [
                [
                  ..._unlocked,
                  {
                    ...entry,
                    start,
                    finish: currentTime,
                    index,
                  },
                ],
                [
                  ..._locked,
                  {
                    ...entry,
                    start: currentTime,
                    finish,
                  },
                ],
              ]
            }

            if (start <= currentTime) {
              // Unlocked
              return [[..._unlocked, entry], _locked]
            }
            // Locked
            return [_unlocked, [..._locked, entry]]
          },
          [[], []],
        )
        .map<Stream[]>(entries =>
          entries.map(entry => {
            const { start, finish, index } = entry
            const amount = getEntryAmount(entry)

            const type = start >= currentTime ? StreamType.Locked : StreamType.Unlocked

            return {
              amount: { [type]: amount },
              start,
              finish,
              index,
            }
          }),
        )

      const unlocked = unlockedStreams.reduce((prev, stream) => prev + (stream.amount[StreamType.Unlocked] ?? 0), 0)
      const locked = lockedStreams.reduce((prev, stream) => prev + (stream.amount[StreamType.Locked] ?? 0), 0)
      const earned = calculateEarned(currentTime, vault)

      const earnedStream: Stream = {
        amount: {
          [StreamType.Earned]: earned.unlocked,
        },
        start: lastClaim > 0 ? Math.min(lastClaim, lastAction) : lastAction,
        finish: currentTime,
        index: 0,
      }

      const previewLocked = earned.locked ?? 0
      const previewStream: Stream = {
        amount: {
          [StreamType.LockedPreview]: previewLocked,
        },
        start: lastAction + lockupDuration,
        finish: currentTime + lockupDuration,
      }

      const total = earned.unlocked + previewLocked + locked + unlocked

      // TODO Unclaimed and earned can overlap (but not immediately)
      //   amount: {
      //     [StreamType.Unclaimed]: unclaimed,
      //     [StreamType.Earned]: earned.total,
      //     [StreamType.Unlocked]: unlocked,
      //   },
      //   start: unlockedStreams[0]?.start
      //     ? Math.min(earnedStream.start, unlockedStreams[0].start)
      //     : earnedStream.start,
      //   finish: currentTime,

      const chartData: ChartData = [earnedStream, ...unlockedStreams, ...lockedStreams, previewStream]
        .filter(stream => stream.start > 0)
        .flatMap(({ start, finish, amount }) => [
          {
            ...ZERO_AMOUNTS,
            t: start,
          },
          {
            ...ZERO_AMOUNTS,
            ...amount,
            t: finish,
          },
          {
            ...ZERO_AMOUNTS,
            t: finish + 1,
          },
        ])

      if (!claimRange) {
        return
      }

      const platform = parseInt((account?.platformRewards ?? 0).toString()) / 1e18

      const amounts = {
        earned,
        locked,
        previewLocked,
        unlocked,
        total,
        platform,
      }

      return {
        amounts,
        chartData,
        claimRange: claimRange,
        currentTime,
        nextUnlock: lockedStreams[0]?.start,
        previewStream,
        lockedStreams: [...lockedStreams, previewStream],
      } as RewardStreams
    }
  }, [currentTime, vault, claimRange])

  return <ctx.Provider value={rewardStreams}>{children}</ctx.Provider>
}
Example #26
Source File: createRewardsEarnedContext.ts    From mStable-apps with GNU Lesser General Public License v3.0 4 votes vote down vote up
createRewardsEarnedContext = (
  stakingRewardsCtx: Context<StakingRewardsExtended>,
): Readonly<[() => RewardsEarned, FC, Context<RewardsEarned>]> => {
  const context = createContext<RewardsEarned>(null as never)

  const RewardEarnedProvider: FC = ({ children }) => {
    const stakingRewards = useContext(stakingRewardsCtx)

    const [value, setValue] = useState<RewardsEarned>({ rewards: [] })

    useInterval(() => {
      if (!stakingRewards.stakingRewardsContract) {
        return setValue({ rewards: [] })
      }

      const {
        lastUpdateTime,
        periodFinish,
        platformRewards: { platformReward, platformRewardPerTokenStoredNow, platformRewardRate, platformToken } = {},
        rewardPerTokenStoredNow,
        rewardRate,
        rewardsToken,
        stakingBalance,
        stakingReward,
        totalSupply,
      } = stakingRewards.stakingRewardsContract
      const totalTokens = totalSupply.exact

      const rewardPerToken = (() => {
        if (totalTokens.eq(0)) {
          // If there is no StakingToken liquidity, avoid div(0)
          return { rewardPerTokenStoredNow, platformRewardPerTokenStoredNow }
        }

        const lastTimeRewardApplicable = Math.min(periodFinish, getUnixTime(Date.now()))

        const timeSinceLastUpdate = lastTimeRewardApplicable - lastUpdateTime

        // New reward units to distribute = rewardRate * timeSinceLastUpdate
        const rewardUnitsToDistribute = rewardRate.exact.mul(timeSinceLastUpdate)
        const platformRewardUnitsToDistribute = platformRewardRate?.exact.mul(timeSinceLastUpdate)

        // New reward units per token = (rewardUnitsToDistribute * 1e18) / totalTokens
        const unitsToDistributePerToken = rewardUnitsToDistribute.mul(SCALE).div(totalTokens)
        const platformUnitsToDistributePerToken = platformRewardUnitsToDistribute?.mul(SCALE).div(totalTokens)

        return {
          rewardPerTokenStoredNow: rewardPerTokenStoredNow.add(unitsToDistributePerToken),
          platformRewardPerTokenStoredNow: platformRewardPerTokenStoredNow?.add(platformUnitsToDistributePerToken ?? BigDecimal.ZERO),
        }
      })()

      // Current rate per token - rate user previously received
      const userRewardDelta = rewardPerToken.rewardPerTokenStoredNow.sub(stakingReward.amountPerTokenPaid).exact
      const platformUserRewardDelta = rewardPerToken.platformRewardPerTokenStoredNow?.sub(
        platformReward?.amountPerTokenPaid ?? BigDecimal.ZERO,
      )

      // New reward = staked tokens * difference in rate
      const userNewReward = stakingBalance.mulTruncate(userRewardDelta)
      const userNewPlatformReward = platformUserRewardDelta ? stakingBalance.mulTruncate(platformUserRewardDelta.exact) : undefined

      // Add to previous rewards
      const summedRewards = stakingReward.amount.add(userNewReward)
      const summedPlatformRewards =
        userNewPlatformReward && platformReward ? platformReward.amount.add(userNewPlatformReward) : BigDecimal.ZERO

      return setValue({
        canClaim: summedRewards.exact.gt(0) || summedPlatformRewards.exact.gt(0),
        rewards: [
          {
            earned: summedRewards,
            token: rewardsToken.symbol,
          },
          ...(platformToken
            ? [
                {
                  earned: summedPlatformRewards,
                  token: platformToken.symbol,
                },
              ]
            : []),
        ],
      })
    }, 1e3)

    return providerFactory(context, { value }, children)
  }

  return [createUseContextFn(context), RewardEarnedProvider, context] as const
}
Example #27
Source File: ClaimButtons.tsx    From mStable-apps with GNU Lesser General Public License v3.0 4 votes vote down vote up
ClaimButtons: FC<{ questId: string }> = ({ questId }) => {
  const account = useAccount()
  const clients = useApolloClients()
  const addQuestNotification = useAddQuestNotification()

  const [isPending, toggleIsPending] = useToggle(false)
  const questManagerContract = useQuestManagerContract()
  const propose = usePropose()

  const [playBleep28] = useSound(bleep28, { volume: 0.2 })
  const [playBleep29] = useSound(bleep29, { volume: 0.2 })

  const [updateQuest] = useUpdateQuestMutation({
    client: clients.questbook,
    variables: { questId, userId: account, hasUser: !!account },
    onCompleted: data => {
      const { userQuest, title, objectives } = data.updateQuest
      if (userQuest) return

      const nowUnix = getUnixTime(Date.now())

      if (userQuest.completedAt && nowUnix - userQuest.completedAt < 30) {
        addQuestNotification(title)
      }

      userQuest.objectives
        .filter(obj => obj.completedAt && nowUnix - obj.completedAt < 30)
        .forEach(obj => {
          const obj_ = objectives.find(_obj => _obj.id === obj.id)
          if (obj_) addQuestNotification(obj_.title, obj_.points)
        })
    },
  })

  const questbookQuery = useQuestbookQuestQuery({
    client: clients.questbook,
    variables: { questId, userId: account ?? '', hasUser: !!account },
    pollInterval: 15e3,
  })
  const questbookQuest = questbookQuery.data?.quest
  const ethereumId = questbookQuest?.ethereumId?.toString()

  const questQuery = useQuestQuery({
    client: clients.staking,
    variables: { id: ethereumId as string },
    skip: !ethereumId,
  })

  const accountQuery = useAccountQuery({
    client: clients.staking,
    variables: { id: account ?? '' },
    skip: !account,
    pollInterval: 15e3,
    nextFetchPolicy: 'cache-only',
  })

  const claimed = accountQuery.data?.account?.completedQuests?.find(c => c.quest.id === questbookQuest?.ethereumId?.toString())
  const readyToClaim = !claimed && questbookQuest?.userQuest?.complete
  const questExpired = questQuery.data?.quest && questQuery.data.quest.expiry < nowUnix

  const handleClaimQuest = () => {
    if (
      isPending ||
      !questManagerContract ||
      !questbookQuest ||
      typeof questbookQuest.ethereumId !== 'number' ||
      !questbookQuest.userQuest?.signature
    )
      return

    propose(
      new TransactionManifest<Interfaces.QuestManager, 'completeUserQuests'>(
        questManagerContract,
        'completeUserQuests',
        [account, [questbookQuest.ethereumId], questbookQuest.userQuest.signature],
        {
          present: 'Complete quest',
          past: 'Completed quest',
        },
      ),
    )
  }

  const handleRefresh = () => {
    if (isPending) return

    playBleep28()
    toggleIsPending(true)
    updateQuest()
      .catch(error => {
        console.error(error)
      })
      .finally(() => {
        toggleIsPending(false)
        playBleep29()
      })
  }

  return claimed ? (
    <Button disabled>Claimed</Button>
  ) : readyToClaim ? (
    <Button highlighted onClick={handleClaimQuest} disabled={isPending || questExpired || !ethereumId}>
      {ethereumId ? (
        questExpired ? (
          'Expired'
        ) : (
          'Claim'
        )
      ) : (
        <Tooltip tip="This quest is not available to complete on-chain yet, but it will be in the near future">Claim</Tooltip>
      )}
    </Button>
  ) : (
    <Button highlighted onClick={handleRefresh} disabled={isPending}>
      {isPending ? 'Checking...' : 'Check status'}
    </Button>
  )
}
Example #28
Source File: priceData.ts    From vvs-ui with GNU General Public License v3.0 4 votes vote down vote up
fetchTokenPriceData = async (
  address: string,
  interval: number,
  startTimestamp: number,
): Promise<{
  data?: PriceChartEntry[]
  error: boolean
}> => {
  // Construct timestamps to query against
  const endTimestamp = getUnixTime(new Date())
  const timestamps = []
  let time = startTimestamp
  while (time <= endTimestamp) {
    timestamps.push(time)
    time += interval
  }
  try {
    const blocks = await getBlocksFromTimestamps(timestamps, 'asc', 500)
    if (!blocks || blocks.length === 0) {
      console.error('Error fetching blocks for timestamps', timestamps)
      return {
        error: false,
      }
    }

    const prices: any | undefined = await multiQuery(
      priceQueryConstructor,
      getPriceSubqueries(address, blocks),
      INFO_CLIENT,
      200,
    )

    if (!prices) {
      console.error('Price data failed to load')
      return {
        error: false,
      }
    }

    // format token BNB price results
    const tokenPrices: {
      timestamp: string
      derivedCRO: number
      priceUSD: number
    }[] = []

    // Get Token prices in BNB
    Object.keys(prices).forEach((priceKey) => {
      const timestamp = priceKey.split('t')[1]
      // if its BNB price e.g. `b123` split('t')[1] will be undefined and skip BNB price entry
      if (timestamp) {
        tokenPrices.push({
          timestamp,
          derivedCRO: prices[priceKey]?.derivedCRO ? parseFloat(prices[priceKey].derivedCRO) : 0,
          priceUSD: 0,
        })
      }
    })

    // Go through BNB USD prices and calculate Token price based on it
    Object.keys(prices).forEach((priceKey) => {
      const timestamp = priceKey.split('b')[1]
      // if its Token price e.g. `t123` split('b')[1] will be undefined and skip Token price entry
      if (timestamp) {
        const tokenPriceIndex = tokenPrices.findIndex((tokenPrice) => tokenPrice.timestamp === timestamp)
        if (tokenPriceIndex >= 0) {
          const { derivedCRO } = tokenPrices[tokenPriceIndex]
          tokenPrices[tokenPriceIndex].priceUSD = parseFloat(prices[priceKey]?.croPrice ?? 0) * derivedCRO
        }
      }
    })

    // graphql-request does not guarantee same ordering of batched requests subqueries, hence sorting by timestamp from oldest to newest
    tokenPrices.sort((a, b) => parseInt(a.timestamp, 10) - parseInt(b.timestamp, 10))

    const formattedHistory = []

    // for each timestamp, construct the open and close price
    for (let i = 0; i < tokenPrices.length - 1; i++) {
      formattedHistory.push({
        time: parseFloat(tokenPrices[i].timestamp),
        open: tokenPrices[i].priceUSD,
        close: tokenPrices[i + 1].priceUSD,
        high: tokenPrices[i + 1].priceUSD,
        low: tokenPrices[i].priceUSD,
      })
    }

    return { data: formattedHistory, error: false }
  } catch (error) {
    console.error(`Failed to fetch price data for token ${address}`, error)
    return {
      error: true,
    }
  }
}
Example #29
Source File: priceData.ts    From glide-frontend with GNU General Public License v3.0 4 votes vote down vote up
fetchTokenPriceData = async (
  address: string,
  interval: number,
  startTimestamp: number,
): Promise<{
  data?: PriceChartEntry[]
  error: boolean
}> => {
  // Construct timestamps to query against
  const endTimestamp = getUnixTime(new Date())
  const timestamps = []
  let time = startTimestamp
  while (time <= endTimestamp) {
    timestamps.push(time)
    time += interval
  }
  try {
    const blocks = await getBlocksFromTimestamps(timestamps, 'asc', 500)
    if (!blocks || blocks.length === 0) {
      console.error('Error fetching blocks for timestamps', timestamps)
      return {
        error: false,
      }
    }

    const prices: any | undefined = await multiQuery(
      priceQueryConstructor,
      getPriceSubqueries(address, blocks),
      INFO_CLIENT,
      200,
    )

    if (!prices) {
      console.error('Price data failed to load')
      return {
        error: false,
      }
    }

    // format token ELA price results
    const tokenPrices: {
      timestamp: string
      derivedELA: number
      priceUSD: number
    }[] = []

    // Get Token prices in ELA
    Object.keys(prices).forEach((priceKey) => {
      const timestamp = priceKey.split('t')[1]
      // if its ELA price e.g. `b123` split('t')[1] will be undefined and skip ELA price entry
      if (timestamp) {
        tokenPrices.push({
          timestamp,
          derivedELA: prices[priceKey]?.derivedELA ? parseFloat(prices[priceKey].derivedELA) : 0,
          priceUSD: 0,
        })
      }
    })

    // Go through ELA USD prices and calculate Token price based on it
    Object.keys(prices).forEach((priceKey) => {
      const timestamp = priceKey.split('b')[1]
      // if its Token price e.g. `t123` split('b')[1] will be undefined and skip Token price entry
      if (timestamp) {
        const tokenPriceIndex = tokenPrices.findIndex((tokenPrice) => tokenPrice.timestamp === timestamp)
        if (tokenPriceIndex >= 0) {
          const { derivedELA } = tokenPrices[tokenPriceIndex]
          tokenPrices[tokenPriceIndex].priceUSD = parseFloat(prices[priceKey]?.elaPrice ?? 0) * derivedELA
        }
      }
    })

    // graphql-request does not guarantee same ordering of batched requests subqueries, hence sorting by timestamp from oldest to newest
    tokenPrices.sort((a, b) => parseInt(a.timestamp, 10) - parseInt(b.timestamp, 10))

    const formattedHistory = []

    // for each timestamp, construct the open and close price
    for (let i = 0; i < tokenPrices.length - 1; i++) {
      formattedHistory.push({
        time: parseFloat(tokenPrices[i].timestamp),
        open: tokenPrices[i].priceUSD,
        close: tokenPrices[i + 1].priceUSD,
        high: tokenPrices[i + 1].priceUSD,
        low: tokenPrices[i].priceUSD,
      })
    }

    return { data: formattedHistory, error: false }
  } catch (error) {
    console.error(`Failed to fetch price data for token ${address}`, error)
    return {
      error: true,
    }
  }
}