Skip to content

Commit

Permalink
feat: continue
Browse files Browse the repository at this point in the history
  • Loading branch information
danielsimao committed Aug 29, 2023
1 parent 1fa41e5 commit d0b8d8f
Show file tree
Hide file tree
Showing 13 changed files with 235 additions and 170 deletions.
1 change: 1 addition & 0 deletions src/component-library/List/List.style.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const StyledListItem = styled.li<StyledListItemProps>`
cursor: ${({ $isInteractable }) => $isInteractable && 'pointer'};
outline: ${({ $isFocusVisible }) => !$isFocusVisible && 'none'};
opacity: ${({ $isDisabled }) => $isDisabled && 0.5};
white-space: nowrap;
${({ $variant }) => {
if ($variant === 'card') {
Expand Down
35 changes: 35 additions & 0 deletions src/hooks/api/escrow/use-get-account-claimable-rewards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { CurrencyExt } from '@interlay/interbtc-api';
import { MonetaryAmount } from '@interlay/monetary-js';
import { AccountId } from '@polkadot/types/interfaces';
import { useErrorHandler } from 'react-error-boundary';
import { useQuery } from 'react-query';

import { useWallet } from '@/hooks/use-wallet';
import { REFETCH_INTERVAL } from '@/utils/constants/api';

const getAccountStakingData = async (accountId: AccountId) => window.bridge.escrow.getRewards(accountId);

interface UseGetAccountStakingClaimableRewardsResult {
data: MonetaryAmount<CurrencyExt> | undefined;
refetch: () => void;
}

const useGetAccountStakingClaimableRewards = (): UseGetAccountStakingClaimableRewardsResult => {
const { account } = useWallet();

const queryKey = ['staking-claimable-rewards', account];

const { data, error, refetch } = useQuery({
queryKey,
queryFn: () => account && getAccountStakingData(account),
refetchInterval: REFETCH_INTERVAL.BLOCK,
enabled: !!account
});

useErrorHandler(error);

return { data, refetch };
};

export { useGetAccountStakingClaimableRewards };
export type { UseGetAccountStakingClaimableRewardsResult };
47 changes: 18 additions & 29 deletions src/hooks/api/escrow/use-get-account-staking-data.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,42 @@ import { MonetaryAmount } from '@interlay/monetary-js';
import { AccountId } from '@polkadot/types/interfaces';
import Big from 'big.js';
import { add } from 'date-fns';
import { useCallback } from 'react';
import { useErrorHandler } from 'react-error-boundary';
import { useQuery } from 'react-query';

import { BLOCK_TIME } from '@/config/parachain';
import { REFETCH_INTERVAL } from '@/utils/constants/api';
import { convertWeeksToBlockNumbers } from '@/utils/helpers/staking';

import useAccountId from '../../use-account-id';

type AccountUnlockStakingData = {
date: Date;
block: number;
remainingBlocks: number;
isAvailable: boolean;
};

type AccountStakingData = {
unlock: AccountUnlockStakingData;
balance: MonetaryAmount<CurrencyExt>;
endBlock: number;
votingBalance: MonetaryAmount<CurrencyExt>;
claimableRewards: MonetaryAmount<CurrencyExt>;
projected: {
amount: MonetaryAmount<CurrencyExt>;
apy: Big;
};
// limit: MonetaryAmount<CurrencyExt>;
};

const getUnlockData = (stakeEndBlock: number, currentBlockNumber: number): AccountUnlockStakingData => {
const blocksUntilUnlockDate = stakeEndBlock - currentBlockNumber;
const remainingBlocks = stakeEndBlock - currentBlockNumber;

const unlockDate = add(new Date(), { seconds: blocksUntilUnlockDate * BLOCK_TIME });
const unlockDate = add(new Date(), { seconds: remainingBlocks * BLOCK_TIME });

return {
date: unlockDate,
block: stakeEndBlock
block: stakeEndBlock,
remainingBlocks,
isAvailable: remainingBlocks <= 0
};
};

Expand All @@ -48,14 +49,19 @@ const getAccountStakingData = async (accountId: AccountId): Promise<AccountStaki
return null;
}

// const limitPromise = window.bridge.api.rpc.escrow.freeStakable(accountId);
const currentBlockNumberPromise = window.bridge.system.getCurrentBlockNumber();
const claimableRewardsPromise = window.bridge.escrow.getRewards(accountId);
const projectedPromise = window.bridge.escrow.getRewardEstimate(accountId);
const votingBalancePromise = window.bridge.escrow.votingBalance(accountId);

const [currentBlockNumber, claimableRewards, projected, votingBalance] = await Promise.all([
const [
// limit,
currentBlockNumber,
projected,
votingBalance
] = await Promise.all([
// limitPromise,
currentBlockNumberPromise,
claimableRewardsPromise,
projectedPromise,
votingBalancePromise
]);
Expand All @@ -65,16 +71,14 @@ const getAccountStakingData = async (accountId: AccountId): Promise<AccountStaki
return {
unlock,
balance: stakedBalance.amount,
endBlock: stakedBalance.endBlock,
votingBalance,
claimableRewards,
projected
// limit
};
};

interface UseGetAccountStakingDataResult {
data: AccountStakingData | null | undefined;
getUnlockHeight: (lockTime: number) => Promise<number>;
refetch: () => void;
}

Expand All @@ -90,24 +94,9 @@ const useGetAccountStakingData = (): UseGetAccountStakingDataResult => {
enabled: !!accountId
});

const getUnlockHeight = useCallback(
async (lockTime: number) => {
const newLockBlockNumber = convertWeeksToBlockNumbers(lockTime);

if (data) {
return data.endBlock + newLockBlockNumber;
}

const currentBlockNumber = await window.bridge.system.getCurrentBlockNumber();

return currentBlockNumber + newLockBlockNumber;
},
[data]
);

useErrorHandler(error);

return { data, refetch, getUnlockHeight };
return { data, refetch };
};

export { useGetAccountStakingData };
Expand Down
12 changes: 6 additions & 6 deletions src/hooks/api/escrow/use-get-staking-estimation-data.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,20 @@ const getRewardEstimate = async (
accountId?: AccountId,
accountData?: AccountStakingData | null,
amount: MonetaryAmount<CurrencyExt> = newMonetaryAmount(0, GOVERNANCE_TOKEN),
lockTime = 0
weeksLocked = 0
): Promise<AccountStakingEstimationData | undefined> => {
if (!accountId) return;

const baseBlockNumber = accountData?.endBlock || (await window.bridge.system.getCurrentBlockNumber());
const baseBlockNumber = accountData?.unlock.block || (await window.bridge.system.getCurrentBlockNumber());

const newBlockNumber = baseBlockNumber + convertWeeksToBlockNumbers(lockTime);
const newBlockNumber = baseBlockNumber + convertWeeksToBlockNumbers(weeksLocked);

return window.bridge.escrow.getRewardEstimate(accountId, amount, newBlockNumber);
};

type StakingEstimationVariables = {
amount?: MonetaryAmount<CurrencyExt>;
lockTime?: number;
weeksLocked?: number;
};

type UseGetStakingEstimationOptions = UseMutationOptions<
Expand All @@ -60,8 +60,8 @@ const useGetStakingEstimationData = (

const fn: MutationFunction<AccountStakingEstimationData | undefined, StakingEstimationVariables> = ({
amount,
lockTime
}) => getRewardEstimate(accountId, accountData.data, amount, lockTime);
weeksLocked
}) => getRewardEstimate(accountId, accountData.data, amount, weeksLocked);

const mutation = useMutation<AccountStakingEstimationData | undefined, Error, StakingEstimationVariables, unknown>(
fn,
Expand Down
63 changes: 30 additions & 33 deletions src/lib/form/schemas/staking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,51 @@
import yup, { MaxAmountValidationParams, MinAmountValidationParams } from '../yup.custom';

const STAKING_AMOUNT_FIELD = 'staking-amount';
const STAKING_LOCK_TIME_AMOUNT_FIELD = 'staking-lock-time-amount';
const STAKING_LOCKED_WEEKS_AMOUNT_FIELD = 'staking-locked-weeks-amount';
const STAKING_FEE_TOKEN_FIELD = 'staking-fee-token';

type StakingFormData = {
[STAKING_AMOUNT_FIELD]?: string;
[STAKING_LOCK_TIME_AMOUNT_FIELD]?: number;
[STAKING_LOCKED_WEEKS_AMOUNT_FIELD]?: string;
[STAKING_FEE_TOKEN_FIELD]?: string;
};

type StakingValidationParams = {
[STAKING_AMOUNT_FIELD]: Partial<MaxAmountValidationParams> & Partial<MinAmountValidationParams>;
[STAKING_LOCK_TIME_AMOUNT_FIELD]: {
[STAKING_LOCKED_WEEKS_AMOUNT_FIELD]: {
min: number;
max: number;
};
};

// TODO: lock time could be 0 if only adding into staking amount
const stakingSchema = (params: StakingValidationParams): yup.ObjectSchema<any> =>
yup.object().shape({
[STAKING_AMOUNT_FIELD]: yup
.string()
// .when([STAKING_LOCK_TIME_AMOUNT_FIELD], {
// is: !hasStaked,
// then: yup.number().required(i18n.t('forms.please_enter_your_field', { field: 'stake' }))
// })
// .requiredAmount('stake')
.maxAmount(params[STAKING_AMOUNT_FIELD] as MaxAmountValidationParams)
.minAmount(params[STAKING_AMOUNT_FIELD] as MinAmountValidationParams, 'transfer'),
[STAKING_LOCK_TIME_AMOUNT_FIELD]: yup
.number()
// .test('is-required', i18n.t('forms.please_enter_your_field', { field: 'lock time' }), (value) =>
// hasStaked ? true : value !== undefined
// )
// .when([], {
// is: !hasStaked,
// then: yup.number().required(i18n.t('forms.please_enter_your_field', { field: 'lock time' }))
// })
.min(
params[STAKING_LOCK_TIME_AMOUNT_FIELD].min,
`Lock time must be greater than or equal to ${params[STAKING_LOCK_TIME_AMOUNT_FIELD].min}`
)
.max(
params[STAKING_LOCK_TIME_AMOUNT_FIELD].max,
`Lock time must be less than or equal to ${params[STAKING_LOCK_TIME_AMOUNT_FIELD].max}`
),
const stakingSchema = (params: StakingValidationParams, hasStaked: boolean): yup.ObjectSchema<any> => {
const amountParams = params[STAKING_AMOUNT_FIELD];
const { min, max } = params[STAKING_LOCKED_WEEKS_AMOUNT_FIELD];

let baseAmountSchema = yup
.string()
.maxAmount(amountParams as MaxAmountValidationParams)
.minAmount(amountParams as MinAmountValidationParams, 'transfer');

const baseLockTimeSchema = yup
.string()
.test('min', `Lock time must be greater than or equal to ${min}`, (value) => Number(value) >= min)
.test('max', `Lock time must be less than or equal to ${max}`, (value) => Number(value) <= max);
// .min(min, `Lock time must be greater than or equal to ${min}`)
// .max(max, `Lock time must be less than or equal to ${max}`);

if (!hasStaked) {
baseAmountSchema = baseAmountSchema.requiredAmount('stake');

// baseLockTimeSchema = baseLockTimeSchema.required(i18n.t('forms.please_enter_your_field', { field: 'lock time' }));
}

return yup.object().shape({
[STAKING_AMOUNT_FIELD]: baseAmountSchema,
[STAKING_LOCKED_WEEKS_AMOUNT_FIELD]: baseLockTimeSchema,
[STAKING_FEE_TOKEN_FIELD]: yup.string().required()
});
};

export { STAKING_AMOUNT_FIELD, STAKING_FEE_TOKEN_FIELD, STAKING_LOCK_TIME_AMOUNT_FIELD, stakingSchema };
export { STAKING_AMOUNT_FIELD, STAKING_FEE_TOKEN_FIELD, STAKING_LOCKED_WEEKS_AMOUNT_FIELD, stakingSchema };
export type { StakingFormData, StakingValidationParams };
4 changes: 1 addition & 3 deletions src/pages/Staking copy/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,6 @@ const Staking = (): JSX.Element => {
const extensionTime =
(stakedAmountAndEndBlock?.endBlock || currentBlockNumber) + convertWeeksToBlockNumbers(lockTimeValue);

console.log(stakedAmountAndEndBlock?.endBlock, currentBlockNumber, convertWeeksToBlockNumbers(lockTimeValue));

setBlockLockTimeExtension(extensionTime);
}, [currentBlockNumber, lockTime, stakedAmountAndEndBlock]);

Expand Down Expand Up @@ -580,7 +578,7 @@ const Staking = (): JSX.Element => {

// New lock-time that is applied to the entire staked governance token
newLockTime = currentLockTime + extendingLockTime; // Weeks

console.log(currentLockTime, extendingLockTime);
// New total staked governance token
newLockingAmount = monetaryLockingAmount.add(stakedAmount);
}
Expand Down
6 changes: 5 additions & 1 deletion src/pages/Staking/Staking.style.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Flex, theme } from '@/component-library';
import { StakingForm } from './components';

const StyledWrapper = styled(Flex)`
width: 100%;
max-width: 840px;
margin: 0 auto;
flex-direction: column-reverse;
Expand All @@ -15,9 +16,12 @@ const StyledWrapper = styled(Flex)`
`;

const StyledStakingForm = styled(StakingForm)`
min-width: 540px;
width: 100%;
flex: 1 1 540px;
@media ${theme.breakpoints.up('lg')} {
min-width: 540px;
}
`;

export { StyledStakingForm, StyledWrapper };
14 changes: 10 additions & 4 deletions src/pages/Staking/Staking.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Flex } from '@/component-library';
import { MainContainer } from '@/components';
import { useGetAccountStakingClaimableRewards } from '@/hooks/api/escrow/use-get-account-claimable-rewards';
import { useGetAccountStakingData } from '@/hooks/api/escrow/use-get-account-staking-data';
import { useGetNetworkStakingData } from '@/hooks/api/escrow/uset-get-network-staking-data';
import FullLoadingSpinner from '@/legacy-components/FullLoadingSpinner';
Expand All @@ -10,19 +11,24 @@ import { StyledStakingForm, StyledWrapper } from './Staking.style';

const Staking = (): JSX.Element => {
const { data: accountData, refetch: refetchAccountData } = useGetAccountStakingData();
const { data: claimableRewards, refetch: refetchClaimableRewards } = useGetAccountStakingClaimableRewards();
const { data: networkData } = useGetNetworkStakingData();

if (accountData === undefined || networkData === undefined) {
if (accountData === undefined || claimableRewards === undefined || networkData === undefined) {
return <FullLoadingSpinner />;
}

return (
<MainContainer>
<StyledWrapper gap='spacing8'>
<StyledWrapper gap='spacing4'>
<StyledStakingForm accountData={accountData} networkData={networkData} onStaking={refetchAccountData} />
<Flex direction='column' gap='spacing4'>
<StakingAccountDetails data={accountData} onVotingClaimRewards={refetchAccountData} />
{accountData && <StakingWithdrawCard data={accountData} onClaimRewards={refetchAccountData} />}
<StakingAccountDetails
accountData={accountData}
claimableRewards={claimableRewards}
onClaimRewards={refetchClaimableRewards}
/>
{accountData && <StakingWithdrawCard data={accountData} onWithdraw={refetchAccountData} />}
</Flex>
</StyledWrapper>
</MainContainer>
Expand Down
Loading

0 comments on commit d0b8d8f

Please sign in to comment.