From 83e2aa2d56e3a4f664ee221defa67457cb3e5bf9 Mon Sep 17 00:00:00 2001 From: Alissa Crane Date: Tue, 11 Jun 2024 00:04:45 -0400 Subject: [PATCH 1/4] add swap component --- site/docs/components/SwapContainer.tsx | 41 +++++++++++++++++ site/docs/pages/swap/swap.mdx | 61 ++++++++++++++++++++++++++ site/sidebar.ts | 4 ++ src/swap/components/Swap.tsx | 57 ++++++++++++++++++++++++ src/swap/index.ts | 1 + src/swap/types.ts | 3 +- 6 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 site/docs/components/SwapContainer.tsx create mode 100644 site/docs/pages/swap/swap.mdx create mode 100644 src/swap/components/Swap.tsx diff --git a/site/docs/components/SwapContainer.tsx b/site/docs/components/SwapContainer.tsx new file mode 100644 index 0000000000..b7e05a194c --- /dev/null +++ b/site/docs/components/SwapContainer.tsx @@ -0,0 +1,41 @@ +import { ReactElement, useState } from 'react'; +import type { Token } from '@coinbase/onchainkit/token'; + +type SwapContainer = { + children: ( + fromAmount: string, + fromToken: Token, + fromTokenBalance: string, + setFromAmount: (a: string) => void, + setFromToken: (t: Token) => void, + setToToken: (t: Token) => void, + toAmount: string, + toToken: Token, + ) => ReactElement; +}; + +const TOKEN_BALANCE_MAP: Record = { + ETH: '3.5', + USDC: '2.77', + DAI: '4.9', +}; + +export default function SwapContainer({ children }: SwapContainer) { + const [toToken, setToToken] = useState(); + const [fromToken, setFromToken] = useState(); + const [fromAmount, setFromAmount] = useState(''); + const [toAmount, setToAmount] = useState(''); + + const fromTokenBalance = TOKEN_BALANCE_MAP[fromToken?.symbol]; + + return children( + fromAmount, + fromToken, + fromTokenBalance, + setFromAmount, + setFromToken, + setToToken, + toAmount, + toToken, + ); +} diff --git a/site/docs/pages/swap/swap.mdx b/site/docs/pages/swap/swap.mdx new file mode 100644 index 0000000000..174b822fc4 --- /dev/null +++ b/site/docs/pages/swap/swap.mdx @@ -0,0 +1,61 @@ +import { Swap } from '../../../../src/swap'; +import App from '../App'; +import SwapContainer from '../../components/SwapContainer.tsx'; + +# `` + +The `Swap` component... + + + + {( + fromAmount, + fromToken, + fromTokenBalance, + setFromAmount, + setFromToken, + setToToken, + toAmount, + toToken, + ) => ( + + )} + + diff --git a/site/sidebar.ts b/site/sidebar.ts index a13646638d..f9052ddbc0 100644 --- a/site/sidebar.ts +++ b/site/sidebar.ts @@ -143,6 +143,10 @@ export const sidebar = [ { text: 'Components', items: [ + { + text: 'Swap', + link: '/swap/swap', + }, { text: 'SwapAmountInput', link: '/swap/swap-amount-input', diff --git a/src/swap/components/Swap.tsx b/src/swap/components/Swap.tsx new file mode 100644 index 0000000000..681223049a --- /dev/null +++ b/src/swap/components/Swap.tsx @@ -0,0 +1,57 @@ +import { Token } from '../../token'; +import { SwapAmountInput } from './SwapAmountInput'; + +type SwapReact = { + fromAmount?: string; + fromToken?: Token; + fromTokenBalance?: string; + setFromAmount: (amount: string) => void; + setFromToken: () => void; + setToToken: () => void; + swappableTokens: Token[]; + toAmount?: string; + toToken?: Token; +}; + +export function Swap({ + fromAmount, + fromToken, + fromTokenBalance, + setFromAmount, + setFromToken, + setToToken, + swappableTokens, + toAmount, + toToken, +}: SwapReact) { + return ( +
+ + + +
+ +
+
+ ); +} diff --git a/src/swap/index.ts b/src/swap/index.ts index e51725e16b..5a1eaf6ef2 100644 --- a/src/swap/index.ts +++ b/src/swap/index.ts @@ -1,5 +1,6 @@ // 🌲☀️🌲 export { getQuote } from './core/getQuote'; +export { Swap } from './components/Swap' export type { Fee, GetQuoteParams, diff --git a/src/swap/types.ts b/src/swap/types.ts index 684ba8cb30..3ffcaa7a5e 100644 --- a/src/swap/types.ts +++ b/src/swap/types.ts @@ -86,8 +86,9 @@ export type Transaction = { export type SwapAmountInputReact = { amount?: string; // Token amount disabled?: boolean; // Whether the input is disabled + displayMaxButton?: boolean; // Whether the max button is displayed label: string; // Descriptive label for the input field - setAmount: (amount: string) => void; // Callback function when the amount changes + setAmount?: (amount: string) => void; // Callback function when the amount changes setToken: () => void; // Callback function when the token selector is clicked swappableTokens: Token[]; // Tokens available for swap token?: Token; // Selected token From 5cea3aa093c9c23674bb3cf83ed9697910769f9b Mon Sep 17 00:00:00 2001 From: Alissa Crane Date: Tue, 11 Jun 2024 11:59:57 -0400 Subject: [PATCH 2/4] update swap component types --- site/docs/components/SwapContainer.tsx | 6 +- src/swap/components/Swap.tsx | 104 +++++++++++++++++-------- src/swap/types.ts | 21 ++++- 3 files changed, 97 insertions(+), 34 deletions(-) diff --git a/site/docs/components/SwapContainer.tsx b/site/docs/components/SwapContainer.tsx index b7e05a194c..a223748b0e 100644 --- a/site/docs/components/SwapContainer.tsx +++ b/site/docs/components/SwapContainer.tsx @@ -11,6 +11,7 @@ type SwapContainer = { setToToken: (t: Token) => void, toAmount: string, toToken: Token, + toTokenBalance: string, ) => ReactElement; }; @@ -24,10 +25,10 @@ export default function SwapContainer({ children }: SwapContainer) { const [toToken, setToToken] = useState(); const [fromToken, setFromToken] = useState(); const [fromAmount, setFromAmount] = useState(''); - const [toAmount, setToAmount] = useState(''); + const [toAmount, _] = useState(''); const fromTokenBalance = TOKEN_BALANCE_MAP[fromToken?.symbol]; - + const toTokenBalance = TOKEN_BALANCE_MAP[toToken?.symbol]; return children( fromAmount, fromToken, @@ -37,5 +38,6 @@ export default function SwapContainer({ children }: SwapContainer) { setToToken, toAmount, toToken, + toTokenBalance, ); } diff --git a/src/swap/components/Swap.tsx b/src/swap/components/Swap.tsx index 681223049a..8572cb3a9b 100644 --- a/src/swap/components/Swap.tsx +++ b/src/swap/components/Swap.tsx @@ -1,54 +1,96 @@ -import { Token } from '../../token'; +import { useCallback } from 'react'; import { SwapAmountInput } from './SwapAmountInput'; +import { SwapReact, SwapTokensButtonReact } from '../types'; -type SwapReact = { - fromAmount?: string; - fromToken?: Token; - fromTokenBalance?: string; - setFromAmount: (amount: string) => void; - setFromToken: () => void; - setToToken: () => void; - swappableTokens: Token[]; - toAmount?: string; - toToken?: Token; -}; +const swapIcon = ( + + + + + + + + + + +); + +export function SwapTokensButton({ onClick }: SwapTokensButtonReact) { + return ( +
+ {swapIcon} +
+ ); +} export function Swap({ fromAmount, fromToken, fromTokenBalance, + onSubmit, setFromAmount, setFromToken, setToToken, swappableTokens, toAmount, toToken, + toTokenBalance, }: SwapReact) { + const handleSwapTokensClick = useCallback(() => { + if (!toToken || !fromToken) { + return; + } + const prevFromToken = fromToken; + setFromToken(toToken); + setToToken(prevFromToken); + }, [fromToken, toToken, setFromToken, setToToken]); + return (
- - +
+ + + +
-
diff --git a/src/swap/types.ts b/src/swap/types.ts index 3ffcaa7a5e..39bfb087bd 100644 --- a/src/swap/types.ts +++ b/src/swap/types.ts @@ -89,8 +89,27 @@ export type SwapAmountInputReact = { displayMaxButton?: boolean; // Whether the max button is displayed label: string; // Descriptive label for the input field setAmount?: (amount: string) => void; // Callback function when the amount changes - setToken: () => void; // Callback function when the token selector is clicked + setToken: (token: Token) => void; // Callback function when the token selector is clicked swappableTokens: Token[]; // Tokens available for swap token?: Token; // Selected token tokenBalance?: string; // Amount of selected token user owns }; + +export type SwapTokensButtonReact = { + onClick: () => void; +}; + +export type SwapReact = { + fromAmount?: string; // The amount of the token to be sold + fromToken?: Token; // The token that the user is selling + fromTokenBalance?: string; // The balance of the token that the user is selling + // TODO: add argument to this function + onSubmit: () => void; // A callback function to submit the swap transaction + setFromAmount: (amount: string) => void; // A callback function to set the amount of the token to be sold + setFromToken: (token: Token) => void; // A callback function to set the token to be sold + setToToken: (token: Token) => void; // A callback function to set the token to be bought + swappableTokens: Token[]; // An array of tokens available for swapping + toAmount?: string; // The amount of the token to be bought + toToken?: Token; // The token that the user is buying + toTokenBalance?: string; // The balance of the token that the user is buying +}; From a8782b4cf2cde5562718e543e379f0d345069991 Mon Sep 17 00:00:00 2001 From: Alissa Crane Date: Tue, 11 Jun 2024 12:00:09 -0400 Subject: [PATCH 3/4] update docs --- site/docs/pages/swap/swap.mdx | 60 +++++++++++++++++++++++++++++++++- site/docs/pages/swap/types.mdx | 18 ++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/site/docs/pages/swap/swap.mdx b/site/docs/pages/swap/swap.mdx index 174b822fc4..6892733639 100644 --- a/site/docs/pages/swap/swap.mdx +++ b/site/docs/pages/swap/swap.mdx @@ -4,7 +4,59 @@ import SwapContainer from '../../components/SwapContainer.tsx'; # `` -The `Swap` component... +The `Swap` component is a comprehensive interface for users to execute token swaps. It includes two instances of the `SwapAmountInput` component, enabling users to specify the amount of tokens to sell and buy. The `SwapTokensButton` component facilitates the swapping of selected tokens with a single click, dynamically interchanging the tokens in the "Sell" and "Buy" fields. Additionally, the component features a "Swap" button for initiating the transaction. + +## Usage + +:::code-group + +```tsx [code] + +``` + +```html [return html] + +``` + +::: @@ -17,6 +69,7 @@ The `Swap` component... setToToken, toAmount, toToken, + toTokenBalance, ) => ( )} + +## Props + +[`SwapReact`](/swap/types#SwapReact) diff --git a/site/docs/pages/swap/types.mdx b/site/docs/pages/swap/types.mdx index 8e77b70884..319d766b41 100644 --- a/site/docs/pages/swap/types.mdx +++ b/site/docs/pages/swap/types.mdx @@ -19,3 +19,21 @@ type SwapAmountInputReact = { tokenBalance?: string; // Amount of selected token user owns }; ``` + +## `SwapReact` + +```ts +export type SwapReact = { + fromAmount?: string; // The amount of the token to be sold + fromToken?: Token; // The token that the user is selling + fromTokenBalance?: string; // The balance of the token that the user is selling + onSubmit: () => void; // A callback function to submit the swap transaction + setFromAmount: (amount: string) => void; // A callback function to set the amount of the token to be sold + setFromToken: (token: Token) => void; // A callback function to set the token to be sold + setToToken: (token: Token) => void; // A callback function to set the token to be bought + swappableTokens: Token[]; // An array of tokens available for swapping + toAmount?: string; // The amount of the token to be bought + toToken?: Token; // The token that the user is buying + toTokenBalance?: string; // The balance of the token that the user is buying +}; +``` From ff62bfecace356345113e0d7f38c2fc937a1892f Mon Sep 17 00:00:00 2001 From: Alissa Crane Date: Tue, 11 Jun 2024 12:29:21 -0400 Subject: [PATCH 4/4] add onsubmit --- site/docs/pages/swap/swap.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/site/docs/pages/swap/swap.mdx b/site/docs/pages/swap/swap.mdx index 6892733639..c905c3175e 100644 --- a/site/docs/pages/swap/swap.mdx +++ b/site/docs/pages/swap/swap.mdx @@ -15,6 +15,7 @@ The `Swap` component is a comprehensive interface for users to execute token swa fromAmount={fromAmount} fromToken={fromToken} fromTokenBalance={fromTokenBalance} + onSubmit={onSubmit} setFromAmount={setFromAmount} setFromToken={setFromToken} setToToken={setToToken} @@ -75,6 +76,7 @@ The `Swap` component is a comprehensive interface for users to execute token swa fromAmount={fromAmount} fromToken={fromToken} fromTokenBalance={fromTokenBalance} + onSubmit={() => {}} setFromAmount={setFromAmount} setFromToken={setFromToken} setToToken={setToToken}