From 6a1c7d39c15e6d692e71dc2b51ea0d4f27fa8e0d Mon Sep 17 00:00:00 2001 From: Chef Penguin Date: Mon, 4 Nov 2024 16:50:00 +0530 Subject: [PATCH 1/5] chore: revert from free to discounted swaps on zksync --- apps/web/src/config/paymaster.ts | 54 +++++++++++--------------------- 1 file changed, 18 insertions(+), 36 deletions(-) diff --git a/apps/web/src/config/paymaster.ts b/apps/web/src/config/paymaster.ts index eb5029fa0f6f8..b705119b70187 100644 --- a/apps/web/src/config/paymaster.ts +++ b/apps/web/src/config/paymaster.ts @@ -7,11 +7,11 @@ import addresses from 'config/constants/contracts' import { getAddressFromMap } from 'utils/addressHelpers' import { Address, Hex } from 'viem' -// export const DEFAULT_PAYMASTER_TOKEN = Native.onChain(ChainId.ZKSYNC) +export const DEFAULT_PAYMASTER_TOKEN = Native.onChain(ChainId.ZKSYNC) export const paymasterTokens: Currency[] = [ - // DEFAULT_PAYMASTER_TOKEN, - Native.onChain(ChainId.ZKSYNC), + DEFAULT_PAYMASTER_TOKEN, + zksyncTokens.zk, zksyncTokens.wbtc, zksyncTokens.dai, zksyncTokens.usdc, @@ -26,73 +26,55 @@ export const paymasterTokens: Currency[] = [ zksyncTokens.weth, zksyncTokens.wethe, zksyncTokens.hold, - zksyncTokens.zk, ] -export const DEFAULT_PAYMASTER_TOKEN = paymasterTokens[4] - export const paymasterInfo: { [gasTokenAddress: Address]: { discount: `-${number}%` | 'FREE'; discountLabel?: string } } = { [zksyncTokens.wbtc.address]: { - discount: 'FREE', // Example: -20%, FREE - discountLabel: 'FREE SWAP', + discount: '-20%', // Example: -20%, FREE }, [zksyncTokens.dai.address]: { - discount: 'FREE', - discountLabel: 'FREE SWAP', + discount: '-20%', }, [zksyncTokens.usdc.address]: { - discount: 'FREE', - discountLabel: 'FREE SWAP', + discount: '-20%', }, [zksyncTokens.usdcNative.address]: { - discount: 'FREE', - discountLabel: 'FREE SWAP', + discount: '-20%', }, [zksyncTokens.usdt.address]: { - discount: 'FREE', - discountLabel: 'FREE SWAP', + discount: '-20%', }, [zksyncTokens.grai.address]: { - discount: 'FREE', - discountLabel: 'FREE SWAP', + discount: '-20%', }, [zksyncTokens.tes.address]: { - discount: 'FREE', - discountLabel: 'FREE SWAP', + discount: '-20%', }, [zksyncTokens.busd.address]: { - discount: 'FREE', - discountLabel: 'FREE SWAP', + discount: '-20%', }, [zksyncTokens.reth.address]: { - discount: 'FREE', - discountLabel: 'FREE SWAP', + discount: '-20%', }, [zksyncTokens.wstETH.address]: { - discount: 'FREE', - discountLabel: 'FREE SWAP', + discount: '-20%', }, [zksyncTokens.meow.address]: { - discount: 'FREE', - discountLabel: 'FREE SWAP', + discount: '-20%', }, [zksyncTokens.weth.address]: { - discount: 'FREE', - discountLabel: 'FREE SWAP', + discount: '-20%', }, [zksyncTokens.wethe.address]: { - discount: 'FREE', - discountLabel: 'FREE SWAP', + discount: '-20%', }, [zksyncTokens.hold.address]: { - discount: 'FREE', - discountLabel: 'FREE SWAP', + discount: '-20%', }, [zksyncTokens.zk.address]: { - discount: 'FREE', - discountLabel: 'FREE SWAP', + discount: '-40%', }, } From 6a6b7f61736c08879453bcb8d6707a3b76888bf6 Mon Sep 17 00:00:00 2001 From: Chef Penguin Date: Mon, 4 Nov 2024 16:56:25 +0530 Subject: [PATCH 2/5] chore: gas token help text --- .../components/Paymaster/GasTokenSelector.tsx | 18 ++++++++++-------- apps/web/src/pages/api/paymaster/index.ts | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/apps/web/src/components/Paymaster/GasTokenSelector.tsx b/apps/web/src/components/Paymaster/GasTokenSelector.tsx index e14f0032fba9c..aad6a686e4008 100644 --- a/apps/web/src/components/Paymaster/GasTokenSelector.tsx +++ b/apps/web/src/components/Paymaster/GasTokenSelector.tsx @@ -6,6 +6,7 @@ import { Button, CircleLoader, Column, + DottedHelpText, Flex, Heading, ModalBody, @@ -15,6 +16,7 @@ import { ModalTitle, ModalV2, QuestionHelper, + QuestionHelperV2, RowBetween, RowFixed, Text, @@ -265,12 +267,9 @@ export const GasTokenSelector = ({ currency: inputCurrency }: GasTokenSelectorPr return ( <> - + - - {t('Gas Token')} - - @@ -285,11 +284,14 @@ export const GasTokenSelector = ({ currency: inputCurrency }: GasTokenSelectorPr } - ml="4px" placement="top" - /> + > + + {t('Gas Token')} + + {gasTokenInfo && gasTokenInfo.discount && ( - + ⛽️ {gasTokenInfo.discountLabel ?? gasTokenInfo.discount} )} diff --git a/apps/web/src/pages/api/paymaster/index.ts b/apps/web/src/pages/api/paymaster/index.ts index 487775a090a7e..a45689d1ea012 100644 --- a/apps/web/src/pages/api/paymaster/index.ts +++ b/apps/web/src/pages/api/paymaster/index.ts @@ -25,7 +25,7 @@ const handler: NextApiHandler = async (req, res) => { // Check calldata for ERC20 approve const decodedCalldata = decodeFunctionData({ data: call.calldata, abi: erc20Abi }) if (decodedCalldata.functionName === 'approve') isTransactionWhitelisted = true - } catch (e) { + } catch { // do nothing. must be another type of transaction if decoding failed } From 306e8fcc6e70926cfaf187d7e8f5ffd90bb7ae88 Mon Sep 17 00:00:00 2001 From: Chef Penguin Date: Mon, 4 Nov 2024 17:45:18 +0530 Subject: [PATCH 3/5] chore: whitelist cake as gas token --- apps/web/src/config/paymaster.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/web/src/config/paymaster.ts b/apps/web/src/config/paymaster.ts index b705119b70187..b72052c22f5c6 100644 --- a/apps/web/src/config/paymaster.ts +++ b/apps/web/src/config/paymaster.ts @@ -12,6 +12,7 @@ export const DEFAULT_PAYMASTER_TOKEN = Native.onChain(ChainId.ZKSYNC) export const paymasterTokens: Currency[] = [ DEFAULT_PAYMASTER_TOKEN, zksyncTokens.zk, + zksyncTokens.cake, zksyncTokens.wbtc, zksyncTokens.dai, zksyncTokens.usdc, @@ -31,8 +32,11 @@ export const paymasterTokens: Currency[] = [ export const paymasterInfo: { [gasTokenAddress: Address]: { discount: `-${number}%` | 'FREE'; discountLabel?: string } } = { + [zksyncTokens.zk.address]: { + discount: '-40%', + }, [zksyncTokens.wbtc.address]: { - discount: '-20%', // Example: -20%, FREE + discount: '-20%', }, [zksyncTokens.dai.address]: { discount: '-20%', @@ -73,8 +77,8 @@ export const paymasterInfo: { [zksyncTokens.hold.address]: { discount: '-20%', }, - [zksyncTokens.zk.address]: { - discount: '-40%', + [zksyncTokens.cake.address]: { + discount: '-20%', }, } From 360a3118a4cfc31040b3f17ad59a27bec69baa5d Mon Sep 17 00:00:00 2001 From: Chef Penguin Date: Mon, 4 Nov 2024 19:56:55 +0530 Subject: [PATCH 4/5] chore: new gas token selector location and design --- .../components/Paymaster/GasTokenSelector.tsx | 21 +++++++++++-------- .../Swap/V3Swap/containers/TradeDetails.tsx | 6 ++++-- .../V4Swap/AdvancedSwapDetails.tsx | 5 +---- .../V4Swap/ButtonAndDetailsPanel.tsx | 9 ++++++-- .../SwapSimplify/V4Swap/TradeDetails.tsx | 5 ----- .../src/views/SwapSimplify/V4Swap/index.tsx | 7 +++++++ 6 files changed, 31 insertions(+), 22 deletions(-) diff --git a/apps/web/src/components/Paymaster/GasTokenSelector.tsx b/apps/web/src/components/Paymaster/GasTokenSelector.tsx index aad6a686e4008..e68f349c6bb2f 100644 --- a/apps/web/src/components/Paymaster/GasTokenSelector.tsx +++ b/apps/web/src/components/Paymaster/GasTokenSelector.tsx @@ -2,6 +2,7 @@ import { useTranslation } from '@pancakeswap/localization' import { ArrowDropDownIcon, ArrowForwardIcon, + AtomBoxProps, Box, Button, CircleLoader, @@ -41,8 +42,10 @@ import { DEFAULT_PAYMASTER_TOKEN, paymasterInfo, paymasterTokens } from 'config/ import { useGasToken } from 'hooks/useGasToken' // Selector Styles -const GasTokenSelectButton = styled(Button).attrs({ variant: 'text', scale: 'xs' })` - padding: 18px 0 18px 6px; +const GasTokenSelectButton = styled(Button).attrs({ variant: 'tertiary', scale: 'xs' })` + padding: 16px 0 14px 6px; + border-radius: 12px; + border-bottom: 2px solid rgba(0, 0, 0, 0.1); ` // Modal Styles @@ -108,7 +111,7 @@ const SameTokenWarningBox = styled(Box)` font-size: 13px; background-color: #ffb2371a; padding: 10px; - margin: 5px 0 8px; + margin-bottom: 8px; color: ${({ theme }) => theme.colors.yellow}; border: 1px solid ${({ theme }) => theme.colors.yellow}; border-radius: ${({ theme }) => theme.radii['12px']}; @@ -118,11 +121,11 @@ const StyledWarningIcon = styled(WarningIcon)` fill: ${({ theme }) => theme.colors.yellow}; ` -interface GasTokenSelectorProps { - currency?: Currency +interface GasTokenSelectorProps extends AtomBoxProps { + inputCurrency?: Currency } -export const GasTokenSelector = ({ currency: inputCurrency }: GasTokenSelectorProps) => { +export const GasTokenSelector = ({ inputCurrency, ...props }: GasTokenSelectorProps) => { const { t } = useTranslation() const { isOpen, setIsOpen, onDismiss } = useModalV2() const { address: account } = useAccount() @@ -267,7 +270,7 @@ export const GasTokenSelector = ({ currency: inputCurrency }: GasTokenSelectorPr return ( <> - + ⛽️

- + {(gasToken && gasToken.symbol && gasToken.symbol.length > 10 ? `${gasToken.symbol.slice(0, 4)}...${gasToken.symbol.slice( gasToken.symbol.length - 5, @@ -317,7 +320,7 @@ export const GasTokenSelector = ({ currency: inputCurrency }: GasTokenSelectorPr )}` : gasToken?.symbol) || ''} - +
diff --git a/apps/web/src/views/Swap/V3Swap/containers/TradeDetails.tsx b/apps/web/src/views/Swap/V3Swap/containers/TradeDetails.tsx index 541bf08d94601..0ab321d1e4403 100644 --- a/apps/web/src/views/Swap/V3Swap/containers/TradeDetails.tsx +++ b/apps/web/src/views/Swap/V3Swap/containers/TradeDetails.tsx @@ -5,9 +5,9 @@ import { memo, useMemo } from 'react' import { TradeSummary } from 'views/Swap/components/AdvancedSwapDetails' import { AdvancedDetailsFooter } from 'views/Swap/components/AdvancedSwapDetailsDropdown' +import { PriceOrder } from '@pancakeswap/price-api-sdk' import { GasTokenSelector } from 'components/Paymaster/GasTokenSelector' import { usePaymaster } from 'hooks/usePaymaster' -import { PriceOrder } from '@pancakeswap/price-api-sdk' import { isClassicOrder, isXOrder } from 'views/Swap/utils' import { RoutesBreakdown, XRoutesBreakdown } from '../components' import { useIsWrapping, useSlippageAdjustedAmounts } from '../hooks' @@ -53,7 +53,9 @@ export const TradeDetails = memo(function TradeDetails({ loaded, order }: Props) priceImpactWithoutFee={priceImpactWithoutFee ?? undefined} realizedLPFee={lpFeeAmount ?? undefined} hasStablePair={hasStablePool} - gasTokenSelector={isPaymasterAvailable && inputAmount && } + gasTokenSelector={ + isPaymasterAvailable && inputAmount && + } /> {isXOrder(order) ? : } diff --git a/apps/web/src/views/SwapSimplify/V4Swap/AdvancedSwapDetails.tsx b/apps/web/src/views/SwapSimplify/V4Swap/AdvancedSwapDetails.tsx index 4b03179841d59..bb63025876460 100644 --- a/apps/web/src/views/SwapSimplify/V4Swap/AdvancedSwapDetails.tsx +++ b/apps/web/src/views/SwapSimplify/V4Swap/AdvancedSwapDetails.tsx @@ -15,7 +15,7 @@ import { } from '@pancakeswap/uikit' import { formatAmount, formatFraction } from '@pancakeswap/utils/formatFractions' import { useUserSlippage } from '@pancakeswap/utils/user' -import React, { memo, useState } from 'react' +import { memo, useState } from 'react' import { NumberDisplay } from '@pancakeswap/widgets-internal' import { RowBetween, RowFixed } from 'components/Layout/Row' @@ -44,7 +44,6 @@ export const TradeSummary = memo(function TradeSummary({ slippageAdjustedAmounts, priceImpactWithoutFee, realizedLPFee, - gasTokenSelector, isX = false, loading = false, }: { @@ -55,7 +54,6 @@ export const TradeSummary = memo(function TradeSummary({ slippageAdjustedAmounts: SlippageAdjustedAmounts priceImpactWithoutFee?: Percent | null realizedLPFee?: CurrencyAmount | null - gasTokenSelector?: React.ReactNode isX?: boolean loading?: boolean }) { @@ -66,7 +64,6 @@ export const TradeSummary = memo(function TradeSummary({ return ( - {gasTokenSelector} theme.colors.cardBorder}; ` interface ButtonAndDetailsPanelProps { + shouldRenderDetails?: boolean + swapCommitButton: React.ReactNode pricingAndSlippage: React.ReactNode tradeDetails: React.ReactNode - shouldRenderDetails?: boolean + + gasTokenSelector?: React.ReactNode } export const ButtonAndDetailsPanel: React.FC = ({ + shouldRenderDetails, swapCommitButton, pricingAndSlippage, tradeDetails, - shouldRenderDetails, + gasTokenSelector, }) => { const [isOpen, setIsOpen] = useState(false) return ( {swapCommitButton} + {gasTokenSelector} {shouldRenderDetails && ( } loading={!loaded} /> diff --git a/apps/web/src/views/SwapSimplify/V4Swap/index.tsx b/apps/web/src/views/SwapSimplify/V4Swap/index.tsx index a263903f0bd94..d5c502a75f787 100644 --- a/apps/web/src/views/SwapSimplify/V4Swap/index.tsx +++ b/apps/web/src/views/SwapSimplify/V4Swap/index.tsx @@ -5,9 +5,11 @@ import { useUserSlippage } from '@pancakeswap/utils/user' import { SwapUIV2 } from '@pancakeswap/widgets-internal' import { useTokenRisk } from 'components/AccessRisk' import { RiskDetailsPanel, useShouldRiskPanelDisplay } from 'components/AccessRisk/SwapRevampRiskDisplay' +import { GasTokenSelector } from 'components/Paymaster/GasTokenSelector' import { useCurrency } from 'hooks/Tokens' import { useActiveChainId } from 'hooks/useActiveChainId' import { useCurrencyUsdPrice } from 'hooks/useCurrencyUsdPrice' +import { usePaymaster } from 'hooks/usePaymaster' import { useMemo } from 'react' import { Field } from 'state/swap/actions' import { useSwapState } from 'state/swap/hooks' @@ -120,6 +122,8 @@ export function V4SwapForm() { const token0Risk = useTokenRisk(inputCurrency?.wrapped) const token1Risk = useTokenRisk(outputCurrency?.wrapped) + const { isPaymasterAvailable } = usePaymaster() + return ( @@ -180,6 +184,9 @@ export function V4SwapForm() { } tradeDetails={} + gasTokenSelector={ + isPaymasterAvailable && + } shouldRenderDetails={Boolean(executionPrice) && Boolean(bestOrder) && !isWrapping} /> From 2fffad9538e8a41edbe3676445fd60c63f46af26 Mon Sep 17 00:00:00 2001 From: Chef Penguin Date: Tue, 5 Nov 2024 10:00:22 +0530 Subject: [PATCH 5/5] chore: paymaster whitelist only if txn is sponsored --- apps/web/src/config/paymaster.ts | 2 +- apps/web/src/pages/api/paymaster/index.ts | 28 ++++++++++++----------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/apps/web/src/config/paymaster.ts b/apps/web/src/config/paymaster.ts index b72052c22f5c6..dc313e12b9552 100644 --- a/apps/web/src/config/paymaster.ts +++ b/apps/web/src/config/paymaster.ts @@ -83,7 +83,7 @@ export const paymasterInfo: { } /** - * Contracts that the paymaster is allowed to interact with. + * Contracts that the paymaster is allowed to interact with if transaction is sponsored. * In addition, ERC20 Approve transactions are allowed. */ export const PAYMASTER_CONTRACT_WHITELIST = [ diff --git a/apps/web/src/pages/api/paymaster/index.ts b/apps/web/src/pages/api/paymaster/index.ts index a45689d1ea012..600bf0db5f205 100644 --- a/apps/web/src/pages/api/paymaster/index.ts +++ b/apps/web/src/pages/api/paymaster/index.ts @@ -19,22 +19,24 @@ const handler: NextApiHandler = async (req, res) => { } try { - let isTransactionWhitelisted = PAYMASTER_CONTRACT_WHITELIST.includes(call.address.toLowerCase()) + const gasTokenInfo = paymasterInfo[gasTokenAddress] + const isSponsored = gasTokenInfo?.discount === 'FREE' - try { - // Check calldata for ERC20 approve - const decodedCalldata = decodeFunctionData({ data: call.calldata, abi: erc20Abi }) - if (decodedCalldata.functionName === 'approve') isTransactionWhitelisted = true - } catch { - // do nothing. must be another type of transaction if decoding failed - } + if (isSponsored) { + let isTransactionWhitelisted = PAYMASTER_CONTRACT_WHITELIST.includes(call.address.toLowerCase()) - if (!isTransactionWhitelisted) { - return res.status(400).json({ error: 'Transaction type not whitelisted for Paymaster' }) - } + try { + // Check calldata for ERC20 approve + const decodedCalldata = decodeFunctionData({ data: call.calldata, abi: erc20Abi }) + if (decodedCalldata.functionName === 'approve') isTransactionWhitelisted = true + } catch { + // do nothing. must be another type of transaction if decoding failed + } - const gasTokenInfo = paymasterInfo[gasTokenAddress] - const isSponsored = gasTokenInfo?.discount === 'FREE' + if (!isTransactionWhitelisted) { + return res.status(400).json({ error: 'Transaction type not whitelisted for Paymaster' }) + } + } const PAYMASTER_URL = isSponsored ? ZYFI_SPONSORED_PAYMASTER_URL : ZYFI_PAYMASTER_URL const gas = calculateGasMargin(BigInt(call.gas), 2000n)