diff --git a/.changeset/modern-walls-relax.md b/.changeset/modern-walls-relax.md deleted file mode 100644 index c254d46628..0000000000 --- a/.changeset/modern-walls-relax.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@coinbase/onchainkit': patch ---- - -- **fix**: add spacing between swap input and token select. By @alessey #1229 diff --git a/.changeset/shy-foxes-jog.md b/.changeset/shy-foxes-jog.md new file mode 100644 index 0000000000..5a3e97d56a --- /dev/null +++ b/.changeset/shy-foxes-jog.md @@ -0,0 +1,7 @@ +--- +'@coinbase/onchainkit': patch +--- + +- **feat**: introduced `config` for the `Swap` component, with the first option for `maxSlippage`. By @zizzamia & @cpcramer #1242 +- **fix**: added spacing between swap input and token select. By @alessey #1229 +- **feat**: added slippage support in `Swap` component with settings UI. This combined feat incorporates slippage functionality into the Swap component, including a dedicated settings section with a title, description, and input field for configuring slippage tolerance. By @cpcramer #1187 #1192 #1191 #1189 #1195 #1196 #1206 diff --git a/package.json b/package.json index 675949cb48..cde8a201b2 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "wagmi": "^2.11.0" }, "devDependencies": { - "@biomejs/biome": "^1.8.0", + "@biomejs/biome": "1.8.3", "@changesets/changelog-github": "^0.4.8", "@changesets/cli": "^2.26.2", "@chromatic-com/storybook": "^1.7.0", diff --git a/src/swap/components/Swap.tsx b/src/swap/components/Swap.tsx index b9d790efb6..32ed5a6367 100644 --- a/src/swap/components/Swap.tsx +++ b/src/swap/components/Swap.tsx @@ -2,6 +2,7 @@ import { Children, useMemo } from 'react'; import { findComponent } from '../../internal/utils/findComponent'; import { background, cn, text } from '../../styles/theme'; import { useIsMounted } from '../../useIsMounted'; +import { DEFAULT_MAX_SLIPPAGE } from '../constants'; import type { SwapReact } from '../types'; import { SwapAmountInput } from './SwapAmountInput'; import { SwapButton } from './SwapButton'; @@ -12,6 +13,9 @@ import { SwapToggleButton } from './SwapToggleButton'; export function Swap({ children, + config = { + maxSlippage: DEFAULT_MAX_SLIPPAGE, + }, className, experimental = { useAggregator: true }, onError, @@ -39,6 +43,7 @@ export function Swap({ } return ( <SwapProvider + config={config} experimental={experimental} onError={onError} onStatus={onStatus} diff --git a/src/swap/components/SwapProvider.test.tsx b/src/swap/components/SwapProvider.test.tsx index 7e03aff084..8cc2e6590c 100644 --- a/src/swap/components/SwapProvider.test.tsx +++ b/src/swap/components/SwapProvider.test.tsx @@ -49,7 +49,7 @@ vi.mock('../path/to/maxSlippageModule', () => ({ const queryClient = new QueryClient(); -const config = createConfig({ +const accountConfig = createConfig({ chains: [base], connectors: [ mock({ @@ -66,9 +66,12 @@ const config = createConfig({ }); const wrapper = ({ children }) => ( - <WagmiProvider config={config}> + <WagmiProvider config={accountConfig}> <QueryClientProvider client={queryClient}> - <SwapProvider experimental={{ useAggregator: true, maxSlippage: 5 }}> + <SwapProvider + config={{ maxSlippage: 5 }} + experimental={{ useAggregator: true }} + > {children} </SwapProvider> </QueryClientProvider> @@ -81,11 +84,13 @@ const renderWithProviders = ({ onStatus = vi.fn(), onSuccess = vi.fn(), }) => { - const mockExperimental = { useAggregator: true, maxSlippage: 10 }; + const config = { maxSlippage: 10 }; + const mockExperimental = { useAggregator: true }; return render( - <WagmiProvider config={config}> + <WagmiProvider config={accountConfig}> <QueryClientProvider client={queryClient}> <SwapProvider + config={config} experimental={mockExperimental} onError={onError} onStatus={onStatus} @@ -748,10 +753,11 @@ describe('SwapProvider', () => { const { lifeCycleStatus } = useSwapContext(); return lifeCycleStatus; }; + const config = { maxSlippage: 3 }; const wrapper = ({ children }) => ( - <WagmiProvider config={config}> + <WagmiProvider config={accountConfig}> <QueryClientProvider client={queryClient}> - <SwapProvider experimental={{ useAggregator: true }}> + <SwapProvider config={config} experimental={{ useAggregator: true }}> {children} </SwapProvider> </QueryClientProvider> diff --git a/src/swap/components/SwapProvider.tsx b/src/swap/components/SwapProvider.tsx index fecec06fe8..e9f9a7d980 100644 --- a/src/swap/components/SwapProvider.tsx +++ b/src/swap/components/SwapProvider.tsx @@ -39,6 +39,9 @@ export function useSwapContext() { export function SwapProvider({ children, + config = { + maxSlippage: DEFAULT_MAX_SLIPPAGE, + }, experimental, onError, onStatus, @@ -47,11 +50,8 @@ export function SwapProvider({ const { address } = useAccount(); // Feature flags const { useAggregator } = experimental; - const [initialMaxSlippage, _setInitialMaxSlippage] = useState( - experimental.maxSlippage || DEFAULT_MAX_SLIPPAGE, - ); // Core Hooks - const config = useConfig(); + const accountConfig = useConfig(); const [loading, setLoading] = useState(false); const [error, setError] = useState<SwapError>(); const [isTransactionPending, setPendingTransaction] = useState(false); @@ -59,7 +59,7 @@ export function SwapProvider({ statusName: 'init', statusData: { isMissingRequiredField: true, - maxSlippage: initialMaxSlippage, + maxSlippage: config.maxSlippage, }, }); // Component lifecycle const [hasHandledSuccess, setHasHandledSuccess] = useState(false); @@ -300,7 +300,7 @@ export function SwapProvider({ return; } await processSwapTransaction({ - config, + config: accountConfig, lifeCycleStatus, sendTransactionAsync, setLifeCycleStatus, @@ -327,8 +327,8 @@ export function SwapProvider({ }); } }, [ + accountConfig, address, - config, from.amount, from.token, lifeCycleStatus, diff --git a/src/swap/types.ts b/src/swap/types.ts index 138c1c8b0e..0a5f5fd482 100644 --- a/src/swap/types.ts +++ b/src/swap/types.ts @@ -193,9 +193,11 @@ export type SwapParams = { export type SwapProviderReact = { children: React.ReactNode; + config?: { + maxSlippage: number; // Maximum acceptable slippage for a swap. (default: 10) This is as a percent, not basis points + }; experimental: { useAggregator: boolean; // Whether to use a DEX aggregator. (default: true) - maxSlippage?: number; // Maximum acceptable slippage for a swap. (default: 10) This is as a percent, not basis points }; onError?: (error: SwapError) => void; // An optional callback function that handles errors within the provider. onStatus?: (lifeCycleStatus: LifeCycleStatus) => void; // An optional callback function that exposes the component lifecycle state @@ -208,9 +210,11 @@ export type SwapProviderReact = { export type SwapReact = { children: ReactNode; className?: string; // Optional className override for top div element. + config?: { + maxSlippage: number; // Maximum acceptable slippage for a swap. (default: 10) This is as a percent, not basis points + }; experimental?: { useAggregator: boolean; // Whether to use a DEX aggregator. (default: true) - maxSlippage?: number; // Maximum acceptable slippage for a swap. (default: 10) This is as a percent, not basis points }; onError?: (error: SwapError) => void; // An optional callback function that handles errors within the provider. onStatus?: (lifeCycleStatus: LifeCycleStatus) => void; // An optional callback function that exposes the component lifecycle state diff --git a/yarn.lock b/yarn.lock index 12687adba8..39f13b1536 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1612,7 +1612,7 @@ __metadata: languageName: node linkType: hard -"@biomejs/biome@npm:^1.8.0": +"@biomejs/biome@npm:1.8.3": version: 1.8.3 resolution: "@biomejs/biome@npm:1.8.3" dependencies: @@ -2172,7 +2172,7 @@ __metadata: version: 0.0.0-use.local resolution: "@coinbase/onchainkit@workspace:." dependencies: - "@biomejs/biome": "npm:^1.8.0" + "@biomejs/biome": "npm:1.8.3" "@changesets/changelog-github": "npm:^0.4.8" "@changesets/cli": "npm:^2.26.2" "@chromatic-com/storybook": "npm:^1.7.0"