diff --git a/package.json b/package.json index 7cc642904d..cd8676e25b 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,6 @@ "@supabase/auth-helpers-nextjs": "^0.5.4", "@supabase/auth-helpers-react": "^0.3.1", "@supabase/supabase-js": "^2.10.0", - "@sushiswap/sdk": "5.0.0-canary.116", "@tanstack/react-query": "^5.49.2", "@uiw/react-markdown-preview": "^4.1.13", "@uiw/react-md-editor": "^3.23.3", diff --git a/src/components/AMMPrices/TokenAMMPriceRow.tsx b/src/components/AMMPrices/TokenAMMPriceRow.tsx deleted file mode 100644 index a260d4ee88..0000000000 --- a/src/components/AMMPrices/TokenAMMPriceRow.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { LoadingOutlined } from '@ant-design/icons' -import { t, Trans } from '@lingui/macro' -import { Tooltip } from 'antd' -import SushiswapLogo from 'components/icons/Sushiswap' -import UniswapLogo from 'components/icons/Uniswap' -import { ONE_TRILLION } from 'constants/numbers' -import { classNames } from 'utils/classNames' -import { formatOrTruncate } from 'utils/format/formatNumber' -import ExternalLink from '../ExternalLink' -import TooltipIcon from '../TooltipIcon' - -type ExchangeName = 'Uniswap' | 'Sushiswap' - -const LOGOS = { - Uniswap: UniswapLogo, - Sushiswap: SushiswapLogo, -} - -type Props = { - className?: string - exchangeName: ExchangeName - tokenSymbol: string - exchangeLink?: string - WETHPrice?: string - loading?: boolean -} - -const formatPrice = (price: string) => { - const p = parseInt(price, 10) - const formatLimit = ONE_TRILLION - - // format all values below trillion value, otherwise truncate is as long number. - return formatOrTruncate(p, formatLimit) -} - -const NotAvailableText = ({ WETHPrice, exchangeName, tokenSymbol }: Props) => { - const tooltip = !WETHPrice - ? t`${exchangeName} has no market for ${tokenSymbol}.` - : '' - - return ( - - - {!WETHPrice ? Unavailable : null} - - - - ) -} - -export default function TokenAMMPriceRow({ - className, - exchangeName, - tokenSymbol, - exchangeLink, - WETHPrice, - loading, -}: Props) { - const LogoComponent = LOGOS[exchangeName] - - return ( -
-
- - - - {exchangeName} -
- {loading && } - - {!loading && - (WETHPrice ? ( - - - {`${formatPrice(WETHPrice)} ${tokenSymbol} / ETH`} - - - ) : ( - - ))} -
- ) -} diff --git a/src/components/AMMPrices/hooks/useERC20SushiswapPrice.ts b/src/components/AMMPrices/hooks/useERC20SushiswapPrice.ts deleted file mode 100644 index 52122b4c18..0000000000 --- a/src/components/AMMPrices/hooks/useERC20SushiswapPrice.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { CurrencyAmount, Pair, Route, Token, WETH9 } from '@sushiswap/sdk' -import { useQuery } from '@tanstack/react-query' -import IUniswapV2PairABI from '@uniswap/v2-core/build/IUniswapV2Pair.json' -import { readNetwork } from 'constants/networks' -import { WAD_DECIMALS } from 'constants/numbers' -import { readProvider } from 'constants/readProvider' -import { Contract } from 'ethers' - -/** - * Fetches information about a pair and constructs a pair from the given two tokens. - * @param tokenA first token - * @param tokenB second token - * @param provider the provider to use to fetch the data - * Source: https://github.com/Uniswap/v2-sdk/blob/a88048e9c4198a5bdaea00883ca00c8c8e582605/src/fetcher.ts - */ -async function fetchPairData(tokenA: Token, tokenB: Token): Promise { - const pairAddress = Pair.getAddress(tokenA, tokenB) - - const [reserves0, reserves1] = await new Contract( - pairAddress, - IUniswapV2PairABI.abi, - readProvider, - ).getReserves() - - const balances = tokenA.sortsBefore(tokenB) - ? [reserves0, reserves1] - : [reserves1, reserves0] - return new Pair( - CurrencyAmount.fromRawAmount(tokenA, balances[0]), - CurrencyAmount.fromRawAmount(tokenB, balances[1]), - ) -} - -type Props = { - tokenSymbol: string - tokenAddress: string -} - -const networkId = readNetwork.chainId - -export function useSushiswapPriceQuery({ tokenSymbol, tokenAddress }: Props) { - const PROJECT_TOKEN = new Token( - networkId, - tokenAddress, - WAD_DECIMALS, - tokenSymbol, - ) - const WETH = WETH9[networkId] - - return useQuery({ - queryKey: [`${tokenSymbol}-sushiswap-price`], - queryFn: async () => { - // note that you may want/need to handle this async code differently, - // for example if top-level await is not an option - const pair = await fetchPairData(PROJECT_TOKEN, WETH) - - const route = new Route([pair], WETH, PROJECT_TOKEN) - return { - tokenSymbol, - midPrice: route.midPrice, - } - }, - }) -} diff --git a/src/components/AMMPrices/index.tsx b/src/components/AMMPrices/index.tsx deleted file mode 100644 index 78dba545f7..0000000000 --- a/src/components/AMMPrices/index.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { Trans } from '@lingui/macro' -import { generateAMMLink } from 'lib/amm' -import { useSushiswapPriceQuery } from './hooks/useERC20SushiswapPrice' -import { useUniswapPriceQuery } from './hooks/useERC20UniswapPrice' -import TokenAMMPriceRow from './TokenAMMPriceRow' - -type Props = { - mode: 'buy' | 'redeem' - tokenSymbol: string - tokenAddress: string -} - -/** - * Component for rendering a set of AMM Prices. - */ -export default function AMMPrices({ mode, tokenSymbol, tokenAddress }: Props) { - const { data: uniswapPriceData, isLoading: uniswapLoading } = - useUniswapPriceQuery({ - tokenSymbol, - tokenAddress, - }) - - const { data: sushiswapPriceData, isLoading: sushiswapLoading } = - useSushiswapPriceQuery({ - tokenSymbol, - tokenAddress, - }) - - return ( - <> -

- Current 3rd Party Exchange Rates -

- - - - ) -} diff --git a/src/components/Create/components/pages/ProjectDetails/ProjectDetailsPage.tsx b/src/components/Create/components/pages/ProjectDetails/ProjectDetailsPage.tsx index 8b72f915a4..ee3d20a30d 100644 --- a/src/components/Create/components/pages/ProjectDetails/ProjectDetailsPage.tsx +++ b/src/components/Create/components/pages/ProjectDetails/ProjectDetailsPage.tsx @@ -1,6 +1,5 @@ import { RightOutlined } from '@ant-design/icons' import { t, Trans } from '@lingui/macro' -import { ADDRESS_ZERO } from '@uniswap/v3-sdk' import { Col, Form, Row } from 'antd' import { Callout } from 'components/Callout/Callout' import { useLockPageRulesWrapper } from 'components/Create/hooks/useLockPageRulesWrapper' @@ -13,6 +12,7 @@ import { JuiceInput } from 'components/inputs/JuiceTextInput' import PrefixedInput from 'components/inputs/PrefixedInput' import { RichEditor } from 'components/RichEditor' import { CREATE_FLOW } from 'constants/fathomEvents' +import { constants } from 'ethers' import { useWallet } from 'hooks/Wallet' import { trackFathomGoal } from 'lib/fathom' import Link from 'next/link' @@ -166,7 +166,7 @@ export const ProjectDetailsPage: React.FC< }), ])} > - + {projectOwnerDifferentThanWalletAddress && ( diff --git a/src/components/Project/RedeemAMMPrices.tsx b/src/components/Project/RedeemAMMPrices.tsx deleted file mode 100644 index 215c64489b..0000000000 --- a/src/components/Project/RedeemAMMPrices.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Trans } from '@lingui/macro' -import { Tooltip } from 'antd' -import Loading from 'components/Loading' -import { Suspense, lazy } from 'react' -const AMMPrices = lazy(() => import('components/AMMPrices')) - -export const RedeemAMMPrices = ({ - className, - tokenSymbol, - tokenAddress, -}: { - className?: string - tokenSymbol: string - tokenAddress: string -}) => { - return ( - - - or{' '} - }> - - - } - placement="bottomLeft" - > - - sell {tokenSymbol} on exchange. - - - - - ) -} diff --git a/src/lib/amm.ts b/src/lib/amm.ts deleted file mode 100644 index c1b658e818..0000000000 --- a/src/lib/amm.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const generateAMMLink = ({ - mode, - baseLink, - tokenAddress, -}: { - mode: 'buy' | 'redeem' - baseLink: string - tokenAddress: string -}) => { - switch (mode) { - case 'buy': - return `${baseLink}/swap?inputCurrency=ETH&outputCurrency=${tokenAddress}` - case 'redeem': - return `${baseLink}/swap?inputCurrency=${tokenAddress}&outputCurrency=ETH` - default: - break - } -} diff --git a/src/locales/messages.pot b/src/locales/messages.pot index f89068ae21..828bdb844f 100644 --- a/src/locales/messages.pot +++ b/src/locales/messages.pot @@ -230,9 +230,6 @@ msgstr "" msgid "Cycles:" msgstr "" -msgid "or <0><1>sell {tokenSymbol} on exchange." -msgstr "" - msgid "Amount (USD)" msgstr "" @@ -338,9 +335,6 @@ msgstr "" msgid "<0>Owned by<1/>" msgstr "" -msgid "{tokenSymbol}/ETH exchange rate on {exchangeName}." -msgstr "" - msgid "Your payouts do not sum to 100%. Because your project is set to pay out all available ETH, the remainder will go to the project owner." msgstr "" @@ -1499,9 +1493,6 @@ msgstr "" msgid "Still have questions or want to know more about us? Jump into our Discord and come say hello." msgstr "" -msgid "Project tokens can be redeemed to reclaim a portion of the ETH not needed for this cycle's payouts. The amount of ETH returned depends on this cycle's redemption rate.<0>Tokens are burned when they are redeemed." -msgstr "" - msgid "Mint {0}" msgstr "" @@ -1757,9 +1748,6 @@ msgstr "" msgid "Untitled project" msgstr "" -msgid "or <0><1>buy {tokenText} on an exchange." -msgstr "" - msgid "{chainName} Project #{projectId}" msgstr "" @@ -1859,6 +1847,9 @@ msgstr "" msgid "30 days" msgstr "" +msgid "Get more for your PEOPLE." +msgstr "" + msgid "allocation" msgstr "" @@ -1985,6 +1976,9 @@ msgstr "" msgid "Paid as <0/>" msgstr "" +msgid "Check <0>Uniswap, <1>SushiSwap, or other third-party exchanges for better rates before redeeming on Juicebox." +msgstr "" + msgid "Send a percentage of reserved tokens to the wallets and Juicebox projects of your choosing. By default, reserved tokens are sent to the project owner." msgstr "" @@ -2354,9 +2348,6 @@ msgstr "" msgid "reserved token recipient" msgstr "" -msgid "{nftCount, plural, one {+ # NFT} other {+ # NFTs}}" -msgstr "" - msgid "Controller configuration" msgstr "" @@ -3170,6 +3161,9 @@ msgstr "" msgid "{tokenTextSingular} recipients" msgstr "" +msgid "Project tokens can be redeemed to reclaim a portion of the ETH not needed for this cycle's payouts. The amount of ETH returned depends on this cycle's redemption rate. <0>Tokens are burned when they are redeemed." +msgstr "" + msgid "Will be rounded to <0/>{0}" msgstr "" @@ -3236,9 +3230,6 @@ msgstr "" msgid "Notifications" msgstr "" -msgid "{exchangeName} has no market for {tokenSymbol}." -msgstr "" - msgid "Logo" msgstr "" @@ -3344,9 +3335,6 @@ msgstr "" msgid "to select" msgstr "" -msgid "Unavailable" -msgstr "" - msgid "Burn token" msgstr "" @@ -3512,6 +3500,9 @@ msgstr "" msgid "With an auction estimate of $10-15 million at Sotheby's, ConstitutionDAO wanted to raise as much as possible and decided to set Payouts to Unlimited. In order to build trust with potential supporters, the campaign set up a 9/13 multisig with core team members and well-known figures in web3. Reserved Rate was also set to 0 to guarantee that everyone had equal access to PEOPLE tokens which would govern the document if they won the auction." msgstr "" +msgid "Current Redemption Rate:" +msgstr "" + msgid "Connected wallet not authorized" msgstr "" @@ -3548,9 +3539,6 @@ msgstr "" msgid "No payouts are scheduled for this cycle. All ETH is available for redemption (subject to the redemption rate)." msgstr "" -msgid "Receive {receiveText}" -msgstr "" - msgid "Need artwork?" msgstr "" @@ -4274,9 +4262,6 @@ msgstr "" msgid "What's Juicebox?" msgstr "" -msgid "Current 3rd Party Exchange Rates" -msgstr "" - msgid "Last {TRENDING_WINDOW_DAYS} days" msgstr "" diff --git a/src/packages/v1/components/V1Project/PayProjectForm/PayInputSubText.tsx b/src/packages/v1/components/V1Project/PayProjectForm/PayInputSubText.tsx deleted file mode 100644 index 8f1458caa0..0000000000 --- a/src/packages/v1/components/V1Project/PayProjectForm/PayInputSubText.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import { plural, Trans } from '@lingui/macro' -import { Tooltip } from 'antd' -import AMMPrices from 'components/AMMPrices' -import { CurrencyContext } from 'contexts/CurrencyContext' -import { BigNumber, utils } from 'ethers' -import { useCurrencyConverter } from 'hooks/useCurrencyConverter' -import useWeiConverter from 'hooks/useWeiConverter' -import { CurrencyOption } from 'models/currencyOption' -import { formatIssuanceRate } from 'packages/v2v3/utils/math' -import { useContext, useMemo } from 'react' -import { formattedNum } from 'utils/format/formatNumber' -import { tokenSymbolText } from 'utils/tokenSymbolText' -import { PayProjectFormContext } from './payProjectFormContext' - -/** - * Help text shown below the Pay input field. - * - * If the user has entered an amount, display - * the amount of project tokens they will receive. - * - * Else, display the exchange rate of the user selected currency to project token. - */ -export default function PayInputSubText({ - payInCurrency, - amount, -}: { - payInCurrency: CurrencyOption - amount: string | undefined -}) { - const { - currencyMetadata, - currencies: { ETH }, - } = useContext(CurrencyContext) - const { reservedRate, weight, tokenSymbol, tokenAddress, weightingFn, form } = - useContext(PayProjectFormContext) - - const converter = useCurrencyConverter() - const weiPayAmt = useWeiConverter({ - currency: payInCurrency, - amount: amount, - }) - - const tokenText = tokenSymbolText({ - tokenSymbol, - capitalize: false, - plural: true, - }) - - const receiveText = useMemo(() => { - const formatReceivedTickets = (wei: BigNumber): string | undefined => { - const exchangeRate = weightingFn?.(weight, reservedRate, wei, 'payer') - return exchangeRate - ? formattedNum(formatIssuanceRate(exchangeRate)) - : undefined - } - - if (weiPayAmt?.gt(0)) { - const receivedTickets = formatReceivedTickets(weiPayAmt) - const tokenReceiveText = tokenSymbolText({ - tokenSymbol, - capitalize: false, - plural: receivedTickets !== '1', - }) - const nftCount = form?.payMetadata?.tierIdsToMint.length - const nftText = nftCount - ? plural(nftCount, { - one: '+ # NFT', - other: '+ # NFTs', - }) - : '' - - return `${receivedTickets} ${tokenReceiveText} ${nftText}` - } - - const receivedTickets = formatReceivedTickets( - (payInCurrency === ETH - ? utils.parseEther('1') - : converter.usdToWei('1')) ?? BigNumber.from(0), - ) - - const tokenReceiveText = tokenSymbolText({ - tokenSymbol, - capitalize: false, - plural: receivedTickets !== '1', - }) - - return `${receivedTickets} ${tokenReceiveText}/1 ${currencyMetadata[payInCurrency]?.name}` - }, [ - converter, - payInCurrency, - weiPayAmt, - weight, - currencyMetadata, - ETH, - reservedRate, - tokenSymbol, - form?.payMetadata?.tierIdsToMint.length, - weightingFn, - ]) - - return ( -
- - Receive {receiveText} - - {tokenSymbol && tokenAddress && ( -
- - or{' '} - - } - placement="bottomLeft" - overlayClassName="min-w-xs" - overlayInnerStyle={{ padding: '1rem' }} - > - - buy {tokenText} on an exchange. - - - -
- )} -
- ) -} diff --git a/src/packages/v1/components/V1Project/PayProjectForm/PayProjectForm.tsx b/src/packages/v1/components/V1Project/PayProjectForm/PayProjectForm.tsx index e0c1fa47ea..6e4485c9f5 100644 --- a/src/packages/v1/components/V1Project/PayProjectForm/PayProjectForm.tsx +++ b/src/packages/v1/components/V1Project/PayProjectForm/PayProjectForm.tsx @@ -6,7 +6,6 @@ import { NftRewardsContext } from 'packages/v2v3/contexts/NftRewards/NftRewardsC import { useContext } from 'react' import { fromWad } from 'utils/format/formatNumber' import { getHighestAffordableNft, getNftRewardOfFloor } from 'utils/nftRewards' -import PayInputSubText from './PayInputSubText' import { PayProjectFormContext } from './payProjectFormContext' export function PayProjectForm({ disabled }: { disabled?: boolean }) { @@ -98,10 +97,6 @@ export function PayProjectForm({ disabled }: { disabled?: boolean }) { /> } /> - - -
-

- Redemption rate:{' '} - - {fcMetadata?.bondingCurveRate !== undefined - ? fcMetadata.bondingCurveRate / 2 - : '--'} - % - -

-

- {tokenSymbolText({ tokenSymbol, capitalize: true })} balance:{' '} +

+ {isConstitutionDao ? ( + + + Get more for your PEOPLE. + {' '} +
+ + Check{' '} + + Uniswap + + ,{' '} + + SushiSwap + + , or other third-party exchanges for better rates before + redeeming on Juicebox. + +
+
+ ) : null} +
+
+

+ Your {tokenSymbolText({ tokenSymbol, capitalize: true })} balance:{' '} {totalBalance ? (

-

+ +

+ Current Redemption Rate:{' '} + + {fcMetadata?.bondingCurveRate !== undefined + ? fcMetadata.bondingCurveRate / 2 + : '--'} + % + +

+ +

Currently worth:{' '} @@ -171,13 +210,15 @@ export default function RedeemModal({

+
+

{overflow?.gt(0) ? ( Project tokens can be redeemed to reclaim a portion of the ETH not needed for this cycle's payouts. The amount of ETH returned - depends on this cycle's redemption rate. - + depends on this cycle's redemption rate.{' '} + Tokens are burned when they are redeemed. @@ -215,13 +256,6 @@ export default function RedeemModal({ disabled={totalBalance?.eq(0)} onChange={val => setRedeemAmount(val)} /> - {tokenSymbol && tokenAddress ? ( - - ) : null} {overflow?.gt(0) ? ( @@ -234,7 +268,7 @@ export default function RedeemModal({

) : null}
-
+ ) } diff --git a/src/packages/v2v3/components/V2V3Project/V2V3ManageTokensSection/AccountBalanceDescription/V2V3BurnOrRedeemModal.tsx b/src/packages/v2v3/components/V2V3Project/V2V3ManageTokensSection/AccountBalanceDescription/V2V3BurnOrRedeemModal.tsx index 80f2804007..ba1eb9ca72 100644 --- a/src/packages/v2v3/components/V2V3Project/V2V3ManageTokensSection/AccountBalanceDescription/V2V3BurnOrRedeemModal.tsx +++ b/src/packages/v2v3/components/V2V3Project/V2V3ManageTokensSection/AccountBalanceDescription/V2V3BurnOrRedeemModal.tsx @@ -6,7 +6,6 @@ import { Callout } from 'components/Callout/Callout' import ETHAmount from 'components/currency/ETHAmount' import FormattedNumberInput from 'components/inputs/FormattedNumberInput' import TransactionModal from 'components/modals/TransactionModal' -import { RedeemAMMPrices } from 'components/Project/RedeemAMMPrices' import { TokenAmount } from 'components/TokenAmount' import { ProjectMetadataContext } from 'contexts/ProjectMetadataContext' import { BigNumber } from 'ethers' @@ -301,13 +300,6 @@ export function V2V3BurnOrRedeemModal({ disabled={totalBalance?.eq(0)} onChange={val => setRedeemAmount(val)} /> - {tokenSymbol && tokenAddress ? ( - - ) : null}