diff --git a/README.md b/README.md index 8bda46054b..aac68cae2c 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ [![Discord][discord-badge]][discord-url] -Code Version: `2.3.1`
-Whitepaper Version: `2.3.0` +Code Version: `2.4.1`
+Whitepaper Version: `2.4.0` ## About diff --git a/beanstalk.pdf b/beanstalk.pdf index 758a42c00f..8048e31aab 100644 Binary files a/beanstalk.pdf and b/beanstalk.pdf differ diff --git a/projects/dex-ui/netlify.toml b/projects/dex-ui/netlify.toml new file mode 100644 index 0000000000..b37e2dc770 --- /dev/null +++ b/projects/dex-ui/netlify.toml @@ -0,0 +1,9 @@ +[[redirects]] + from = "/discord" + to = "https://discord.gg/3QcnNe6ZBD" + status = 308 + +[[redirects]] + from = "/*" + to = "index.html" + status = 200 \ No newline at end of file diff --git a/projects/dex-ui/package.json b/projects/dex-ui/package.json index 9d08768996..c331667779 100644 --- a/projects/dex-ui/package.json +++ b/projects/dex-ui/package.json @@ -27,6 +27,7 @@ "connectkit": "1.2.1", "ethers": "^5", "graphql-request": "5.2.0", + "lightweight-charts": "4.0.1", "loadash": "1.0.0", "prettier": "2.7.1", "react": "^18.2.0", diff --git a/projects/dex-ui/public/_redirects b/projects/dex-ui/public/_redirects deleted file mode 100644 index fdde6bce42..0000000000 --- a/projects/dex-ui/public/_redirects +++ /dev/null @@ -1,3 +0,0 @@ -# social - -/discord https://discord.gg/3QcnNe6ZBD \ No newline at end of file diff --git a/projects/dex-ui/src/components/App/App.tsx b/projects/dex-ui/src/components/App/App.tsx index ee1e3658d7..9e867026c6 100644 --- a/projects/dex-ui/src/components/App/App.tsx +++ b/projects/dex-ui/src/components/App/App.tsx @@ -12,8 +12,8 @@ import { Settings } from "src/settings"; import { Liquidity } from "src/pages/Liquidity"; export const App = ({}) => { - const isNotProd = !Settings.PRODUCTION - + const isNotProd = !Settings.PRODUCTION; + return ( diff --git a/projects/dex-ui/src/components/App/Wrapper.tsx b/projects/dex-ui/src/components/App/Wrapper.tsx index 5d527809d5..cbb2867ee9 100644 --- a/projects/dex-ui/src/components/App/Wrapper.tsx +++ b/projects/dex-ui/src/components/App/Wrapper.tsx @@ -27,7 +27,7 @@ export const Wrapper: FC<{}> = ({ children }) => { }} customTheme={{ "--ck-font-family": "PPMori", - "--ck-modal-box-shadow": "0px 0px 0px 2px black", + "--ck-modal-box-shadow": "0px 0px 0px 2px black" }} > diff --git a/projects/dex-ui/src/components/Checkbox.tsx b/projects/dex-ui/src/components/Checkbox.tsx index d04c5b0450..dc07f6bbb4 100644 --- a/projects/dex-ui/src/components/Checkbox.tsx +++ b/projects/dex-ui/src/components/Checkbox.tsx @@ -13,17 +13,17 @@ type Props = { export const Checkbox: FC = ({ label, checked = false, mode, checkboxColor, onClick = () => {} }) => { return ( - + - {label && - - {label} - - } + {label && ( + + {label} + + )} ); @@ -55,25 +55,25 @@ const HiddenCheckbox = styled.input.attrs({ type: "checkbox" })` `; const StyledCheckboxContainer = styled.div` - border: 1px solid ${(props) => (props.checkboxColor && props.checked ? props.checkboxColor : '#000')}; + border: 1px solid ${(props) => (props.checkboxColor && props.checked ? props.checkboxColor : "#000")}; border-radius: 1em; width: 16px; height: 16px; - position: ${(props) => (props.mode === "checkOnly" ? 'relative' : 'absolute')}; - top: ${(props) => (props.mode === "checkOnly" ? '0px' : '2px')}; + position: ${(props) => (props.mode === "checkOnly" ? "relative" : "absolute")}; + top: ${(props) => (props.mode === "checkOnly" ? "0px" : "2px")}; cursor: pointer; `; const Checkmark = styled.div` - border: 1px solid ${(props) => (props.checkboxColor ? props.checkboxColor : '#FFF')}; + border: 1px solid ${(props) => (props.checkboxColor ? props.checkboxColor : "#FFF")}; border-radius: 1em; width: 8px; height: 8px; - position: ${(props) => (props.mode === "checkOnly" ? 'relative' : 'absolute')}; + position: ${(props) => (props.mode === "checkOnly" ? "relative" : "absolute")}; top: 50%; left: 50%; transform: translate(-50%, -50%); - background: ${(props) => (props.checkboxColor ? props.checkboxColor : '#FFF')}; + background: ${(props) => (props.checkboxColor ? props.checkboxColor : "#FFF")}; filter: ${(props) => (props.checkboxColor ? "brightness(100%);" : "brightness(0%);")} opacity: ${(props) => (props.checked ? "1" : "0")}; z-index: 2; @@ -84,14 +84,14 @@ const HoverCheckmark = styled.div` border-radius: 1em; width: 8px; height: 8px; - position: ${(props) => (props.mode === "checkOnly" ? 'relative' : 'absolute')}; + position: ${(props) => (props.mode === "checkOnly" ? "relative" : "absolute")}; top: 50%; left: 50%; transform: translate(-50%, -50%); background: transparent; ${HoverContainer}:hover & { - border: 1px solid ${(props) => (props.checkboxColor ? props.checkboxColor : '#FFF')}; - background: ${(props) => (props.checkboxColor ? props.checkboxColor : '#FFF')}; + border: 1px solid ${(props) => (props.checkboxColor ? props.checkboxColor : "#FFF")}; + background: ${(props) => (props.checkboxColor ? props.checkboxColor : "#FFF")}; filter: brightness(50%); } z-index: 1; diff --git a/projects/dex-ui/src/components/ExpandBox.tsx b/projects/dex-ui/src/components/ExpandBox.tsx index f81419551a..c51c13abee 100644 --- a/projects/dex-ui/src/components/ExpandBox.tsx +++ b/projects/dex-ui/src/components/ExpandBox.tsx @@ -35,7 +35,14 @@ export const ExpandBox: FC & Composition = ({ width = 432, children }) => {open && body} @@ -49,7 +56,7 @@ const Container = styled.div` border-top: 0.5px solid #9ca3af; border-left: 0.5px solid #9ca3af; border-right: 0.5px solid #9ca3af; - border-bottom: ${(p) => p.open ? '0.5px' : '0px'} solid #9caeaf; + border-bottom: ${(p) => (p.open ? "0.5px" : "0px")} solid #9caeaf; width: ${(p) => p.width}px; min-width: ${(p) => p.width}px; cursor: pointer; @@ -57,9 +64,9 @@ const Container = styled.div` border-top: 0.5px solid #46b955; border-left: 0.5px solid #46b955; border-right: 0.5px solid #46b955; - border-bottom: ${(p) => p.open ? '0.5px' : '0px'} solid #46b955; + border-bottom: ${(p) => (p.open ? "0.5px" : "0px")} solid #46b955; outline: 0.5px solid #46b955; - }; + } `; const Header = styled.div` background-color: #f9f8f6; @@ -70,8 +77,8 @@ const Header = styled.div` justify-content: space-between; align-items: center; :hover { - border-bottom: 0.5px solid ${(p) => !p.open ? '#46b955' : '#9ca3af'}; - }; + border-bottom: 0.5px solid ${(p) => (!p.open ? "#46b955" : "#9ca3af")}; + } `; const Body = styled.div` display: flex; diff --git a/projects/dex-ui/src/components/Frame/Footer.tsx b/projects/dex-ui/src/components/Frame/Footer.tsx index 64e3d41be4..17fb04402c 100644 --- a/projects/dex-ui/src/components/Frame/Footer.tsx +++ b/projects/dex-ui/src/components/Frame/Footer.tsx @@ -4,7 +4,9 @@ import { Discord, Github, Twitter } from "../Icons"; export const Footer = () => ( - We are open source. Contribute to this site → + + We are open source. Contribute to this site → + Join the discussion diff --git a/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx b/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx index fcbabacced..16e9a90f51 100644 --- a/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx +++ b/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx @@ -31,7 +31,13 @@ export type AddLiquidityQuote = { estimate: TokenValue; }; -export const AddLiquidity = ({ well, txnCompleteCallback, slippage, slippageSettingsClickHandler, handleSlippageValueChange }: AddLiquidityProps) => { +export const AddLiquidity = ({ + well, + txnCompleteCallback, + slippage, + slippageSettingsClickHandler, + handleSlippageValueChange +}: AddLiquidityProps) => { const { address } = useAccount(); const [amounts, setAmounts] = useState({}); const [balancedMode, setBalancedMode] = useState(true); @@ -41,7 +47,7 @@ export const AddLiquidity = ({ well, txnCompleteCallback, slippage, slippageSett const [prices, setPrices] = useState<(TokenValue | null)[]>([]); const sdk = useSdk(); - const { reserves: wellReserves, refetch: refetchWellReserves } = useWellReserves(well); + const { reserves: wellReserves, refetch: refetchWellReserves } = useWellReserves(well); useEffect(() => { const run = async () => { @@ -64,7 +70,7 @@ export const AddLiquidity = ({ well, txnCompleteCallback, slippage, slippageSett const nonZeroValues = Object.values(amounts).filter((amount) => amount.value.gt("0")).length; return nonZeroValues !== 0; - }, [amounts, well.tokens]) + }, [amounts, well.tokens]); const checkMinAllowanceForAllTokens = useCallback(async () => { if (!address) { @@ -115,7 +121,6 @@ export const AddLiquidity = ({ well, txnCompleteCallback, slippage, slippageSett const allTokensHaveMinAllowance = useMemo(() => tokenAllowance.filter((a) => a === false).length === 0, [tokenAllowance]); const { data: quote } = useQuery(["wells", "quote", "addliquidity", address, amounts, allTokensHaveMinAllowance], async () => { - if (!atLeastOneAmountNonZero) { setShowQuoteDetails(false); return null; @@ -123,11 +128,11 @@ export const AddLiquidity = ({ well, txnCompleteCallback, slippage, slippageSett try { const quote = await well.addLiquidityQuote(Object.values(amounts)); - let estimate + let estimate; if (allTokensHaveMinAllowance) { estimate = await well.addLiquidityGasEstimate(Object.values(amounts), quote, address); } else { - estimate = TokenValue.ZERO + estimate = TokenValue.ZERO; } setShowQuoteDetails(true); return { @@ -146,7 +151,7 @@ export const AddLiquidity = ({ well, txnCompleteCallback, slippage, slippageSett loading: "Adding liquidity...", error: "Approval failed", success: "Liquidity added" - }); + }); try { const quoteAmountLessSlippage = quote.quote.subSlippage(slippage); const addLiquidityTxn = await well.addLiquidity(Object.values(amounts), quoteAmountLessSlippage, address); @@ -156,7 +161,7 @@ export const AddLiquidity = ({ well, txnCompleteCallback, slippage, slippageSett resetAmounts(); checkMinAllowanceForAllTokens(); refetchWellReserves(); - txnCompleteCallback(); + txnCompleteCallback(); } catch (error) { Log.module("AddLiquidity").error("Error adding liquidity: ", (error as Error).message); toast.error(error); @@ -176,18 +181,18 @@ export const AddLiquidity = ({ well, txnCompleteCallback, slippage, slippageSett if (!prices[index]) { setAmounts({ ...amounts, [index]: amount }); return; - }; + } const amountInUSD = amount.mul(prices[index] || TokenValue.ZERO); let _amounts = []; for (let i = 0; i < prices.length; i++) { if (i !== index) { - const conversion = prices[i] && prices[i]?.gt(TokenValue.ZERO) ? amountInUSD.div(prices[i]!) : TokenValue.ZERO + const conversion = prices[i] && prices[i]?.gt(TokenValue.ZERO) ? amountInUSD.div(prices[i]!) : TokenValue.ZERO; const conversionFormatted = TokenValue.fromHuman(conversion.humanString, well.tokens![i].decimals); _amounts[i] = conversionFormatted; } else { _amounts[i] = amount; - }; - }; + } + } setAmounts(Object.assign({}, _amounts)); }, [amounts, prices, well.tokens] @@ -238,38 +243,38 @@ export const AddLiquidity = ({ well, txnCompleteCallback, slippage, slippageSett
{well.tokens!.length > 0 && ( - - {well.tokens?.map((token: Token, index: number) => ( - - ))} - - setBalancedMode(!balancedMode)} /> - {showQuoteDetails && ( - + {well.tokens?.map((token: Token, index: number) => ( + - )} - + ))} + + setBalancedMode(!balancedMode)} /> + {showQuoteDetails && ( + + )} + {well.tokens!.length > 0 && well.tokens!.map((token: Token, index: number) => { - if (amounts[index] && amounts[index].gt(TokenValue.ZERO) && tokenAllowance[index] === false ) { + if (amounts[index] && amounts[index].gt(TokenValue.ZERO) && tokenAllowance[index] === false) { return ( - + )}
@@ -303,13 +308,13 @@ const LargeGapContainer = styled.div` display: flex; flex-direction: column; gap: 24px; -` +`; const MediumGapContainer = styled.div` display: flex; flex-direction: column; gap: 12px; -` +`; const ButtonWrapper = styled.div` display: flex; @@ -328,4 +333,4 @@ const TokenListContainer = styled.div` display: flex; flex-direction: column; gap: 12px; -`; \ No newline at end of file +`; diff --git a/projects/dex-ui/src/components/Liquidity/LiquidityRoot.tsx b/projects/dex-ui/src/components/Liquidity/LiquidityRoot.tsx index a0e5edc2db..ca9a5d9359 100644 --- a/projects/dex-ui/src/components/Liquidity/LiquidityRoot.tsx +++ b/projects/dex-ui/src/components/Liquidity/LiquidityRoot.tsx @@ -29,27 +29,39 @@ export const LiquidityRoot = ({ well, txnCompleteCallback }: LiquidityRootProps) return ( - <> - - - setShowRemove(false)}> - Add Liquidity - - - - setShowRemove(true)}> - Remove Liquidity - - - -
- {showRemove ? ( - console.log("complete")} slippage={slippage} slippageSettingsClickHandler={slippageSettingsClickHandler} handleSlippageValueChange={handleSlippageValueChange}/> - ) : ( - console.log("complete")} slippage={slippage} slippageSettingsClickHandler={slippageSettingsClickHandler} handleSlippageValueChange={handleSlippageValueChange}/> - )} -
- + <> + + + setShowRemove(false)}> + Add Liquidity + + + + setShowRemove(true)}> + Remove Liquidity + + + +
+ {showRemove ? ( + console.log("complete")} + slippage={slippage} + slippageSettingsClickHandler={slippageSettingsClickHandler} + handleSlippageValueChange={handleSlippageValueChange} + /> + ) : ( + console.log("complete")} + slippage={slippage} + slippageSettingsClickHandler={slippageSettingsClickHandler} + handleSlippageValueChange={handleSlippageValueChange} + /> + )} +
+
); }; diff --git a/projects/dex-ui/src/components/Liquidity/QuoteDetails.tsx b/projects/dex-ui/src/components/Liquidity/QuoteDetails.tsx index 7ff321596a..36cf9e6ef6 100644 --- a/projects/dex-ui/src/components/Liquidity/QuoteDetails.tsx +++ b/projects/dex-ui/src/components/Liquidity/QuoteDetails.tsx @@ -10,12 +10,13 @@ import { ImageButton } from "../ImageButton"; import { Tooltip } from "../Tooltip"; type QuoteDetailsProps = { - type: LIQUIDITY_OPERATION_TYPE; + type: LIQUIDITY_OPERATION_TYPE | "FORWARD_SWAP" | "REVERSE_SWAP"; removeLiquidityMode?: REMOVE_LIQUIDITY_MODE | undefined; quote: | { quote: TokenValue | TokenValue[]; estimate: TokenValue; + gas?: TokenValue; } | null | undefined; @@ -25,7 +26,7 @@ type QuoteDetailsProps = { wellLpToken?: ERC20Token | undefined; wellTokens?: Token[] | undefined; selectedTokenIndex?: number; - slippageSettingsClickHandler: () => void; + slippageSettingsClickHandler?: () => void; handleSlippageValueChange: (value: string) => void; tokenPrices?: (TokenValue | undefined | null)[]; tokenReserves?: (TokenValue | undefined | null)[]; @@ -47,15 +48,21 @@ const QuoteDetails = ({ const sdk = useSdk(); const [gasFeeUsd, setGasFeeUsd] = useState(""); const [tokenUSDValue, setTokenUSDValue] = useState(TokenValue.ZERO); - const [accordionOpen, setAccordionOpen] = useState(false) + const [accordionOpen, setAccordionOpen] = useState(false); useEffect(() => { const _setGasFeeUsd = async () => { - if (!quote || !quote.estimate) { + if (!quote || !quote.estimate || !quote.gas) { setGasFeeUsd("0.00"); } else { - const usd = await getGasInUsd(sdk, quote!.estimate.toBigNumber()); - setGasFeeUsd(`~${usd.toLocaleString("en-US", { + let usd + if (type === "FORWARD_SWAP" || "REVERSE_SWAP") { + usd = await getGasInUsd(sdk, quote.gas.toBigNumber()); + } else { + usd = await getGasInUsd(sdk, quote.estimate.toBigNumber()); + } + setGasFeeUsd( + `~${usd.toLocaleString("en-US", { style: "currency", currency: "USD" })}` @@ -64,22 +71,30 @@ const QuoteDetails = ({ }; _setGasFeeUsd(); - }, [sdk.provider, sdk, quote]); + }, [sdk.provider, sdk, quote, type]); const quoteValue = useMemo(() => { if (!quote || !quote.quote) { - return 'X.XXXX TOKEN'; + return "X.XXXX TOKEN"; + } + + if (type === "FORWARD_SWAP") { + return `${quote.estimate.toHuman("short")} ${wellTokens![1].symbol}`; + } + + if (type === "REVERSE_SWAP") { + return `${quote.estimate.toHuman("short")} ${wellTokens![0].symbol}`; } if (type === LIQUIDITY_OPERATION_TYPE.REMOVE) { if (!wellTokens) { - return 'X.XXXX TOKEN'; + return "X.XXXX TOKEN"; } } if (type === LIQUIDITY_OPERATION_TYPE.ADD) { const _quoteValue = quote?.quote as TokenValue; - console.log('Here', _quoteValue, _quoteValue.toHuman(), _quoteValue.toHuman("short")); + console.log("Here", _quoteValue, _quoteValue.toHuman(), _quoteValue.toHuman("short")); return `${_quoteValue.toHuman("short")} ${wellLpToken!.symbol}`; } @@ -114,25 +129,30 @@ const QuoteDetails = ({ throw new Error("invalid type or removeLiquidityMode"); }, [quote, type, wellLpToken, wellTokens, removeLiquidityMode, inputs, selectedTokenIndex]); - useEffect(() => { - const run = async() => { - if (tokenPrices && tokenReserves && quote && quote.quote) { + useEffect(() => { + const run = async () => { + if (!quote || !quote.quote) return; + if (tokenPrices && tokenReserves) { if (type === LIQUIDITY_OPERATION_TYPE.REMOVE) { let totalUSDValue = TokenValue.ZERO; - let valueInUSD + let valueInUSD; if (removeLiquidityMode === REMOVE_LIQUIDITY_MODE.OneToken) { - valueInUSD = tokenPrices![selectedTokenIndex!]!.mul(!Array.isArray(quote.quote) ? quote.quote || TokenValue.ZERO : TokenValue.ZERO); + valueInUSD = tokenPrices![selectedTokenIndex!]!.mul( + !Array.isArray(quote.quote) ? quote.quote || TokenValue.ZERO : TokenValue.ZERO + ); totalUSDValue = totalUSDValue.add(valueInUSD); } else { for (let i = 0; i < tokenPrices.length; i++) { - valueInUSD = tokenPrices![i]!.mul(removeLiquidityMode === REMOVE_LIQUIDITY_MODE.Balanced && Array.isArray(quote.quote) ? quote.quote[i] || TokenValue.ZERO : inputs![i] || TokenValue.ZERO); + valueInUSD = tokenPrices![i]!.mul( + removeLiquidityMode === REMOVE_LIQUIDITY_MODE.Balanced && Array.isArray(quote.quote) + ? quote.quote[i] || TokenValue.ZERO + : inputs![i] || TokenValue.ZERO + ); totalUSDValue = totalUSDValue.add(valueInUSD); } } setTokenUSDValue(totalUSDValue); - } else if (type === LIQUIDITY_OPERATION_TYPE.ADD) { - let totalReservesUSDValue = TokenValue.ZERO; for (let i = 0; i < tokenPrices.length; i++) { const reserveValueInUSD = tokenPrices![i]!.mul(tokenReserves[i]!.add(inputs![i] || TokenValue.ZERO)); @@ -146,7 +166,11 @@ const QuoteDetails = ({ const lpTokenUSDValue = totalReservesUSDValue.div(lpTokenSupply); const finalUSDValue = !Array.isArray(quote.quote) ? lpTokenUSDValue.mul(quote.quote) : TokenValue.ZERO; setTokenUSDValue(finalUSDValue); - } + } + } else if (type === "FORWARD_SWAP") { + setTokenUSDValue(quote!.estimate.mul(tokenPrices![1] || TokenValue.ZERO)) + } else if (type === "REVERSE_SWAP") { + setTokenUSDValue(inputs![1].mul(tokenPrices![1] || TokenValue.ZERO)) } } @@ -154,42 +178,41 @@ const QuoteDetails = ({ }, [tokenPrices, tokenReserves, quote, type, selectedTokenIndex, inputs, removeLiquidityMode, wellLpToken]); const priceImpact = useMemo(() => { - - if (!tokenReserves || !inputs || !tokenPrices) return TokenValue.ZERO + if (!tokenReserves || !inputs || !tokenPrices) return TokenValue.ZERO; function calculatePrice(prevVal: any, token: any) { if (token.eq(TokenValue.ZERO)) { - return TokenValue.ZERO - }; + return TokenValue.ZERO; + } return prevVal!.div(token!); - }; + } - const currentData = tokenReserves.map((token, index) => - tokenReserves[index]?.mul(tokenPrices![index]!) - //'reservesUSD': tokenReserves[index]!.mul(tokenPrices![index]!) + const currentData = tokenReserves.map( + (token, index) => tokenReserves[index]?.mul(tokenPrices![index]!) + //'reservesUSD': tokenReserves[index]!.mul(tokenPrices![index]!) ); const newData = tokenReserves.map((token, index) => { if (!quote) return TokenValue.ZERO; if (type === LIQUIDITY_OPERATION_TYPE.REMOVE) { if (removeLiquidityMode === REMOVE_LIQUIDITY_MODE.Custom) { - return (tokenReserves[index]?.sub(inputs![index] || TokenValue.ZERO).mul(tokenPrices![index]!)); + return tokenReserves[index]?.sub(inputs![index] || TokenValue.ZERO).mul(tokenPrices![index]!); } else if (removeLiquidityMode === REMOVE_LIQUIDITY_MODE.OneToken && !Array.isArray(quote!.quote)) { - return (tokenReserves[index]?.sub(index === selectedTokenIndex ? quote!.quote : TokenValue.ZERO).mul(tokenPrices![index]!)); + return tokenReserves[index]?.sub(index === selectedTokenIndex ? quote!.quote : TokenValue.ZERO).mul(tokenPrices![index]!); } else if (removeLiquidityMode === REMOVE_LIQUIDITY_MODE.Balanced && Array.isArray(quote!.quote)) { - return (tokenReserves[index]?.sub(quote!.quote[index]).mul(tokenPrices![index]!)); + return tokenReserves[index]?.sub(quote!.quote[index]).mul(tokenPrices![index]!); } else { - return TokenValue.ZERO - }; + return TokenValue.ZERO; + } } else { - return (tokenReserves[index]?.add(inputs![index] || TokenValue.ZERO).mul(tokenPrices![index]!)); - }; + return tokenReserves[index]?.add(inputs![index] || TokenValue.ZERO).mul(tokenPrices![index]!); + } }); - const oldPrice = currentData.reduce(calculatePrice) - const newPrice = newData.reduce(calculatePrice) + const oldPrice = currentData.reduce(calculatePrice); + const newPrice = newData.reduce(calculatePrice); - let priceDiff + let priceDiff; if (!newPrice || !oldPrice) { return TokenValue.ZERO; } else if (newPrice?.eq(TokenValue.ZERO)) { @@ -197,54 +220,65 @@ const QuoteDetails = ({ } else if (oldPrice?.eq(TokenValue.ZERO)) { return TokenValue.fromHuman(100, 6); } else { - priceDiff = oldPrice.sub(newPrice).div(newPrice).mul(TokenValue.fromHuman(100, 6)) + priceDiff = oldPrice.sub(newPrice).div(newPrice).mul(TokenValue.fromHuman(100, 6)); } - if (priceDiff.abs().lt(TokenValue.fromHuman('0.01', 6))) return TokenValue.ZERO - return priceDiff - - }, [tokenReserves, inputs, quote, removeLiquidityMode, selectedTokenIndex, tokenPrices, type]) + if (priceDiff.abs().lt(TokenValue.fromHuman("0.01", 6))) return TokenValue.ZERO; + return priceDiff; + }, [tokenReserves, inputs, quote, removeLiquidityMode, selectedTokenIndex, tokenPrices, type]); return ( setAccordionOpen(!accordionOpen)} cursor="pointer"> - Expected Output - {quoteValue} - setAccordionOpen(!accordionOpen)} padding="0px" margin="-2px 0px 0px 8px" alt="Click to view more information about this transaction" /> + + {type === "FORWARD_SWAP" ? "Minimum Output" : type === "REVERSE_SWAP" ? "Maximum Input" : "Expected Output"} + + + {quoteValue} + + setAccordionOpen(!accordionOpen)} + padding="0px" + margin="-2px 0px 0px 8px" + alt="Click to view more information about this transaction" + /> - + USD Value {`$${tokenUSDValue.toHuman("short")}`} - - Price Impact - {`${priceImpact.toHuman("short")}%`} - - -
*PRICE IMPACT*
- Change in Token price on this Well caused directly by this action. - - }> + {(type !== "FORWARD_SWAP" && type !== "REVERSE_SWAP") && + + Price Impact + {`${priceImpact.toHuman("short")}%`} + + +
*PRICE IMPACT*
+ Change in Token price on this Well caused directly by this action. + + } + > -
-
-
+
+
+
+ } Slippage Tolerance {`${slippage}%`} - + Estimated Gas Fee @@ -265,20 +299,21 @@ type QuoteDetailProps = { type AccordionProps = { open?: boolean; -} + isShort?: boolean; +}; const IconContainer = styled.div` margin-left: 10px; margin-top: 2px; margin-bottom: -2px; cursor: pointer; -` +`; const AccordionContainer = styled.div` - height: ${(props) => (props.open ? '94px' : '0px')}; - overflow: ${(props) => (props.open ? 'visible' : 'hidden')}; - transition: height 0.2s -` + height: ${(props) => (props.open ? props.isShort ? "70px" : "94px" : "0px")}; + overflow: ${(props) => (props.open ? "visible" : "hidden")}; + transition: height 0.2s; +`; const QuoteDetailLabel = styled.div` align-items: flex-start; @@ -299,7 +334,7 @@ const QuoteDetailLine = styled.div` display: flex; flex-direction: row; width: 100%; - cursor: ${(props) => (props.cursor ?? "auto")}; + cursor: ${(props) => props.cursor ?? "auto"}; `; const QuoteContainer = styled.div` diff --git a/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx b/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx index d2f78dd0f6..191fa8f271 100644 --- a/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx +++ b/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx @@ -28,7 +28,13 @@ type RemoveLiquidityProps = { handleSlippageValueChange: (value: string) => void; }; -export const RemoveLiquidity = ({ well, txnCompleteCallback, slippage, slippageSettingsClickHandler, handleSlippageValueChange }: RemoveLiquidityProps) => { +export const RemoveLiquidity = ({ + well, + txnCompleteCallback, + slippage, + slippageSettingsClickHandler, + handleSlippageValueChange +}: RemoveLiquidityProps) => { const { address } = useAccount(); const [wellLpToken, setWellLpToken] = useState(null); @@ -39,7 +45,7 @@ export const RemoveLiquidity = ({ well, txnCompleteCallback, slippage, slippageS const [prices, setPrices] = useState<(TokenValue | null)[]>(); const sdk = useSdk(); - const { reserves: wellReserves, refetch: refetchWellReserves } = useWellReserves(well); + const { reserves: wellReserves, refetch: refetchWellReserves } = useWellReserves(well); useEffect(() => { const run = async () => { @@ -80,9 +86,9 @@ export const RemoveLiquidity = ({ well, txnCompleteCallback, slippage, slippageS const resetState = useCallback(() => { if (well.tokens) { - const initialAmounts = [] + const initialAmounts = []; for (let i = 0; i < well.tokens.length; i++) { - initialAmounts[i] = TokenValue.ZERO + initialAmounts[i] = TokenValue.ZERO; } setAmounts([...initialAmounts]); @@ -98,7 +104,7 @@ export const RemoveLiquidity = ({ well, txnCompleteCallback, slippage, slippageS loading: "Removing liquidity...", error: "Removal failed", success: "Liquidity removed" - }); + }); let removeLiquidityTxn; try { if (removeLiquidityMode === REMOVE_LIQUIDITY_MODE.OneToken) { @@ -133,10 +139,10 @@ export const RemoveLiquidity = ({ well, txnCompleteCallback, slippage, slippageS resetState(); refetchWellReserves(); txnCompleteCallback(); - } catch (error) { - Log.module("RemoveLiquidity").error("Error removing liquidity: ", (error as Error).message); - toast.error(error); - } + } catch (error) { + Log.module("RemoveLiquidity").error("Error removing liquidity: ", (error as Error).message); + toast.error(error); + } } }, [ well, @@ -155,8 +161,8 @@ export const RemoveLiquidity = ({ well, txnCompleteCallback, slippage, slippageS ]); const handleSwitchRemoveMode = (newMode: REMOVE_LIQUIDITY_MODE) => { - const currentMode = removeLiquidityMode === REMOVE_LIQUIDITY_MODE.Custom || removeLiquidityMode === REMOVE_LIQUIDITY_MODE.Balanced - const _newMode = newMode === REMOVE_LIQUIDITY_MODE.Custom || newMode === REMOVE_LIQUIDITY_MODE.Balanced + const currentMode = removeLiquidityMode === REMOVE_LIQUIDITY_MODE.Custom || removeLiquidityMode === REMOVE_LIQUIDITY_MODE.Balanced; + const _newMode = newMode === REMOVE_LIQUIDITY_MODE.Custom || newMode === REMOVE_LIQUIDITY_MODE.Balanced; if (currentMode && _newMode) { setRemoveLiquidityMode(newMode); } else { @@ -168,7 +174,7 @@ export const RemoveLiquidity = ({ well, txnCompleteCallback, slippage, slippageS const handleInputChange = useCallback( (amountFromInput: TokenValue) => { if (removeLiquidityMode === REMOVE_LIQUIDITY_MODE.Custom) { - setRemoveLiquidityMode(REMOVE_LIQUIDITY_MODE.Balanced) + setRemoveLiquidityMode(REMOVE_LIQUIDITY_MODE.Balanced); } setLpTokenAmount(amountFromInput); }, @@ -181,8 +187,8 @@ export const RemoveLiquidity = ({ well, txnCompleteCallback, slippage, slippageS const handleImbalancedInputChange = useCallback( (index: number) => (amount: TokenValue) => { - let _newAmounts = [...amounts] - _newAmounts[index] = amount + let _newAmounts = [...amounts]; + _newAmounts[index] = amount; for (let i = 0; i < well.tokens!.length; i++) { _newAmounts[i] = _newAmounts[i] ? _newAmounts[i] : i === index ? amount : TokenValue.ZERO; } @@ -263,52 +269,52 @@ export const RemoveLiquidity = ({ well, txnCompleteCallback, slippage, slippageS useEffect(() => { const nonZeroValues = amounts.filter((amount) => amount && amount.value.gt("0")).length; if (nonZeroValues === 0) { - setLpTokenAmount(undefined) + setLpTokenAmount(undefined); } - }, [amounts]) + }, [amounts]); return (
{wellLpToken && ( - - - - + + + + -
Claim LP Tokens as
- - - handleSwitchRemoveMode(REMOVE_LIQUIDITY_MODE.OneToken)} active={removeLiquidityMode === REMOVE_LIQUIDITY_MODE.OneToken} stretch> - - handleSwitchRemoveMode(REMOVE_LIQUIDITY_MODE.OneToken)}>Single Token - - - - handleSwitchRemoveMode(REMOVE_LIQUIDITY_MODE.Balanced)} active={removeLiquidityMode !== REMOVE_LIQUIDITY_MODE.OneToken} stretch> - - handleSwitchRemoveMode(REMOVE_LIQUIDITY_MODE.Balanced)}>Multiple Tokens - - - +
Claim LP Tokens as
+ + + handleSwitchRemoveMode(REMOVE_LIQUIDITY_MODE.OneToken)} + active={removeLiquidityMode === REMOVE_LIQUIDITY_MODE.OneToken} + stretch + > + + handleSwitchRemoveMode(REMOVE_LIQUIDITY_MODE.OneToken)}>Single Token + + + + handleSwitchRemoveMode(REMOVE_LIQUIDITY_MODE.Balanced)} + active={removeLiquidityMode !== REMOVE_LIQUIDITY_MODE.OneToken} + stretch + > + + handleSwitchRemoveMode(REMOVE_LIQUIDITY_MODE.Balanced)}>Multiple Tokens + + +
{removeLiquidityMode !== REMOVE_LIQUIDITY_MODE.OneToken && ( <> @@ -341,11 +347,7 @@ export const RemoveLiquidity = ({ well, txnCompleteCallback, slippage, slippageS {well.tokens!.map((token: Token, index: number) => ( handleSwitchSingleToken(index)}> - + {token.symbol} {singleTokenIndex === index ? ( @@ -358,47 +360,48 @@ export const RemoveLiquidity = ({ well, txnCompleteCallback, slippage, slippageS ))}
)} -
- {removeLiquidityMode !== REMOVE_LIQUIDITY_MODE.OneToken && ( - <> - + {removeLiquidityMode !== REMOVE_LIQUIDITY_MODE.OneToken && ( + <> + handleSwitchRemoveMode( removeLiquidityMode === REMOVE_LIQUIDITY_MODE.Custom ? REMOVE_LIQUIDITY_MODE.Balanced : REMOVE_LIQUIDITY_MODE.Custom - )} - /> - - )} - {lpTokenAmountNonZero && ( - - )} - {!tokenAllowance ? ( - - - - ) : ( - + + )} + {lpTokenAmountNonZero && ( + + )} + {!tokenAllowance ? ( + + + + ) : ( +
@@ -414,20 +417,20 @@ export const RemoveLiquidity = ({ well, txnCompleteCallback, slippage, slippageS }; type ReadOnlyRowProps = { - selected?: boolean -} + selected?: boolean; +}; const LargeGapContainer = styled.div` display: flex; flex-direction: column; gap: 24px; -` +`; const MediumGapContainer = styled.div` display: flex; flex-direction: column; gap: 12px; -` +`; const TabLabel = styled.div` cursor: pointer; @@ -444,8 +447,7 @@ const Tabs = styled.div` gap: 8px; `; -const ApproveTokenButton = styled(Button)` -`; +const ApproveTokenButton = styled(Button)``; const ButtonWrapper = styled.div` display: flex; @@ -465,7 +467,7 @@ const TabRadio = styled.input` height: 1em; outline: none; border: none; - background-color: #F9F8F6; + background-color: #f9f8f6; &:checked { background-color: white; } @@ -480,7 +482,7 @@ const Radio = styled.input` height: 1.4em; outline: none; border: none; - background-color: #F9F8F6; + background-color: #f9f8f6; &:checked { background-color: white; } @@ -492,8 +494,7 @@ const TokenAmount = styled.div` text-align: right; `; -const TokenSymbol = styled.div` -`; +const TokenSymbol = styled.div``; const SmallTokenLogo = styled.img` width: 20px; @@ -503,8 +504,8 @@ const SmallTokenLogo = styled.img` const ReadOnlyTokenValueRow = styled.div` display: flex; flex-direction: row; - font-weight: ${(props) => props.selected ? '600' : 'normal'}; - background-color: ${(props) => props.selected ? 'white' : '#F9F8F6'}; + font-weight: ${(props) => (props.selected ? "600" : "normal")}; + background-color: ${(props) => (props.selected ? "white" : "#F9F8F6")}; border: 0.5px solid black; margin: -0.5px; height: 60px; @@ -527,5 +528,4 @@ const ContainerSingleTokenRow = styled.div` cursor: pointer; `; -const OutputModeSelectorContainer = styled.div` -` +const OutputModeSelectorContainer = styled.div``; diff --git a/projects/dex-ui/src/components/Liquidity/SlippagePanel.tsx b/projects/dex-ui/src/components/Liquidity/SlippagePanel.tsx index 41631a8ed1..6979216c98 100644 --- a/projects/dex-ui/src/components/Liquidity/SlippagePanel.tsx +++ b/projects/dex-ui/src/components/Liquidity/SlippagePanel.tsx @@ -13,47 +13,48 @@ type SlippagePanelProps = { }; const SlippagePanel = ({ handleSlippageValueChange, slippageValue }: SlippagePanelProps) => { - const [modalOpen, setModalOpen] = useState(false); const closeModal = useCallback(() => setModalOpen(false), []); - const dontStealFocus = useCallback((e: MouseEvent) => { + const dontStealFocus = useCallback( + (e: MouseEvent) => { if ((e.target as HTMLElement).id === "modal") { closeModal(); } - }, [closeModal]); + }, + [closeModal] + ); return ( - setModalOpen(!modalOpen)} modalOpen={modalOpen}/> + setModalOpen(!modalOpen)} modalOpen={modalOpen} /> {modalOpen && ( - <> - - - -
Adjust Slippage
- -
- - - handleSlippageValueChange(e.target.value)} /> - Slippage Amount - - Slippage tolerance is the % change in token price caused by external factors between transaction submission and execution that you - are willing to tolerate. - - Your transaction will revert if the price changes by more than the percentage specified. - - -
- + <> + + + +
Adjust Slippage
+ +
+ + + handleSlippageValueChange(e.target.value)} /> + Slippage Amount + + Slippage tolerance is the % change in token price caused by external factors between transaction submission and execution that + you are willing to tolerate. + + Your transaction will revert if the price changes by more than the percentage specified. + + +
+ )}
); }; -const Slippage = styled.div` -` +const Slippage = styled.div``; const StyledInput = styled.input` border: none; @@ -71,25 +72,24 @@ const InputContainer = styled.div` padding-right: 12px; margin-bottom: 8px; &:focus-within { - border: 0.5px solid #46B955; + border: 0.5px solid #46b955; } -` -const InputAdornment = styled.div` -` +`; +const InputAdornment = styled.div``; type GearIconProps = { - modalOpen?: boolean, -} + modalOpen?: boolean; +}; const Icon = styled.img` margin-left: 10px; transition: 0.1s; vertical-align: text-bottom; - rotate: ${(props) => props.modalOpen ? `30deg` : `0deg` }; + rotate: ${(props) => (props.modalOpen ? `30deg` : `0deg`)}; cursor: pointer; - filter: ${(props) => props.modalOpen ? `brightness(0%)` : `brightness(100%)`}; + filter: ${(props) => (props.modalOpen ? `brightness(0%)` : `brightness(100%)`)}; &:hover { - filter: ${(props) => props.modalOpen ? `brightness(0%)` : `brightness(50%)`}; + filter: ${(props) => (props.modalOpen ? `brightness(0%)` : `brightness(50%)`)}; } `; @@ -149,9 +149,8 @@ const ModalContent = styled.div` max-height: calc(100vh - 64px - 48px - 96px - 72px - 48px - 48px); overflow-y: auto; overflow-x: hidden; - + padding: 16px; `; - export default SlippagePanel; diff --git a/projects/dex-ui/src/components/Liquidity/allowance.ts b/projects/dex-ui/src/components/Liquidity/allowance.ts index 69eefe50ba..f769460f19 100644 --- a/projects/dex-ui/src/components/Liquidity/allowance.ts +++ b/projects/dex-ui/src/components/Liquidity/allowance.ts @@ -16,7 +16,7 @@ const ensureAllowance = async (walletAddress: string, spender: string, token: ER loading: "Approving spending limit...", error: "Approval failed", success: "Spending limit approved" - }); + }); try { const approveTXN = await token.getContract().approve(spender, mininumAllowance.toBigNumber(), { gasLimit: 50000 }); toast.confirming(approveTXN); diff --git a/projects/dex-ui/src/components/Liquidity/types.ts b/projects/dex-ui/src/components/Liquidity/types.ts index 6e3e2e2769..1e13a2f97f 100644 --- a/projects/dex-ui/src/components/Liquidity/types.ts +++ b/projects/dex-ui/src/components/Liquidity/types.ts @@ -14,4 +14,3 @@ export enum LIQUIDITY_OPERATION_TYPE { ADD, REMOVE } - diff --git a/projects/dex-ui/src/components/PageComponents/Title.tsx b/projects/dex-ui/src/components/PageComponents/Title.tsx index 4dd022b416..336bf49227 100644 --- a/projects/dex-ui/src/components/PageComponents/Title.tsx +++ b/projects/dex-ui/src/components/PageComponents/Title.tsx @@ -11,26 +11,44 @@ type Props = { title: string; path: string; }; + center?: boolean; }; -export const Title: FC = ({ title, parent, fontweight }) => ( - - {parent && {parent.title} > } - {title} +export const Title: FC = ({ title, parent, fontweight, center }) => ( + + + {parent && {parent.title} > } + {title} + ); type TitleProps = { fontweight?: string; -} +}; + +type TitleContainerProps = { + center?: boolean; +}; + +const Container = styled.div` + display: flex; + flex-direction: row; + ${(props) => props.center && `justify-content: center;`} +`; -const Container = styled.div` +const TitleContainer = styled.div` display: flex; flex-direction: row; + ${(props) => + props.center && + `width: 1344px; + min-width: 1344px;`} `; + const TitleText = styled.div` ${BodyL} - ${(props) => (props.fontweight && `font-weight: ${props.fontweight}`)}; + ${(props) => props.fontweight && `font-weight: ${props.fontweight}`}; text-transform: uppercase; `; const ParentText = styled(Link)` diff --git a/projects/dex-ui/src/components/Swap/ArrowButton.tsx b/projects/dex-ui/src/components/Swap/ArrowButton.tsx index 05c8888ba3..36d6104e46 100644 --- a/projects/dex-ui/src/components/Swap/ArrowButton.tsx +++ b/projects/dex-ui/src/components/Swap/ArrowButton.tsx @@ -8,7 +8,7 @@ type ArrowButtonType = { }; export const ArrowButton: FC = ({ onClick }) => ( - +