Skip to content

Commit

Permalink
Merge pull request #208 from lidofinance/feature/si-1177-return-paras…
Browse files Browse the repository at this point in the history
…wap-to-aggregators-page

feat: paraswap withdrawal aggregator
  • Loading branch information
itaven authored Jan 22, 2024
2 parents fb53558 + da176f6 commit 281d6f9
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 3 deletions.
80 changes: 78 additions & 2 deletions features/withdrawals/hooks/useWithdrawalRates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,26 @@ import { useWatch } from 'react-hook-form';
import { BigNumber } from 'ethers';

import { Zero } from '@ethersproject/constants';
import { TOKENS } from '@lido-sdk/constants';
import { CHAINS, getTokenAddress, TOKENS } from '@lido-sdk/constants';
import { useLidoSWR } from '@lido-sdk/react';

import { useDebouncedValue } from 'shared/hooks/useDebouncedValue';
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';

type GetWithdrawalRateParams = {
amount: BigNumber;
token: TOKENS.STETH | TOKENS.WSTETH;
};

type RateCalculationResult = {
rate: number;
toReceive: BigNumber;
};

type SingleWithdrawalRateResult = {
name: string;
rate: number | null;
Expand All @@ -29,6 +35,20 @@ type GetRateType = (

type GetWithdrawalRateResult = SingleWithdrawalRateResult[];

const RATE_PRECISION = 100000;
const RATE_PRECISION_BN = BigNumber.from(RATE_PRECISION);

const calculateRateReceive = (
amount: BigNumber,
src: BigNumber,
dest: BigNumber,
): RateCalculationResult => {
const _rate = dest.mul(RATE_PRECISION_BN).div(src);
const toReceive = amount.mul(dest).div(src);
const rate = _rate.toNumber() / RATE_PRECISION;
return { rate, toReceive };
};

const getOpenOceanWithdrawalRate: GetRateType = async ({ amount, token }) => {
if (amount && amount.gt(Zero)) {
try {
Expand All @@ -49,10 +69,66 @@ const getOpenOceanWithdrawalRate: GetRateType = async ({ amount, token }) => {
};
};

type ParaSwapPriceResponsePartial = {
priceRoute: {
srcAmount: string;
destAmount: string;
};
};

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

try {
if (amount.isZero() || amount.isNegative()) {
return {
name: 'paraswap',
rate: 0,
toReceive: BigNumber.from(0),
};
}
const capped_amount = amount;
const api = `https://apiv5.paraswap.io/prices`;
const query = new URLSearchParams({
srcToken: getTokenAddress(CHAINS.Mainnet, token),
srcDecimals: '18',
destToken: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE',
destDecimals: '18',
side: 'SELL',
excludeDirectContractMethods: 'true',
userAddress: '0x0000000000000000000000000000000000000000',
amount: capped_amount.toString(),
network: '1',
partner: 'lido',
});

const url = `${api}?${query.toString()}`;
const data: ParaSwapPriceResponsePartial =
await standardFetcher<ParaSwapPriceResponsePartial>(url);

rateInfo = calculateRateReceive(
amount,
BigNumber.from(data.priceRoute.srcAmount),
BigNumber.from(data.priceRoute.destAmount),
);
} catch {
rateInfo = null;
}

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

const getWithdrawalRates = async (
params: GetWithdrawalRateParams,
): Promise<GetWithdrawalRateResult> => {
const rates = await Promise.all([getOpenOceanWithdrawalRate(params)]);
const rates = await Promise.all([
getOpenOceanWithdrawalRate(params),
getParaSwapRate(params),
]);

if (rates.length > 1) {
// sort by rate, then alphabetic
Expand Down
17 changes: 16 additions & 1 deletion features/withdrawals/request/form/options/dex-options.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BigNumber } from 'ethers';
import { TOKENS } from '@lido-sdk/constants';
import { CHAINS, getTokenAddress, TOKENS } from '@lido-sdk/constants';

import { useMemo } from 'react';
import { useWithdrawalRates } from 'features/withdrawals/hooks/useWithdrawalRates';
Expand All @@ -18,6 +18,7 @@ import {
InlineLoaderSmall,
DexOptionLoader,
OpenOceanIcon,
ParaSwapIcon,
DexWarning,
} from './styles';
import { formatEther } from '@ethersproject/units';
Expand Down Expand Up @@ -46,6 +47,20 @@ const dexInfo: {
amount,
)}#/ETH/${token}/ETH`,
},
paraswap: {
title: 'ParaSwap',
icon: <ParaSwapIcon />,
onClickGoTo: () => {
trackMatomoEvent(MATOMO_CLICK_EVENTS_TYPES.withdrawalGoToParaswap);
},
link: (amount, token) =>
`https://app.paraswap.io/?referrer=Lido&takeSurplus=true#/${getTokenAddress(
CHAINS.Mainnet,
token,
)}-0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE/${formatEther(
amount,
)}/SELL?network=ethereum`,
},
};

type DexOptionProps = {
Expand Down
2 changes: 2 additions & 0 deletions features/withdrawals/request/form/options/options-picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
OptionsPickerRow,
OptionsPickerSubLabel,
OpenOceanIcon,
ParaSwapIcon,
} from './styles';
import {
trackMatomoEvent,
Expand Down Expand Up @@ -88,6 +89,7 @@ const DexButton: React.FC<OptionButtonProps> = ({ isActive, onClick }) => {
<OptionsPickerLabel>Use aggregators</OptionsPickerLabel>
<OptionsPickerIcons>
<OpenOceanIcon />
<ParaSwapIcon />
</OptionsPickerIcons>
</OptionsPickerRow>
<OptionsPickerRow data-testid="dexBestRate">
Expand Down
8 changes: 8 additions & 0 deletions features/withdrawals/request/form/options/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { FormatToken } from 'shared/formatters';
import Lido from 'assets/icons/lido.svg';
import OpenOcean from 'assets/icons/open-ocean.svg';
import ExternalLink from 'assets/icons/external-link-icon.svg';
import Paraswap from 'assets/icons/paraswap-circle.svg';

// ICONS

Expand All @@ -22,6 +23,13 @@ export const OpenOceanIcon = styled.img.attrs({
display: block;
`;

export const ParaSwapIcon = styled.img.attrs({
src: Paraswap,
alt: 'paraswap',
})`
display: block;
`;

export const OptionAmountRow = styled.div`
display: flex;
align-items: center;
Expand Down

0 comments on commit 281d6f9

Please sign in to comment.