Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🚧Add switches to toggle protocols #535

Merged
merged 8 commits into from
Sep 5, 2024
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ cp .env.production.example .env

You have successfully set up Soroswap on your local machine! Start swapping, pooling, and exploring the possibilities of decentralized finance (DeFi) on the Soroban network.

If you want to add or remove supported protocols, you can do so by editing the `functions/generateRoute.ts:79-97` file and adding or removing the protocols you want to support on swap.

> [!HINT]
> You can found the list of supported protocols in the `soroswap-router-sdk` repository.

## 🧪🔨 Testing 🧪🔨
To execute the tests, you must first start the development container. To do this, run the following command from your host machine:

Expand Down
9 changes: 5 additions & 4 deletions src/components/Providers.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { Analytics } from '@vercel/analytics/react';
import { AppContext, AppContextType, ColorModeContext, SnackbarIconType } from 'contexts';
import { CssBaseline, ThemeProvider } from 'soroswap-ui';
import { AppContext, AppContextType, ColorModeContext, SnackbarIconType, ProtocolsStatus } from 'contexts';
import { Provider } from 'react-redux';
import { theme } from 'soroswap-ui';
import { useMemo, useState } from 'react';
import InkathonProvider from 'inkathon/InkathonProvider';
import MainLayout from './Layout/MainLayout';
import MySorobanReactProvider from 'soroban/MySorobanReactProvider';
import store from 'state';
import { SorobanContextType } from '@soroban-react/core';
import { SoroswapThemeProvider } from 'soroswap-ui';

export default function Providers({
children,
sorobanReactProviderProps,
Expand All @@ -20,7 +19,7 @@ export default function Providers({
const [isConnectWalletModal, setConnectWalletModal] = useState<boolean>(false);

const [maxHops, setMaxHops] = useState<number>(2);

const [protocolsStatus, setProtocolsStatus] = useState<ProtocolsStatus[]>([]);
const [openSnackbar, setOpenSnackbar] = useState<boolean>(false);
const [snackbarMessage, setSnackbarMessage] = useState<string>('');
const [snackbarTitle, setSnackbarTitle] = useState<string>('Swapped');
Expand Down Expand Up @@ -54,6 +53,8 @@ export default function Providers({
Settings: {
maxHops,
setMaxHops,
protocolsStatus,
setProtocolsStatus,
},
};

Expand Down
133 changes: 133 additions & 0 deletions src/components/Settings/ProtocolsSettings/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import Expand from 'components/Expand';
import QuestionHelper from 'components/QuestionHelper';
import Row, { RowBetween } from 'components/Row';
import { BodySmall } from 'components/Text';
import { AppContext } from 'contexts';
import { useRouterSDK } from 'functions/generateRoute';
import React, { useContext, useEffect, useState } from 'react'
import { Box, styled, Switch, SwitchProps, Typography, useTheme } from 'soroswap-ui';
import { useSWRConfig } from 'swr';


export const CustomSwitch = styled((props: SwitchProps) => (
<Switch sx={{ my: 1 }} focusVisibleClassName=".Mui-focusVisible" disableRipple {...props} />
))(({ theme }) => ({
width: 42,
height: 26,
padding: 0,
alignContent: 'center',
alignItems: 'center',
'& .MuiSwitch-switchBase': {
padding: 0,
margin: 3,
'&.Mui-checked': {
transform: 'translateX(16px)',
color: '#8866DD',
'& .MuiSwitch-thumb:before': {
backgroundColor: '#8866DD',
borderRadius: 32,
},
'& + .MuiSwitch-track': {
backgroundColor: theme.palette.background.paper,
opacity: 1,
border: 0,
},
},
},
'& .MuiSwitch-thumb': {
backgroundColor: 'rgba(136, 102, 221, 0.25)',
width: 20,
height: 20,
'&:before': {
content: "''",
position: 'absolute',
width: '100%',
height: '100%',
left: 0,
top: 0,
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center',
},
},
'& .MuiSwitch-track': {
borderRadius: 32,
backgroundColor: theme.palette.background.paper,
opacity: 1,
},
}));


const firstLetterUppercase = (string: string) => {
return string.charAt(0).toUpperCase() + string.slice(1);
}
const ProtocolsSettings = () => {
const { resetRouterSdkCache } = useRouterSDK();
const theme = useTheme();
const [isOpen, setIsOpen] = useState<boolean>(false);
const { protocolsStatus, setProtocolsStatus } = useContext(AppContext).Settings;
const { mutate } = useSWRConfig();

const switchProtocolValue = (key: string) => {
const newProtocolsStatus = protocolsStatus.map((protocol) => {
if (protocol.key === key) {
return {
key: protocol.key,
value: !protocol.value,
};
}
return protocol;
});
const hasTrueValue = newProtocolsStatus.some((protocol) => protocol.value);
if (hasTrueValue) {
resetRouterSdkCache();
setProtocolsStatus(newProtocolsStatus);
mutate(
(key: any) => {
return true;
},
undefined,
{ revalidate: true },
);
}
else return;
}

return (

<Expand
testId="protocols-settings"
isOpen={isOpen}
onToggle={() => setIsOpen(!isOpen)}
header={
<Row width="auto">
<Typography color={theme.palette.secondary.main}>Protocols</Typography>
<QuestionHelper
text={
<div>
The protocols Soroswap.finance will use to calculate the most efficient path for your transaction.
</div>
}
/>
</Row>
}
button={<></>}
>
<RowBetween gap="md" width={'100%'}>
<Box sx={{ ml: 2 }} width={'100%'} >
{protocolsStatus.map((option, index) => {
return (
<Row key={index} gap="4px" justify='space-between' align='center'>
<BodySmall fontWeight={100} color={theme.palette.secondary.main} >{firstLetterUppercase(option.key)}</BodySmall>
<CustomSwitch checked={option.value} onClick={() => { switchProtocolValue(option.key) }} color="secondary" />
</Row>
)
})}
</Box>
</RowBetween>

</Expand>

)
}

export default ProtocolsSettings
2 changes: 2 additions & 0 deletions src/components/Settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useRef, useState } from 'react';
import MaxSlippageSettings from './MaxSlippageSettings';
import MenuButton from './MenuButton';
import MaxHopsSettings from './MaxHopsSettings';
import ProtocolsSettings from './ProtocolsSettings';

const Menu = styled('div')`
position: relative;
Expand Down Expand Up @@ -74,6 +75,7 @@ export default function SettingsTab({
<ExpandColumn>
<MaxSlippageSettings autoSlippage={autoSlippage} />
<MaxHopsSettings />
<ProtocolsSettings />
</ExpandColumn>
</AnimatedDropdown>
</MenuFlyout>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Swap/SwapPathComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ function SwapPathComponent({ trade }: { trade: InterfaceTrade | undefined }) {
tempDistributionArray.push({ path: fulfilledValues, parts: distribution.parts, protocol: distribution.protocol_id });
setDistributionArray(tempDistributionArray);
setTotalParts(tempDistributionArray.reduce((acc, curr) => acc + curr.parts, 0));
setPathTokensIsLoading(false);
}
setPathTokensIsLoading(false);
}
})();
}, [trade?.path, isLoading, sorobanContext]);
Expand Down
11 changes: 11 additions & 0 deletions src/contexts/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React from 'react';
import { Protocols } from 'soroswap-router-sdk';
import { PlatformType } from 'state/routing/types';

type ConnectWalletModalType = {
isConnectWalletModalOpen: boolean;
Expand All @@ -13,6 +15,11 @@ export enum SnackbarIconType {
ERROR,
}

export interface ProtocolsStatus {
key: Protocols | PlatformType;
value: boolean;
}

export type SnackbarContextType = {
openSnackbar: boolean;
snackbarMessage: string;
Expand All @@ -27,6 +34,8 @@ export type SnackbarContextType = {
export type Settings = {
maxHops: number;
setMaxHops: React.Dispatch<React.SetStateAction<number>>;
protocolsStatus: ProtocolsStatus[];
setProtocolsStatus: React.Dispatch<React.SetStateAction<ProtocolsStatus[]>>;
};

export type AppContextType = {
Expand Down Expand Up @@ -57,5 +66,7 @@ export const AppContext = React.createContext<AppContextType>({
Settings: {
maxHops: 2,
setMaxHops: () => {},
protocolsStatus: [],
setProtocolsStatus: () => {},
},
});
Loading