diff --git a/packages/dex-widget/src/types.ts b/packages/dex-widget/src/types.ts index 4643e65..2e98acd 100644 --- a/packages/dex-widget/src/types.ts +++ b/packages/dex-widget/src/types.ts @@ -385,6 +385,7 @@ export interface IWidgetProps { providerType: ProviderType; walletType: WalletType; tokenPair?: IFormattedTokenPair; + bridgeTokenPair?: IFormattedTokenPair; lang?: string; chainIds?: string[]; } @@ -417,6 +418,8 @@ export interface IWidgetParams { tokenPair?: ITokenPair; + bridgeTokenPair?: ITokenPair; + lang?: string; chainIds?: string[]; diff --git a/packages/dex-widget/src/verifyParamsUtils.ts b/packages/dex-widget/src/verifyParamsUtils.ts index 9d81b8e..81c8e2f 100644 --- a/packages/dex-widget/src/verifyParamsUtils.ts +++ b/packages/dex-widget/src/verifyParamsUtils.ts @@ -7,6 +7,7 @@ export const ERROR_MSG = { INVALID_FEE_CONFIG: 'FeeConfig MUST be an object', INVALID_FEE_PERCENT: 'FeePercent MUST be a number > 0 and <= 3', INVALID_TOKEN_PAIR: 'Invalid tokenPair', + INVALID_BRIDGE_TOKEN_PAIR: 'Invalid bridgeTokenPair', INVALID_PROVIDER_TYPE: 'Invalid providerType', INVALID_WIDGET_VERSION: 'WIDGET_VERSION IS REQUIRED', }; @@ -68,7 +69,7 @@ export const checkTokenPairChain = (tokenPair: ITokenPair) => { return verifyChainId(tokenPair?.fromChain) && verifyChainId(tokenPair?.toChain); }; -export const verifyWidgetParams = ({ widgetVersion, feeConfig = {}, tokenPair, providerType }) => { +export const verifyWidgetParams = ({ widgetVersion, feeConfig = {}, tokenPair, bridgeTokenPair, providerType }) => { const walletType = WALLET_TYPE[providerType]; if (!widgetVersion) { @@ -80,6 +81,9 @@ export const verifyWidgetParams = ({ widgetVersion, feeConfig = {}, tokenPair, p if (tokenPair && !checkTokenPairChain(tokenPair)) { throw new Error(ERROR_MSG.INVALID_TOKEN_PAIR); } + if (bridgeTokenPair && !checkTokenPairChain(bridgeTokenPair)) { + throw new Error(ERROR_MSG.INVALID_BRIDGE_TOKEN_PAIR); + } const errorTips = checkFeeConfig(feeConfig); if (errorTips) { throw new Error(errorTips); diff --git a/packages/dex-widget/src/widgetHelp.ts b/packages/dex-widget/src/widgetHelp.ts index 1b84756..adfe8af 100644 --- a/packages/dex-widget/src/widgetHelp.ts +++ b/packages/dex-widget/src/widgetHelp.ts @@ -24,34 +24,71 @@ export const WALLET_TYPE: TWalletTypeRecord = { export const SOLANA_CHAIN_ID = 501; -export function getSupportTradeTypeAndRoute( + +export const formatTokenPair = (tokenPair?: ITokenPair): IFormattedTokenPair => { + return tokenPair + ? { + inputChain: tokenPair.fromChain, + outputChain: tokenPair.toChain, + inputCurrency: tokenPair.fromToken, + outputCurrency: tokenPair.toToken, + } + : null; +}; + +// this function is designed to determine the supported trade types and the appropriate route based on the provided trade type and token pairs. +// It returns an object containing the supported trade types, the route, and formatted token pairs. +export function formatDefaultConfig( tradeType: TradeType, tokenPair?: ITokenPair, -): { supportTradeType: TradeType[]; route: string } { - let supportTradeType = []; - let route = ''; + bridgeTokenPair?: ITokenPair, +): { + supportTradeType: TradeType[]; + route: string; + defaultTokenPair?: IFormattedTokenPair, + formattedTokenPair?: IFormattedTokenPair, + formattedBridgeTokenPair?: IFormattedTokenPair +} { + const formattedTokenPair = formatTokenPair(tokenPair); + const formattedBridgeTokenPair = formatTokenPair(bridgeTokenPair); + if (tradeType === TradeType.SWAP) { - supportTradeType = [TradeType.SWAP]; - route = WIDGET_ROUTE_CONSTANTS.SWAP; - } else if (tradeType === TradeType.BRIDGE) { - supportTradeType = [TradeType.BRIDGE]; - route = WIDGET_ROUTE_CONSTANTS.BRIDGE; - } else { - supportTradeType = [TradeType.SWAP, TradeType.BRIDGE]; - - route = - !tokenPair || isSameChain(tokenPair) - ? WIDGET_ROUTE_CONSTANTS.SWAP - : WIDGET_ROUTE_CONSTANTS.BRIDGE; + return { + supportTradeType: [TradeType.SWAP], + route: WIDGET_ROUTE_CONSTANTS.SWAP, + defaultTokenPair: formattedTokenPair, + formattedTokenPair, + formattedBridgeTokenPair: null, + }; + } + + if (tradeType === TradeType.BRIDGE) { + return { + supportTradeType: [TradeType.BRIDGE], + route: WIDGET_ROUTE_CONSTANTS.BRIDGE, + defaultTokenPair: formattedBridgeTokenPair, + formattedTokenPair: null, + formattedBridgeTokenPair, + }; } + + const defaultIsBridge = !formattedTokenPair && formattedBridgeTokenPair; + const route = defaultIsBridge + ? WIDGET_ROUTE_CONSTANTS.BRIDGE + : WIDGET_ROUTE_CONSTANTS.SWAP; + const defaultTokenPair = defaultIsBridge ? formattedBridgeTokenPair : formattedTokenPair; + return { - supportTradeType, + supportTradeType: [TradeType.SWAP, TradeType.BRIDGE], route, + defaultTokenPair, + formattedTokenPair, + formattedBridgeTokenPair, }; } export const createWidgetParams = (widgetParams: IWidgetParams): IFormattedWidgetProps => { - const { baseUrl, feeConfig, tokenPair, providerType, tradeType, theme, lang, chainIds } = + const { baseUrl, feeConfig, tokenPair, bridgeTokenPair, providerType, tradeType, theme, lang, chainIds } = widgetParams; const widgetVersion = process.env.WIDGET_VERSION; @@ -60,21 +97,18 @@ export const createWidgetParams = (widgetParams: IWidgetParams): IFormattedWidge widgetVersion, feeConfig, tokenPair, + bridgeTokenPair, providerType, }); - // get trade type config and route - const { supportTradeType, route } = getSupportTradeTypeAndRoute(tradeType, tokenPair); - - // trans token pair params for dex - const tokenPairParams: IFormattedTokenPair = tokenPair - ? { - inputChain: tokenPair.fromChain, - outputChain: tokenPair.toChain, - inputCurrency: tokenPair.fromToken, - outputCurrency: tokenPair.toToken, - } - : {}; + // get trade type config, route, default token pair and formatted tokenPair/bridgeTokenPair config + const { + supportTradeType, + route, + defaultTokenPair, + formattedTokenPair, + formattedBridgeTokenPair, + } = formatDefaultConfig(tradeType, tokenPair, bridgeTokenPair); // define initial params const initParams = { @@ -89,7 +123,7 @@ export const createWidgetParams = (widgetParams: IWidgetParams): IFormattedWidge // add token info to url params const urlParams = { ...initParams, - ...tokenPairParams, + ...defaultTokenPair, }; const params = new URLSearchParams(); // Append non-empty key-value pairs to URLSearchParams @@ -110,7 +144,8 @@ export const createWidgetParams = (widgetParams: IWidgetParams): IFormattedWidge // add tokenPair, feeConfig, providerType to generate data const data = { ...initParams, - tokenPair: tokenPairParams, + tokenPair: formattedTokenPair, + bridgeTokenPair: formattedBridgeTokenPair, feeConfig, providerType, }; diff --git a/packages/widget-configurator/src/app/configurator/controls/TokenPairControl.tsx b/packages/widget-configurator/src/app/configurator/controls/TokenPairControl.tsx index 881859e..548c4b0 100644 --- a/packages/widget-configurator/src/app/configurator/controls/TokenPairControl.tsx +++ b/packages/widget-configurator/src/app/configurator/controls/TokenPairControl.tsx @@ -3,16 +3,16 @@ import FormControl from '@mui/material/FormControl'; import { Dispatch, SetStateAction } from 'react'; import debounce from '@mui/material/utils/debounce'; -const TokenPairControl = ({ state, widgetHandler, params }: { state: [string, Dispatch>], params: any, widgetHandler: any }) => { +const TokenPairControl = ({ state, widgetHandler, params, tokenPairKey }: { state: [string, Dispatch>], params: any, widgetHandler: any, tokenPairKey: 'tokenPair' | 'bridgeTokenPair' }) => { const [tokenPair, setTokenPair] = state; const updateTokenPair = debounce((value) => { if (!value) { - widgetHandler.current?.reload({ ...params, tokenPair: null }) + widgetHandler.current?.reload({ ...params, [tokenPairKey]: null }) return; } try { const tokenPairObj = JSON.parse(value) - widgetHandler.current?.reload({ ...params, tokenPair: tokenPairObj }) + widgetHandler.current?.reload({ ...params, [tokenPairKey]: tokenPairObj }) } catch (error) { console.log(error); } @@ -31,7 +31,7 @@ const TokenPairControl = ({ state, widgetHandler, params }: { state: [string, Di maxRows={4} multiline fullWidth - label="TokenPair" + label={tokenPairKey} placeholder={JSON.stringify( { fromChain: 1, diff --git a/packages/widget-configurator/src/app/configurator/hooks/useWidgetParamsAndSettings.ts b/packages/widget-configurator/src/app/configurator/hooks/useWidgetParamsAndSettings.ts index fc7f6b9..9e64e1a 100644 --- a/packages/widget-configurator/src/app/configurator/hooks/useWidgetParamsAndSettings.ts +++ b/packages/widget-configurator/src/app/configurator/hooks/useWidgetParamsAndSettings.ts @@ -11,6 +11,7 @@ export function useWidgetParams(configuratorState: ConfiguratorState) { providerType, lang, tokenPair, + bridgeTokenPair, feeConfig, provider, baseUrl, @@ -25,11 +26,13 @@ export function useWidgetParams(configuratorState: ConfiguratorState) { provider, baseUrl, width, + bridgeTokenPair, }; - let parseTokenPair, parseFeeConfig; + let parseTokenPair, parseBridgeTokenPair, parseFeeConfig; try { parseTokenPair = tokenPair ? JSON.parse(tokenPair) : null; + parseBridgeTokenPair = bridgeTokenPair ? JSON.parse(bridgeTokenPair) : null; // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (error) { parseTokenPair = null; @@ -44,6 +47,10 @@ export function useWidgetParams(configuratorState: ConfiguratorState) { params.tokenPair = parseTokenPair; } + if (parseBridgeTokenPair) { + params.bridgeTokenPair = parseBridgeTokenPair; + } + if (parseFeeConfig) { params.feeConfig = parseFeeConfig; } diff --git a/packages/widget-configurator/src/app/configurator/index.tsx b/packages/widget-configurator/src/app/configurator/index.tsx index 4822910..252037d 100644 --- a/packages/widget-configurator/src/app/configurator/index.tsx +++ b/packages/widget-configurator/src/app/configurator/index.tsx @@ -1,32 +1,32 @@ -import { useContext, useRef, useState } from 'react' -import { ConnectButton } from "@rainbow-me/rainbowkit"; -import CodeIcon from '@mui/icons-material/Code' -import EditIcon from '@mui/icons-material/Edit' -import KeyboardDoubleArrowLeftIcon from '@mui/icons-material/KeyboardDoubleArrowLeft' -import Box from '@mui/material/Box' -import Divider from '@mui/material/Divider' -import Drawer from '@mui/material/Drawer' -import Fab from '@mui/material/Fab' -import Typography from '@mui/material/Typography' +import { useContext, useRef, useState } from 'react'; +import { ConnectButton } from '@rainbow-me/rainbowkit'; +import CodeIcon from '@mui/icons-material/Code'; +import EditIcon from '@mui/icons-material/Edit'; +import KeyboardDoubleArrowLeftIcon from '@mui/icons-material/KeyboardDoubleArrowLeft'; +import Box from '@mui/material/Box'; +import Divider from '@mui/material/Divider'; +import Drawer from '@mui/material/Drawer'; +import Fab from '@mui/material/Fab'; +import Typography from '@mui/material/Typography'; import { createOkxSwapWidget, ProviderType } from '@okxweb3/dex-widget'; -import { TradeType } from '@okxweb3/dex-widget' +import { TradeType } from '@okxweb3/dex-widget'; import { Link } from '@mui/material'; import { ChromeReaderMode } from '@mui/icons-material'; -import { ColorModeContext } from '../../theme/ColorModeContext' -import { EmbedDialog } from '../embedDialog' - -import { CurrentTradeTypeControl } from './controls/CurrentTradeTypeControl' -import { LanguageControl } from './controls/LanguageControl' -import { ThemeControl } from './controls/ThemeControl' -import { useEmbedDialogState } from './hooks/useEmbedDialogState' -import { useWidgetParams } from './hooks/useWidgetParamsAndSettings' -import { ContentStyled, DrawerStyled, WrapperStyled } from './styled' -import { ConfiguratorState } from './types' -import TokenPairControl from './controls/TokenPairControl' -import CommissionControl from './controls/CommissionControl' -import ProviderTypeControl from './controls/ProviderTypeControl' -import ChainIdsControl from './controls/ChainConfigControl' +import { ColorModeContext } from '../../theme/ColorModeContext'; +import { EmbedDialog } from '../embedDialog'; + +import { CurrentTradeTypeControl } from './controls/CurrentTradeTypeControl'; +import { LanguageControl } from './controls/LanguageControl'; +import { ThemeControl } from './controls/ThemeControl'; +import { useEmbedDialogState } from './hooks/useEmbedDialogState'; +import { useWidgetParams } from './hooks/useWidgetParamsAndSettings'; +import { ContentStyled, DrawerStyled, WrapperStyled } from './styled'; +import { ConfiguratorState } from './types'; +import TokenPairControl from './controls/TokenPairControl'; +import CommissionControl from './controls/CommissionControl'; +import ProviderTypeControl from './controls/ProviderTypeControl'; +import ChainIdsControl from './controls/ChainConfigControl'; import { DexWidget } from './DexWidget'; import { ProviderControl } from './controls/ProviderControl'; import { useDevMode } from './hooks/useDevMode'; @@ -34,41 +34,53 @@ import { BaseUrlControl } from './controls/BaseUrlControl'; import WidthControl from './controls/WidthControl'; export function Configurator({ title }: { title: string }) { - const { mode } = useContext(ColorModeContext) + const { mode } = useContext(ColorModeContext); - const [isDrawerOpen, setIsDrawerOpen] = useState(true) + const [isDrawerOpen, setIsDrawerOpen] = useState(true); - const tradeTypeState = useState(TradeType.AUTO) - const [tradeType] = tradeTypeState + const tradeTypeState = useState(TradeType.AUTO); + const [tradeType] = tradeTypeState; - const providerTypeState = useState(ProviderType.EVM) - const [providerType] = providerTypeState + const providerTypeState = useState(ProviderType.EVM); + const [providerType] = providerTypeState; const providerState = useState(''); - const [provider] = providerState - - const chainIdsState = useState('') - const [chainIds] = chainIdsState - - const customLanguagesState = useState('en_us') - const [lang] = customLanguagesState - - const tokenPairState = useState(''); - const [tokenPair] = tokenPairState - - const feeConfigState = useState('') - const [feeConfig] = feeConfigState - + const [provider] = providerState; + + const chainIdsState = useState(''); + const [chainIds] = chainIdsState; + + const customLanguagesState = useState('unknown'); + const [lang] = customLanguagesState; + + const tokenPairState = useState(JSON.stringify({ + fromChain: 1, + toChain: 1, + fromToken: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + toToken: '0xec21fbf8ca053699b5059ae81f72aa2293434c86', + })); + const [tokenPair] = tokenPairState; + + const bridgeTokenPairState = useState(JSON.stringify({ + fromChain: 1, + toChain: 501, + fromToken: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + toToken: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', + })); + const [bridgeTokenPair] = bridgeTokenPairState; + + const feeConfigState = useState(''); + const [feeConfig] = feeConfigState; const baseUrlState = useState(import.meta.env.VITE_APP_DEFAUL_BASE_URL as string || 'https://www.okx.com'); - const [baseUrl] = baseUrlState + const [baseUrl] = baseUrlState; const widthState = useState(''); const [width] = widthState; const widgetHandler = useRef>(); - const { dialogOpen, handleDialogClose, handleDialogOpen } = useEmbedDialogState() + const { dialogOpen, handleDialogClose, handleDialogOpen } = useEmbedDialogState(); const state: ConfiguratorState = { chainIds, @@ -77,13 +89,14 @@ export function Configurator({ title }: { title: string }) { providerType, lang, tokenPair, + bridgeTokenPair, feeConfig, provider, baseUrl, width, - } + }; - const params = useWidgetParams(state) + const params = useWidgetParams(state); const { isDevModeOpen, openDevMode } = useDevMode(); return ( @@ -94,8 +107,8 @@ export function Configurator({ title }: { title: string }) { color="secondary" aria-label="edit" onClick={(e) => { - e.stopPropagation() - setIsDrawerOpen(true) + e.stopPropagation(); + setIsDrawerOpen(true); }} sx={{ position: 'fixed', bottom: '1.6rem', left: '1.6rem' }} > @@ -104,7 +117,8 @@ export function Configurator({ title }: { title: string }) { )} - + {title} @@ -139,17 +153,27 @@ export function Configurator({ title }: { title: string }) { - + + + Fee config - More + More - - + + Developer Docs @@ -193,5 +217,5 @@ export function Configurator({ title }: { title: string }) { View Embed Code - ) + ); } diff --git a/packages/widget-configurator/src/app/configurator/types.ts b/packages/widget-configurator/src/app/configurator/types.ts index b4420aa..501616e 100644 --- a/packages/widget-configurator/src/app/configurator/types.ts +++ b/packages/widget-configurator/src/app/configurator/types.ts @@ -7,6 +7,7 @@ export interface ConfiguratorState { providerType: ProviderType; lang?: string; tokenPair?: string; + bridgeTokenPair?: string; feeConfig?: string; provider?: string; baseUrl?: string;