Skip to content

Commit

Permalink
Merge pull request #236 from lidofinance/develop
Browse files Browse the repository at this point in the history
Merge develop to main
  • Loading branch information
jake4take authored Feb 15, 2024
2 parents 70371cf + 347784b commit 894f740
Show file tree
Hide file tree
Showing 37 changed files with 381 additions and 246 deletions.
12 changes: 6 additions & 6 deletions config/tx.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export const STANDARD_GAS_LIMIT = 21000;
import { BigNumber } from 'ethers';

export const WSTETH_APPROVE_GAS_LIMIT = 78000;
export const WSTETH_APPROVE_GAS_LIMIT = BigNumber.from(78000);

export const WRAP_FROM_ETH_GAS_LIMIT = 100000;
export const WRAP_GAS_LIMIT = 140000;
export const WRAP_GAS_LIMIT_GOERLI = 120000;
export const UNWRAP_GAS_LIMIT = 115000;
export const WRAP_FROM_ETH_GAS_LIMIT = BigNumber.from(100000);
export const WRAP_GAS_LIMIT = BigNumber.from(140000);
export const WRAP_GAS_LIMIT_GOERLI = BigNumber.from(120000);
export const UNWRAP_GAS_LIMIT = BigNumber.from(115000);
2 changes: 1 addition & 1 deletion features/stake/stake-form/stake-form-context/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export type StakeFormNetworkData = {
};

export type StakeFormValidationContext = {
active: boolean;
isWalletActive: boolean;
stakingLimitLevel: LIMIT_LEVEL;
currentStakeLimit: BigNumber;
gasCost: BigNumber;
Expand Down
61 changes: 14 additions & 47 deletions features/stake/stake-form/stake-form-context/validation.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { useMemo } from 'react';
import invariant from 'tiny-invariant';
import { formatEther } from '@ethersproject/units';
import { useWeb3 } from 'reef-knot/web3-react';
import { Zero } from '@ethersproject/constants';

import { validateEtherAmount } from 'shared/hook-form/validation/validate-ether-amount';
import { VALIDATION_CONTEXT_TIMEOUT } from 'features/withdrawals/withdrawals-constants';
import { handleResolverValidationError } from 'shared/hook-form/validation/validation-error';
import { validateBignumberMax } from 'shared/hook-form/validation/validate-bignumber-max';
import { validateStakeLimit } from 'shared/hook-form/validation/validate-stake-limit';
import { awaitWithTimeout } from 'utils/await-with-timeout';
import { useAwaiter } from 'shared/hooks/use-awaiter';

Expand All @@ -18,6 +15,7 @@ import type {
StakeFormNetworkData,
StakeFormValidationContext,
} from './types';
import { validateStakeEth } from 'shared/hook-form/validation/validate-stake-eth';

export const stakeFormValidationResolver: Resolver<
StakeFormInput,
Expand All @@ -33,7 +31,7 @@ export const stakeFormValidationResolver: Resolver<
validateEtherAmount('amount', amount, 'ETH');

const {
active,
isWalletActive,
stakingLimitLevel,
currentStakeLimit,
etherBalance,
Expand All @@ -44,49 +42,18 @@ export const stakeFormValidationResolver: Resolver<
VALIDATION_CONTEXT_TIMEOUT,
);

validateStakeLimit('amount', stakingLimitLevel);

if (active) {
validateBignumberMax(
'amount',
amount,
etherBalance,
`Entered ETH amount exceeds your available balance of ${formatEther(
etherBalance,
)}`,
);

validateBignumberMax(
'amount',
amount,
currentStakeLimit,
`Entered ETH amount exceeds current staking limit of ${formatEther(
currentStakeLimit,
)}`,
);

if (!isMultisig) {
const gasPaddedBalance = etherBalance.sub(gasCost);

validateBignumberMax(
'amount',
Zero,
gasPaddedBalance,
`Ensure you have sufficient ETH to cover the gas cost of ${formatEther(
gasCost,
)}`,
);
validateStakeEth({
formField: 'amount',
amount,
isWalletActive,
stakingLimitLevel,
currentStakeLimit,
etherBalance,
gasCost,
isMultisig,
});

validateBignumberMax(
'amount',
amount,
gasPaddedBalance,
`Enter ETH amount less than ${formatEther(
gasPaddedBalance,
)} to ensure you leave enough ETH for gas fees`,
);
}
} else {
if (!isWalletActive) {
return {
values,
errors: { referral: 'wallet not connected' },
Expand Down Expand Up @@ -114,7 +81,7 @@ export const useStakeFormValidationContext = (
(!active || (etherBalance && gasCost && isMultisig !== undefined))
) {
return {
active,
isWalletActive: active,
stakingLimitLevel: stakingLimitInfo.stakeLimitLevel,
currentStakeLimit: stakingLimitInfo.currentStakeLimit,
// condition above guaranties stubs will only be passed when active = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
import { ClaimFormHelperState, useHelperState } from './use-helper-state';
import { useClaimData } from 'features/withdrawals/contexts/claim-data-context';
import { useTransactionModal } from 'shared/transaction-modal';
import { useWeb3 } from 'reef-knot/web3-react';

type ClaimFormDataContextValueType = {
onSubmit: FormEventHandler<HTMLFormElement>;
Expand All @@ -39,6 +40,7 @@ export const useClaimFormData = () => {

export const ClaimFormProvider: FC<PropsWithChildren> = ({ children }) => {
const { dispatchModalState } = useTransactionModal();
const { active } = useWeb3();
const { data } = useClaimData();

const [shouldReset, setShouldReset] = useState<boolean>(false);
Expand All @@ -49,7 +51,7 @@ export const ClaimFormProvider: FC<PropsWithChildren> = ({ children }) => {
const formObject = useForm<ClaimFormInputType, ClaimFormValidationContext>({
defaultValues: getDefaultValues,
resolver: claimFormValidationResolver,
context: { maxSelectedRequestCount },
context: { maxSelectedRequestCount, isWalletActive: active },
mode: 'onChange',
reValidateMode: 'onChange',
});
Expand Down
1 change: 1 addition & 0 deletions features/withdrawals/claim/claim-form-context/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {

export type ClaimFormValidationContext = {
maxSelectedRequestCount: number;
isWalletActive: boolean;
};

export type ClaimFormInputType = {
Expand Down
12 changes: 11 additions & 1 deletion features/withdrawals/claim/claim-form-context/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const claimFormValidationResolver: Resolver<
> = async ({ requests }, context) => {
invariant(context);
try {
const { maxSelectedRequestCount } = context;
const { maxSelectedRequestCount, isWalletActive } = context;
const selectedTokens = requests
.filter((r) => r.checked)
.map((r) => r.status as RequestStatusClaimable);
Expand All @@ -27,6 +27,16 @@ export const claimFormValidationResolver: Resolver<
`Cannot claim more than ${maxSelectedRequestCount} requests at once`,
);

if (!isWalletActive) {
return {
values: {
requests,
selectedTokens,
},
errors: { selectedTokens: 'no wallet connected' },
};
}

return {
values: {
requests,
Expand Down
10 changes: 5 additions & 5 deletions features/withdrawals/claim/form/requests-list/requests-empty.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useWeb3 } from 'reef-knot/web3-react';

import { EmptyText, WrapperEmpty } from './styles';

export const RequestsEmpty = () => {
const { active } = useWeb3();
type RequestsEmptyProps = {
isWalletConnected?: boolean;
};

if (!active) {
export const RequestsEmpty = ({ isWalletConnected }: RequestsEmptyProps) => {
if (!isWalletConnected) {
return (
<WrapperEmpty>
<EmptyText>Connect wallet to see your withdrawal requests</EmptyText>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import { Wrapper } from './styles';
import { RequestsLoader } from './requests-loader';
import { useFieldArray, useFormContext, useFormState } from 'react-hook-form';
import { ClaimFormInputType } from '../../claim-form-context';
import { useWeb3 } from 'reef-knot/web3-react';

export const RequestsList: React.FC = () => {
const { active } = useWeb3();
const { isLoading } = useFormState<ClaimFormInputType>();
const { register } = useFormContext<ClaimFormInputType>();
const { fields } = useFieldArray<ClaimFormInputType, 'requests'>({
Expand All @@ -16,8 +18,8 @@ export const RequestsList: React.FC = () => {
return <RequestsLoader />;
}

if (fields.length === 0) {
return <RequestsEmpty />;
if (!active || fields.length === 0) {
return <RequestsEmpty isWalletConnected={active} />;
}

return (
Expand Down
35 changes: 18 additions & 17 deletions features/withdrawals/hooks/useEthAmountByStethWsteth.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
import { parseEther } from '@ethersproject/units';
import { BigNumber } from 'ethers';
import { useMemo } from 'react';
import { useContractSWR, useWSTETHContractRPC } from '@lido-sdk/react';

import { useStethByWsteth } from 'shared/hooks';
import { isValidEtherValue } from 'utils/isValidEtherValue';
import { STRATEGY_LAZY } from 'utils/swrStrategies';

type useEthAmountByInputProps = {
isSteth: boolean;
input?: string;
amount: BigNumber | null;
};

export const useEthAmountByStethWsteth = ({
isSteth,
input,
amount,
}: useEthAmountByInputProps) => {
const isValidValue =
input && !isNaN(Number(input)) && isValidEtherValue(input);
const inputBN = useMemo(
() => (isValidValue ? parseEther(input) : BigNumber.from(0)),
[input, isValidValue],
);
const wsteth = isSteth ? null : amount;
const { data: stethByWstethBalance, loading } = useContractSWR({
contract: useWSTETHContractRPC(),
method: 'getStETHByWstETH',
params: [wsteth],
shouldFetch: !!wsteth,
config: STRATEGY_LAZY,
});

const stethByWstethBalance = useStethByWsteth(isSteth ? undefined : inputBN);

if (!isValidValue) return undefined;
if (isSteth) return inputBN;
return stethByWstethBalance;
if (isSteth)
return {
amount: amount ?? undefined,
loading: false,
};
else return { amount: stethByWstethBalance, loading };
};
11 changes: 10 additions & 1 deletion features/withdrawals/hooks/useWithdrawalRates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { STRATEGY_LAZY } from 'utils/swrStrategies';
import { RequestFormInputType } from '../request/request-form-context';
import { getOpenOceanRate } from 'utils/get-open-ocean-rate';
import { standardFetcher } from 'utils/standardFetcher';
import { FetcherError } from 'utils/fetcherError';

type GetWithdrawalRateParams = {
amount: BigNumber;
Expand All @@ -27,6 +28,7 @@ type SingleWithdrawalRateResult = {
name: string;
rate: number | null;
toReceive: BigNumber | null;
displayEmpty?: boolean;
};

type GetRateType = (
Expand All @@ -50,6 +52,8 @@ const calculateRateReceive = (
};

const getOpenOceanWithdrawalRate: GetRateType = async ({ amount, token }) => {
let displayEmpty = false;

if (amount && amount.gt(Zero)) {
try {
const rate = await getOpenOceanRate(amount, token, 'ETH');
Expand All @@ -58,6 +62,7 @@ const getOpenOceanWithdrawalRate: GetRateType = async ({ amount, token }) => {
...rate,
};
} catch (e) {
displayEmpty = e instanceof FetcherError && e.status < 500;
console.warn('[getOpenOceanRate] Failed to receive withdraw rate', e);
}
}
Expand All @@ -66,6 +71,7 @@ const getOpenOceanWithdrawalRate: GetRateType = async ({ amount, token }) => {
name: 'openOcean',
rate: null,
toReceive: null,
displayEmpty,
};
};

Expand All @@ -78,6 +84,7 @@ type ParaSwapPriceResponsePartial = {

const getParaSwapRate: GetRateType = async ({ amount, token }) => {
let rateInfo: RateCalculationResult | null;
let displayEmpty = false;

try {
if (amount.isZero() || amount.isNegative()) {
Expand Down Expand Up @@ -111,14 +118,16 @@ const getParaSwapRate: GetRateType = async ({ amount, token }) => {
BigNumber.from(data.priceRoute.srcAmount),
BigNumber.from(data.priceRoute.destAmount),
);
} catch {
} catch (e) {
rateInfo = null;
displayEmpty = e instanceof FetcherError && e.status < 500;
}

return {
name: 'paraswap',
rate: rateInfo?.rate ?? null,
toReceive: rateInfo?.toReceive ?? null,
displayEmpty,
};
};

Expand Down
4 changes: 2 additions & 2 deletions features/withdrawals/request/form/options/dex-options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@ export const DexOptions: React.FC<
useWithdrawalRates();

const dexesFiltered = useMemo(() => {
return data?.filter(({ rate, name }) => {
return data?.filter(({ rate, name, displayEmpty }) => {
const dex = dexInfo[name];
return dex && (amount.eq('0') || rate !== null);
return dex && (amount.eq('0') || rate !== null || displayEmpty);
});
}, [amount, data]);

Expand Down
Loading

0 comments on commit 894f740

Please sign in to comment.