From 0bdaf42b6fe90f3a5b764909650fa00ce0b44a50 Mon Sep 17 00:00:00 2001 From: Berteotti Date: Thu, 24 Oct 2024 16:36:03 +0700 Subject: [PATCH] feat: editable slippage --- app/components/ConfirmTrade.tsx | 9 +++--- app/components/Swapbox.tsx | 46 +++++++++++++++++++++++++---- app/components/TransactionModal.tsx | 3 +- context/SlippageContext.tsx | 29 ++++++++++++++++++ context/index.ts | 1 + providers/providers.tsx | 6 ++-- 6 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 context/SlippageContext.tsx diff --git a/app/components/ConfirmTrade.tsx b/app/components/ConfirmTrade.tsx index ae4ede8f..ecbfde39 100644 --- a/app/components/ConfirmTrade.tsx +++ b/app/components/ConfirmTrade.tsx @@ -13,7 +13,7 @@ import { successToast, toast, } from '@swapr/ui'; -import { SLIPPAGE, SwapDirection, SwapState } from '.'; +import { SwapDirection, SwapState } from '.'; import MarketABI from '@/abi/market.json'; import { CONDITIONAL_TOKEN_CONTRACT_ADDRESS, @@ -22,7 +22,7 @@ import { import ConditionalTokensABI from '@/abi/conditionalTokens.json'; import { addFraction, removeFraction } from '@/utils/price'; import { Abi, Address, erc20Abi, formatEther, parseEther } from 'viem'; -import { useTx } from '@/context'; +import { useSlippage, useTx } from '@/context'; import { Outcome, Token } from '@/entities'; import { formatEtherWithFixedDecimals, shortenAddress } from '@/utils'; import { @@ -61,6 +61,7 @@ export const ConfirmTrade = ({ const { isModalOpen, closeModal } = useModal(); const { submitTx } = useTx(); const [isApproving, setIsApproving] = useState(false); + const { slippage } = useSlippage(); useEffect(() => { if (!swapState.isAllowed) { @@ -199,7 +200,7 @@ export const ConfirmTrade = ({ if (!tokenAmountOut || !sellAmount) return; const roundedAmountOut = removeFraction(tokenAmountOut, ROUNDING_PRECISON); - const maxSellAmount = addFraction(sellAmount as bigint, SLIPPAGE); + const maxSellAmount = addFraction(sellAmount as bigint, slippage); submitTx({ abi: MarketABI as Abi, @@ -263,7 +264,7 @@ export const ConfirmTrade = ({

Slippage

-

{SLIPPAGE * 100}%

+

{slippage * 100}%

diff --git a/app/components/Swapbox.tsx b/app/components/Swapbox.tsx index 6fa61496..3af6bd45 100644 --- a/app/components/Swapbox.tsx +++ b/app/components/Swapbox.tsx @@ -1,6 +1,14 @@ 'use client'; -import { Button, IconButton } from '@swapr/ui'; +import { + Button, + IconButton, + Popover, + PopoverContent, + PopoverTrigger, + ToggleGroup, + ToggleGroupOption, +} from '@swapr/ui'; import { SwapInput } from './ui/SwapInput'; import { useEffect, useState } from 'react'; import { parseEther, Address, formatEther } from 'viem'; @@ -31,8 +39,8 @@ import { gnosis } from 'viem/chains'; import { formatEtherWithFixedDecimals, formatValueWithFixedDecimals } from '@/utils'; import { useQuery } from '@tanstack/react-query'; import { getTokenUSDPrice } from '@/queries/mobula'; +import { useSlippage } from '@/context'; -export const SLIPPAGE = 0.01; const ONE_UNIT = '1'; export enum SwapDirection { @@ -73,6 +81,7 @@ export const Swapbox = ({ fixedProductMarketMaker }: SwapboxProps) => { const { address, isDisconnected, chainId: connectorChainId } = useAccount(); const supportedChains = useChains(); const { openModal } = useModal(); + const { slippage } = useSlippage(); const [tokenAmountIn, setTokenAmountIn] = useState(''); const [tokenAmountOut, setTokenAmountOut] = useState(); @@ -137,8 +146,7 @@ export const Swapbox = ({ fixedProductMarketMaker }: SwapboxProps) => { useEffect(() => { if (isBuying) { if (!buyAmount) return; - - const amountOut = removeFraction(buyAmount as bigint, SLIPPAGE); + const amountOut = removeFraction(buyAmount as bigint, slippage); setTokenAmountOut(amountOut); } else { @@ -162,6 +170,7 @@ export const Swapbox = ({ fixedProductMarketMaker }: SwapboxProps) => { isBuying, outcome.index, tokenAmountIn, + slippage, ]); useEffect(() => { @@ -337,7 +346,10 @@ export const Swapbox = ({ fixedProductMarketMaker }: SwapboxProps) => {

Slippage

-

{SLIPPAGE * 100}%

+
+

{slippage * 100}%

+ +
{potentialProfit && (
@@ -398,3 +410,27 @@ export const Swapbox = ({ fixedProductMarketMaker }: SwapboxProps) => { ); }; + +const SlippageSettings = () => { + const { slippage, updateSlippage } = useSlippage(); + + return ( + + + + + +
+
+

Slippage tolerance

+
+ + 0.01% + 0.1% + 1% + +
+
+
+ ); +}; diff --git a/app/components/TransactionModal.tsx b/app/components/TransactionModal.tsx index 276f2d04..ef52c6e7 100644 --- a/app/components/TransactionModal.tsx +++ b/app/components/TransactionModal.tsx @@ -102,7 +102,8 @@ export const TransactionModal = ({ variant="pastel" size="lg" > - View in explorer +

View in explorer

+ diff --git a/context/SlippageContext.tsx b/context/SlippageContext.tsx new file mode 100644 index 00000000..29d9f58c --- /dev/null +++ b/context/SlippageContext.tsx @@ -0,0 +1,29 @@ +import { PropsWithChildren, createContext, useContext, useState } from 'react'; + +export interface SlippageContextProps { + slippage: number; + updateSlippage: (slippage: number) => void; +} + +const DEFAULT_SLIPPAGE = 0.0001; + +const SlippageContext = createContext({ + slippage: DEFAULT_SLIPPAGE, + updateSlippage: () => {}, +}); + +export const useSlippage = () => useContext(SlippageContext); + +export const SlippageProvider = ({ children }: PropsWithChildren) => { + const [slippage, setSlippage] = useState(DEFAULT_SLIPPAGE); + + const updateSlippage = (newSlippage: number) => { + setSlippage(newSlippage); + }; + + return ( + + {children} + + ); +}; diff --git a/context/index.ts b/context/index.ts index 36962ff1..ba36df7a 100644 --- a/context/index.ts +++ b/context/index.ts @@ -1,2 +1,3 @@ export * from './ModalContext'; export * from './TxContext'; +export * from './SlippageContext'; diff --git a/providers/providers.tsx b/providers/providers.tsx index d75cc0e4..57ec8585 100644 --- a/providers/providers.tsx +++ b/providers/providers.tsx @@ -7,7 +7,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { config } from './chain-config'; import { ConnectKitProvider, Types } from 'connectkit'; import { ThemeProvider as NextThemesProvider, useTheme } from 'next-themes'; -import { TxProvider, ModalProvider } from '@/context'; +import { TxProvider, ModalProvider, SlippageProvider } from '@/context'; import { useAnalytics } from '@/hooks'; import { Toaster, TooltipProvider } from '@swapr/ui'; @@ -22,10 +22,10 @@ export const Providers = ({ children }: PropsWithChildren) => { + - {children}{' '} - + {children}