| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- // TODO remove these disables when moving off the mock APIs
- /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-non-null-assertion */
- import type { AnchorWallet } from "@solana/wallet-adapter-react";
- import type { Connection } from "@solana/web3.js";
- export type StakeAccount = {
- publicKey: `0x${string}`;
- };
- export type Context = {
- connection: Connection;
- wallet: AnchorWallet;
- stakeAccount: StakeAccount;
- };
- type Data = {
- total: bigint;
- availableRewards: bigint;
- lastSlash:
- | {
- amount: bigint;
- date: Date;
- }
- | undefined;
- expiringRewards: {
- amount: bigint;
- expiry: Date;
- };
- locked: bigint;
- unlockSchedule: {
- date: Date;
- amount: bigint;
- }[];
- walletAmount: bigint;
- governance: {
- warmup: bigint;
- staked: bigint;
- cooldown: bigint;
- cooldown2: bigint;
- };
- integrityStakingPublishers: {
- name: string;
- publicKey: `0x${string}`;
- isSelf: boolean;
- selfStake: bigint;
- poolCapacity: bigint;
- poolUtilization: bigint;
- numFeeds: number;
- qualityRanking: number;
- apyHistory: { date: Date; apy: number }[];
- positions?:
- | {
- warmup?: bigint | undefined;
- staked?: bigint | undefined;
- cooldown?: bigint | undefined;
- cooldown2?: bigint | undefined;
- }
- | undefined;
- }[];
- };
- export enum StakeType {
- Governance,
- IntegrityStaking,
- }
- const StakeDetails = {
- Governance: () => ({ type: StakeType.Governance as const }),
- IntegrityStaking: (publisherName: string) => ({
- type: StakeType.IntegrityStaking as const,
- publisherName,
- }),
- };
- export type StakeDetails = ReturnType<
- (typeof StakeDetails)[keyof typeof StakeDetails]
- >;
- export enum AccountHistoryItemType {
- Deposit,
- LockedDeposit,
- Withdrawal,
- RewardsCredited,
- Claim,
- Slash,
- Unlock,
- StakeCreated,
- StakeFinishedWarmup,
- UnstakeCreated,
- UnstakeExitedCooldown,
- }
- const AccountHistoryAction = {
- Deposit: () => ({ type: AccountHistoryItemType.Deposit as const }),
- LockedDeposit: (unlockDate: Date) => ({
- type: AccountHistoryItemType.LockedDeposit as const,
- unlockDate,
- }),
- Withdrawal: () => ({ type: AccountHistoryItemType.Withdrawal as const }),
- RewardsCredited: () => ({
- type: AccountHistoryItemType.RewardsCredited as const,
- }),
- Claim: () => ({ type: AccountHistoryItemType.Claim as const }),
- Slash: (publisherName: string) => ({
- type: AccountHistoryItemType.Slash as const,
- publisherName,
- }),
- Unlock: () => ({ type: AccountHistoryItemType.Unlock as const }),
- StakeCreated: (details: StakeDetails) => ({
- type: AccountHistoryItemType.StakeCreated as const,
- details,
- }),
- StakeFinishedWarmup: (details: StakeDetails) => ({
- type: AccountHistoryItemType.StakeFinishedWarmup as const,
- details,
- }),
- UnstakeCreated: (details: StakeDetails) => ({
- type: AccountHistoryItemType.UnstakeCreated as const,
- details,
- }),
- UnstakeExitedCooldown: (details: StakeDetails) => ({
- type: AccountHistoryItemType.UnstakeExitedCooldown as const,
- details,
- }),
- };
- export type AccountHistoryAction = ReturnType<
- (typeof AccountHistoryAction)[keyof typeof AccountHistoryAction]
- >;
- type AccountHistory = {
- timestamp: Date;
- action: AccountHistoryAction;
- amount: bigint;
- accountTotal: bigint;
- availableToWithdraw: bigint;
- availableRewards: bigint;
- locked: bigint;
- }[];
- export const getStakeAccounts = async (
- _connection: Connection,
- _wallet: AnchorWallet,
- ): Promise<StakeAccount[]> => {
- await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
- return MOCK_STAKE_ACCOUNTS;
- };
- export const loadData = async (context: Context): Promise<Data> => {
- await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
- // While using mocks we need to clone the MOCK_DATA object every time
- // `loadData` is called so that swr treats the response as changed and
- // triggers a rerender.
- return { ...MOCK_DATA[context.stakeAccount.publicKey]! };
- };
- export const loadAccountHistory = async (
- context: Context,
- ): Promise<AccountHistory> => {
- await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
- return [...MOCK_HISTORY[context.stakeAccount.publicKey]!];
- };
- export const deposit = async (
- context: Context,
- amount: bigint,
- ): Promise<void> => {
- await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
- MOCK_DATA[context.stakeAccount.publicKey]!.total += amount;
- MOCK_DATA[context.stakeAccount.publicKey]!.walletAmount -= amount;
- };
- export const withdraw = async (
- context: Context,
- amount: bigint,
- ): Promise<void> => {
- await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
- MOCK_DATA[context.stakeAccount.publicKey]!.total -= amount;
- MOCK_DATA[context.stakeAccount.publicKey]!.walletAmount += amount;
- };
- export const claim = async (context: Context): Promise<void> => {
- await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
- MOCK_DATA[context.stakeAccount.publicKey]!.total +=
- MOCK_DATA[context.stakeAccount.publicKey]!.availableRewards;
- MOCK_DATA[context.stakeAccount.publicKey]!.availableRewards = 0n;
- MOCK_DATA[context.stakeAccount.publicKey]!.expiringRewards.amount = 0n;
- };
- export const stakeGovernance = async (
- context: Context,
- amount: bigint,
- ): Promise<void> => {
- await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
- MOCK_DATA[context.stakeAccount.publicKey]!.governance.warmup += amount;
- };
- export const cancelWarmupGovernance = async (
- context: Context,
- amount: bigint,
- ): Promise<void> => {
- await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
- MOCK_DATA[context.stakeAccount.publicKey]!.governance.warmup -= amount;
- };
- export const unstakeGovernance = async (
- context: Context,
- amount: bigint,
- ): Promise<void> => {
- await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
- MOCK_DATA[context.stakeAccount.publicKey]!.governance.staked -= amount;
- MOCK_DATA[context.stakeAccount.publicKey]!.governance.cooldown += amount;
- };
- export const delegateIntegrityStaking = async (
- context: Context,
- publisherKey: string,
- amount: bigint,
- ): Promise<void> => {
- await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
- const publisher = MOCK_DATA[
- context.stakeAccount.publicKey
- ]!.integrityStakingPublishers.find(
- (publisher) => publisher.publicKey === publisherKey,
- );
- if (publisher) {
- publisher.positions ||= {};
- publisher.positions.warmup = (publisher.positions.warmup ?? 0n) + amount;
- } else {
- throw new Error(`Invalid publisher key: "${publisherKey}"`);
- }
- };
- export const cancelWarmupIntegrityStaking = async (
- context: Context,
- publisherKey: string,
- amount: bigint,
- ): Promise<void> => {
- await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
- const publisher = MOCK_DATA[
- context.stakeAccount.publicKey
- ]!.integrityStakingPublishers.find(
- (publisher) => publisher.publicKey === publisherKey,
- );
- if (publisher) {
- if (publisher.positions?.warmup) {
- publisher.positions.warmup -= amount;
- }
- } else {
- throw new Error(`Invalid publisher key: "${publisherKey}"`);
- }
- };
- export const unstakeIntegrityStaking = async (
- context: Context,
- publisherKey: string,
- amount: bigint,
- ): Promise<void> => {
- await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
- const publisher = MOCK_DATA[
- context.stakeAccount.publicKey
- ]!.integrityStakingPublishers.find(
- (publisher) => publisher.publicKey === publisherKey,
- );
- if (publisher) {
- if (publisher.positions?.staked) {
- publisher.positions.staked -= amount;
- publisher.positions.cooldown =
- (publisher.positions.cooldown ?? 0n) + amount;
- }
- } else {
- throw new Error(`Invalid publisher key: "${publisherKey}"`);
- }
- };
- export const calculateApy = (
- poolCapacity: bigint,
- poolUtilization: bigint,
- isSelf: boolean,
- ) => {
- const maxApy = isSelf ? 25 : 20;
- const minApy = isSelf ? 10 : 5;
- return Math.min(
- Math.max(
- maxApy - Number((poolUtilization - poolCapacity) / 100_000_000n),
- minApy,
- ),
- maxApy,
- );
- };
- export const getUpcomingEpoch = (): Date => {
- const d = new Date();
- d.setUTCDate(d.getUTCDate() + ((5 + 7 - d.getUTCDay()) % 7 || 7));
- d.setUTCHours(0);
- d.setUTCMinutes(0);
- d.setUTCSeconds(0);
- d.setUTCMilliseconds(0);
- return d;
- };
- export const getNextFullEpoch = (): Date => {
- const d = getUpcomingEpoch();
- d.setUTCDate(d.getUTCDate() + 7);
- return d;
- };
- const MOCK_DELAY = 500;
- const MOCK_STAKE_ACCOUNTS: StakeAccount[] = [
- { publicKey: "0x000000" },
- { publicKey: "0x111111" },
- ];
- const mkMockData = (isDouro: boolean): Data => ({
- total: 15_000_000n,
- availableRewards: 156_000n,
- lastSlash: isDouro
- ? undefined
- : {
- amount: 2147n,
- date: new Date("2024-05-04T00:00:00Z"),
- },
- expiringRewards: {
- amount: 56_000n,
- expiry: new Date("2025-08-01T00:00:00Z"),
- },
- locked: isDouro ? 3_000_000n : 0n,
- unlockSchedule: isDouro
- ? [
- {
- amount: 1_000_000n,
- date: new Date("2025-08-01T00:00:00Z"),
- },
- {
- amount: 2_000_000n,
- date: new Date("2025-09-01T00:00:00Z"),
- },
- ]
- : [],
- walletAmount: 5_000_000_000_000n,
- governance: {
- warmup: 2_670_000n,
- staked: 4_150_000n,
- cooldown: 1_850_000n,
- cooldown2: 4_765_000n,
- },
- integrityStakingPublishers: [
- {
- name: "Douro Labs",
- publicKey: "0xF00",
- isSelf: isDouro,
- selfStake: 5_000_000_000n,
- poolCapacity: 500_000_000n,
- poolUtilization: 200_000_000n,
- numFeeds: 42,
- qualityRanking: 1,
- apyHistory: [
- { date: new Date("2024-07-22"), apy: 5 },
- { date: new Date("2024-07-23"), apy: 10 },
- { date: new Date("2024-07-24"), apy: 25 },
- { date: new Date("2024-07-25"), apy: 20 },
- ],
- positions: {
- warmup: 5_000_000n,
- staked: 4_000_000n,
- cooldown: 1_000_000n,
- cooldown2: 460_000n,
- },
- },
- {
- name: "Jump Trading",
- publicKey: "0xBA4",
- isSelf: false,
- selfStake: 400_000_000n,
- poolCapacity: 500_000_000n,
- poolUtilization: 750_000_000n,
- numFeeds: 84,
- qualityRanking: 2,
- apyHistory: [
- { date: new Date("2024-07-24"), apy: 5 },
- { date: new Date("2024-07-25"), apy: 10 },
- ],
- positions: {
- staked: 1_000_000n,
- },
- },
- {
- name: "Cboe",
- publicKey: "0xAA",
- isSelf: false,
- selfStake: 200_000_000n,
- poolCapacity: 600_000_000n,
- poolUtilization: 450_000_000n,
- numFeeds: 17,
- qualityRanking: 5,
- apyHistory: [
- { date: new Date("2024-07-24"), apy: 5 },
- { date: new Date("2024-07-25"), apy: 10 },
- ],
- },
- {
- name: "Raydium",
- publicKey: "0x111",
- isSelf: false,
- selfStake: 400_000_000n,
- poolCapacity: 500_000_000n,
- poolUtilization: 750_000_000n,
- numFeeds: 84,
- qualityRanking: 3,
- apyHistory: [
- { date: new Date("2024-07-24"), apy: 5 },
- { date: new Date("2024-07-25"), apy: 10 },
- ],
- },
- ],
- });
- const MOCK_DATA: Record<
- (typeof MOCK_STAKE_ACCOUNTS)[number]["publicKey"],
- Data
- > = {
- "0x000000": mkMockData(true),
- "0x111111": mkMockData(false),
- };
- const mkMockHistory = (): AccountHistory => [
- {
- timestamp: new Date("2024-06-10T00:00:00Z"),
- action: AccountHistoryAction.Deposit(),
- amount: 2_000_000n,
- accountTotal: 2_000_000n,
- availableRewards: 0n,
- availableToWithdraw: 2_000_000n,
- locked: 0n,
- },
- {
- timestamp: new Date("2024-06-14T02:00:00Z"),
- action: AccountHistoryAction.RewardsCredited(),
- amount: 200n,
- accountTotal: 2_000_000n,
- availableRewards: 200n,
- availableToWithdraw: 2_000_000n,
- locked: 0n,
- },
- {
- timestamp: new Date("2024-06-16T08:00:00Z"),
- action: AccountHistoryAction.Claim(),
- amount: 200n,
- accountTotal: 2_000_200n,
- availableRewards: 0n,
- availableToWithdraw: 2_000_200n,
- locked: 0n,
- },
- {
- timestamp: new Date("2024-06-16T08:00:00Z"),
- action: AccountHistoryAction.Slash("Cboe"),
- amount: 1000n,
- accountTotal: 1_999_200n,
- availableRewards: 0n,
- availableToWithdraw: 1_999_200n,
- locked: 0n,
- },
- ];
- const MOCK_HISTORY: Record<
- (typeof MOCK_STAKE_ACCOUNTS)[number]["publicKey"],
- AccountHistory
- > = {
- "0x000000": mkMockHistory(),
- "0x111111": mkMockHistory(),
- };
|