Skip to content

Commit

Permalink
✨Created SwapPath component
Browse files Browse the repository at this point in the history
  • Loading branch information
MattPoblete committed Aug 29, 2024
1 parent 5e8c8a8 commit 47a38b9
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 184 deletions.
129 changes: 14 additions & 115 deletions src/components/Swap/AdvancedSwapDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,24 @@
import { BodySmall, LabelSmall } from 'components/Text';
import React from 'react';
import { BodySmall, } from 'components/Text';
import { Box, styled } from 'soroswap-ui';
import { ChevronRight } from '@mui/icons-material';
import { useSorobanReact } from '@soroban-react/core';
import Column from 'components/Column';
import { LoadingRows } from 'components/Loader/styled';
import CurrencyLogo from 'components/Logo/CurrencyLogo';
import Row, { RowBetween, RowFixed } from 'components/Row';
import { RowBetween, RowFixed } from 'components/Row';
import { Separator } from 'components/SearchModal/styleds';
import { MouseoverTooltip } from 'components/Tooltip';
import { formatTokenAmount } from 'helpers/format';
import { useAllTokens } from 'hooks/tokens/useAllTokens';
import { findToken } from 'hooks/tokens/useToken';
import React, { useEffect, useState } from 'react';
import { Percent } from 'soroswap-router-sdk';
import { InterfaceTrade, PlatformType } from 'state/routing/types';
import SwapPathComponent from './SwapPathComponent';
import { InterfaceTrade } from 'state/routing/types';

export const PathBox = styled(Box)`
display: flex;
align-items: end;
justify-content: center;
flex-direction: column;
`;

interface AdvancedSwapDetailsProps {
export interface AdvancedSwapDetailsProps {
trade: InterfaceTrade | undefined;
allowedSlippage: number;
syncing?: boolean;
networkFees: number | null;
}
interface distributionData {
path: string[];
parts: number;
}

export function TextWithLoadingPlaceholder({
syncing,
Expand Down Expand Up @@ -67,6 +54,13 @@ export const formattedPriceImpact = (priceImpact: Percent | Number | undefined)
return `~${priceImpact?.toFixed(2)}%`;
};

export const FormattedProtocolName = (protocol: string) => {
return protocol.charAt(0).toUpperCase() + protocol.slice(1);
}
export const calculatePercentage = (parts: number, totalParts: number) => {
return (parts / totalParts) * 100;
}

export function AdvancedSwapDetails({
trade,
allowedSlippage,
Expand All @@ -76,66 +70,8 @@ export function AdvancedSwapDetails({
// const { chainId } = useWeb3React()
// const nativeCurrency = useNativeCurrency(chainId)
// const txCount = getTransactionCount(trade)
const sorobanContext = useSorobanReact();
const { tokensAsMap, isLoading } = useAllTokens();

const [pathArray, setPathArray] = useState<string[]>([]);
const [distributionArray, setDistributionArray] = useState<distributionData[]>([]);
const [totalParts, setTotalParts] = useState<number>(0);
const [pathTokensIsLoading, setPathTokensIsLoading] = useState(false);

const calculatePercentage = (parts: number) => {
return (parts / totalParts) * 100;
}

useEffect(() => {
(async () => {
if (!trade?.path || isLoading) return;
if (trade.platform == PlatformType.ROUTER) {
setPathTokensIsLoading(true);
const promises = trade.path.map(async (contract) => {
const asset = await findToken(contract, tokensAsMap, sorobanContext);
const code = asset?.code == 'native' ? 'XLM' : asset?.code;
return code;
});
const results = await Promise.allSettled(promises);

const fulfilledValues = results
.filter((result) => result.status === 'fulfilled' && result.value)
.map((result) => (result.status === 'fulfilled' && result.value ? result.value : ''));
setPathArray(fulfilledValues);
setPathTokensIsLoading(false);
} else if (trade.platform == PlatformType.STELLAR_CLASSIC) {
setPathTokensIsLoading(true);
const codes = trade.path.map((address) => {
if (address == 'native') return 'XLM';
return address.split(':')[0];
});
setPathArray(codes);
setPathTokensIsLoading(false);
} else if (trade.platform == PlatformType.AGGREGATOR) {
if (!trade?.distribution) return;
let tempDistributionArray: distributionData[] = [];
setPathTokensIsLoading(true);
for (let distribution of trade?.distribution) {
const promises = distribution.path.map(async (contract) => {
const asset = await findToken(contract, tokensAsMap, sorobanContext);
const code = asset?.code == 'native' ? 'XLM' : asset?.code;
return code;
});
const results = await Promise.allSettled(promises);
const fulfilledValues = results
.filter((result) => result.status === 'fulfilled' && result.value)
.map((result) => (result.status === 'fulfilled' && result.value ? result.value : ''));
tempDistributionArray.push({ path: fulfilledValues, parts: distribution.parts });
setDistributionArray(tempDistributionArray);
setTotalParts(tempDistributionArray.reduce((acc, curr) => acc + curr.parts, 0));
setPathTokensIsLoading(false);
}
}
})();
}, [trade?.path, isLoading, sorobanContext]);

return (
<Column gap="md">
<Separator />
Expand Down Expand Up @@ -188,44 +124,7 @@ export function AdvancedSwapDetails({
</BodySmall>
</TextWithLoadingPlaceholder>
</RowBetween>
{
<RowBetween sx={{ alignItems: 'start' }}>
<RowFixed>
<MouseoverTooltip
title={`
Routing through these assets resulted in the best price for your trade
`}
>
<BodySmall color="textSecondary">{trade?.platform == PlatformType.AGGREGATOR && distributionArray.length > 1 ? 'Paths:' : 'Path'}</BodySmall>
</MouseoverTooltip>
</RowFixed>
<TextWithLoadingPlaceholder syncing={pathTokensIsLoading} width={100}>
<PathBox data-testid="swap__details__path">
{(trade?.platform == PlatformType.ROUTER || trade?.platform == PlatformType.STELLAR_CLASSIC) && pathArray?.map((contract, index) => (
<React.Fragment key={index}>
{contract}
{index !== pathArray.length - 1 && <ChevronRight style={{ opacity: '50%' }} />}
</React.Fragment>
))}
{trade?.platform == PlatformType.AGGREGATOR && distributionArray.map((distribution, index) => (
<Box key={index}>
<Row>
{distribution.path.map((symbol, index) => (
<React.Fragment key={index}>
<LabelSmall fontWeight={100}>{symbol}</LabelSmall>
{index !== distribution.path.length - 1 && (
<ChevronRight style={{ opacity: '50%' }} />
)}
</React.Fragment>
))}
<LabelSmall fontWeight={100} sx={{ ml: 1 }}>({calculatePercentage(distribution.parts)}%)</LabelSmall>
</Row>
</Box>
))}
</PathBox>
</TextWithLoadingPlaceholder>
</RowBetween>
}
<SwapPathComponent trade={trade} />
{trade?.platform && (
<RowBetween>
<MouseoverTooltip title={'The platform where the swap will be made.'}>
Expand Down
77 changes: 8 additions & 69 deletions src/components/Swap/SwapModalFooter.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
import { CircularProgress, styled, useTheme } from 'soroswap-ui';
import { useSorobanReact } from '@soroban-react/core';
import BigNumber from 'bignumber.js';
import { styled, useTheme } from 'soroswap-ui';
import { ButtonError, SmallButtonPrimary } from 'components/Buttons/Button';
import Column from 'components/Column';
import CurrencyLogo from 'components/Logo/CurrencyLogo';
import Row, { AutoRow, RowBetween, RowFixed } from 'components/Row';
import { BodySmall, HeadlineSmall, SubHeaderSmall } from 'components/Text';
import { MouseoverTooltip } from 'components/Tooltip';
import { getPriceImpactNew2 } from 'functions/getPriceImpact';
import { formatTokenAmount, twoDecimalsPercentage } from 'helpers/format';
import { useAllTokens } from 'hooks/tokens/useAllTokens';
import { findToken } from 'hooks/tokens/useToken';
import useGetReservesByPair from 'hooks/useGetReservesByPair';
import { formatTokenAmount } from 'helpers/format';
import { getSwapAmounts } from 'hooks/useSwapCallback';
import React, { ReactNode, useEffect, useState } from 'react';
import { AlertTriangle, ChevronRight } from 'react-feather';
import { InterfaceTrade, PlatformType, TradeType } from 'state/routing/types';
import { PathBox, TextWithLoadingPlaceholder, formattedPriceImpact } from './AdvancedSwapDetails';
import React, { ReactNode } from 'react';
import { AlertTriangle } from 'react-feather';
import { InterfaceTrade, TradeType } from 'state/routing/types';
import { formattedPriceImpact } from './AdvancedSwapDetails';
import { Label } from './SwapModalHeaderAmount';
import { getExpectedAmountOfOne } from './TradePrice';
import { SwapCallbackError, SwapShowAcceptChanges } from './styleds';
import SwapPathComponent from './SwapPathComponent';

const DetailsContainer = styled(Column)`
padding: 0 8px;
Expand Down Expand Up @@ -77,13 +72,10 @@ export default function SwapModalFooter({
// const routes = isClassicTrade(trade) ? getRoutingDiagramEntries(trade) : undefined
// const { chainId } = useWeb3React()
// const nativeCurrency = useNativeCurrency(chainId)
const { tokensAsMap, isLoading } = useAllTokens();

const label = `${trade?.inputAmount?.currency.code}`;
const labelInverted = `${trade?.outputAmount?.currency.code}`;

const sorobanContext = useSorobanReact();

const getSwapValues = () => {
if (!trade || !trade?.tradeType) return { formattedAmount0: '0', formattedAmount1: '0' };

Expand All @@ -100,39 +92,6 @@ export default function SwapModalFooter({
return { formattedAmount0, formattedAmount1 };
};

const [pathArray, setPathArray] = useState<string[]>([]);

const [pathTokensIsLoading, setPathTokensIsLoading] = useState(false);

useEffect(() => {
(async () => {
if (!trade?.path || isLoading) return;
if (trade.platform == PlatformType.ROUTER) {
setPathTokensIsLoading(true);
const promises = trade.path.map(async (contract) => {
const asset = await findToken(contract, tokensAsMap, sorobanContext);
const code = asset?.code == 'native' ? 'XLM' : asset?.code;
return code;
});
const results = await Promise.allSettled(promises);

const fulfilledValues = results
.filter((result) => result.status === 'fulfilled' && result.value)
.map((result) => (result.status === 'fulfilled' && result.value ? result.value : ''));
setPathArray(fulfilledValues);
setPathTokensIsLoading(false);
} else if (trade.platform == PlatformType.STELLAR_CLASSIC) {
setPathTokensIsLoading(true);
const codes = trade.path.map((address) => {
if (address == "native") return "XLM"
return address.split(":")[0]
})
setPathArray(codes);
setPathTokensIsLoading(false);
}
})();
}, [trade?.path, isLoading, sorobanContext]);

return (
<>
<DetailsContainer gap="md">
Expand Down Expand Up @@ -205,27 +164,7 @@ export default function SwapModalFooter({
</DetailRowValue>
</Row>
</BodySmall>
<RowBetween>
<RowFixed>
<MouseoverTooltip
title={`
Routing through these assets resulted in the best price for your trade
`}
>
<Label cursor="help">Path</Label>
</MouseoverTooltip>
</RowFixed>
<TextWithLoadingPlaceholder syncing={pathTokensIsLoading} width={100}>
<PathBox>
{pathArray?.map((contract, index) => (
<React.Fragment key={index}>
{contract}
{index !== pathArray.length - 1 && <ChevronRight style={{ opacity: '50%' }} />}
</React.Fragment>
))}
</PathBox>
</TextWithLoadingPlaceholder>
</RowBetween>
<SwapPathComponent trade={trade} />
{trade?.platform && (
<RowBetween>
<MouseoverTooltip title={'The platform where the swap will be made.'}>
Expand Down
Loading

0 comments on commit 47a38b9

Please sign in to comment.