diff --git a/examples/with-next/app/App.tsx b/examples/with-next/app/App.tsx index 5384cd2150..13ff3d38f1 100644 --- a/examples/with-next/app/App.tsx +++ b/examples/with-next/app/App.tsx @@ -1,7 +1,7 @@ import { Bridge, USDC, USDT, DAI, ETH, USDCe } from '@abtestingalpha/widget' import { useEthereumWallet } from './hooks/useEthereumWallet' -const tokens = [USDC, USDT, DAI, ETH, USDCe] +const targetTokens = [USDC, USDT, DAI, ETH, USDCe] function App() { const { web3Provider } = useEthereumWallet() @@ -15,10 +15,10 @@ function App() {
diff --git a/examples/with-react/src/App.tsx b/examples/with-react/src/App.tsx index 638b2fd049..be4a92b8a9 100644 --- a/examples/with-react/src/App.tsx +++ b/examples/with-react/src/App.tsx @@ -12,7 +12,7 @@ import Header from './Header' import Footer from './Footer' import { Install, Developer, Support } from './icons' -const tokens = [USDC, USDT, DAI, ETH] +const targetTokens = [USDC, USDT, DAI, ETH] const customRpcs: CustomRpcs = { 1: 'https://eth.llamarpc.com', @@ -97,10 +97,10 @@ function App() {
diff --git a/src/components/Transactions.tsx b/src/components/Transactions.tsx index 9140c828bc..eb019632f9 100644 --- a/src/components/Transactions.tsx +++ b/src/components/Transactions.tsx @@ -4,6 +4,7 @@ import { TransactionDetails } from '@/state/slices/transactions/reducer' import { Transaction } from './Transaction' import { getTimeMinutesFromNow } from '@/utils/getTimeMinutesFromNow' +/** TODO: Pull synapseSDK from context vs passing in */ export const Transactions = ({ synapseSDK, connectedAddress, diff --git a/src/components/Widget.tsx b/src/components/Widget.tsx index f6f05cc14f..6ce61e2b03 100644 --- a/src/components/Widget.tsx +++ b/src/components/Widget.tsx @@ -13,7 +13,7 @@ import { stringToBigInt } from '@/utils/stringToBigInt' import { cleanNumberInput } from '@/utils/cleanNumberInput' import { Receipt } from '@/components/Receipt' -import { BridgeableToken, Chain, WidgetProps } from 'types' +import { BridgeableToken, Chain, CustomThemeVariables } from 'types' import { ChainSelect } from '@/components/ui/ChainSelect' import { TokenSelect } from '@/components/ui/TokenSelect' @@ -23,8 +23,9 @@ import { setOriginChainId, setOriginToken, setDestinationToken, - setTokens, + setTargetTokens, setDebouncedInputAmount, + setTargetChainIds, } from '@/state/slices/bridge/reducer' import { useBridgeState } from '@/state/slices/bridge/hooks' import { @@ -63,14 +64,25 @@ import { Transactions } from './Transactions' import { CHAINS_BY_ID } from '@/constants/chains' import { useSynapseContext } from '@/providers/SynapseProvider' +import { getFromTokens } from '@/utils/routeMaker/getFromTokens' +import { getSymbol } from '@/utils/routeMaker/generateRoutePossibilities' +import { findTokenByRouteSymbol } from '@/utils/findTokenByRouteSymbol' + +interface WidgetProps { + theme?: 'light' | 'dark' + customTheme: CustomThemeVariables + container?: Boolean + targetTokens?: BridgeableToken[] + targetChainIds?: number[] +} export const Widget = ({ theme, customTheme, container, - tokens, - toChainId, -}) => { + targetChainIds, + targetTokens, +}: WidgetProps) => { const dispatch = useAppDispatch() const currentSDKRequestID = useRef(0) @@ -88,9 +100,19 @@ export const Widget = ({ originToken, destinationChainId, destinationToken, - tokens: allTokens, } = useBridgeState() + const allTokens = useMemo(() => { + return getFromTokens({ + fromChainId: originChainId, + fromTokenRouteSymbol: null, + toChainId: null, + toTokenRouteSymbol: null, + }) + .map(getSymbol) + .map(findTokenByRouteSymbol) + }, [originChainId]) + const { bridgeQuote, isLoading } = useBridgeQuoteState() const { isInputValid, hasValidSelections } = useValidations() @@ -107,10 +129,15 @@ export const Widget = ({ }, [originChainId]) useEffect(() => { - dispatch(setTokens(tokens)) - dispatch(setDestinationChainId(toChainId)) - dispatch(setDestinationToken(tokens[0])) - }, [tokens, toChainId]) + dispatch(setTargetTokens(targetTokens)) + dispatch(setTargetChainIds(targetChainIds)) + if (targetChainIds && targetChainIds.length > 0) { + dispatch(setDestinationChainId(targetChainIds[0])) + } + if (targetTokens && targetTokens.length > 0) { + dispatch(setDestinationToken(targetTokens[0])) + } + }, [targetTokens, targetChainIds, targetTokens]) /** Debounce user input to fetch bridge quote (in ms) */ /** TODO: Can this be moved to the input component? */ @@ -129,7 +156,7 @@ export const Widget = ({ /** TODO: Can this be moved into a level above? */ useEffect(() => { if (!signer && !originChainProvider) return - if (originChainId && tokens && connectedAddress) { + if (originChainId && allTokens && connectedAddress) { dispatch( fetchAndStoreTokenBalances({ address: connectedAddress, diff --git a/src/components/ui/TokenPopoverSelect.tsx b/src/components/ui/TokenPopoverSelect.tsx index 11fc458afc..4e8e1fd0a6 100644 --- a/src/components/ui/TokenPopoverSelect.tsx +++ b/src/components/ui/TokenPopoverSelect.tsx @@ -61,6 +61,7 @@ export function TokenPopoverSelect({ /> ) })} +
Other tokens
{remaining?.map((option: BridgeableToken, index) => { const matchedTokenBalance: TokenBalance = balances?.find( (token: TokenBalance) => token.token === option diff --git a/src/components/ui/TokenSelect.tsx b/src/components/ui/TokenSelect.tsx index e80dc4b270..240a9b6266 100644 --- a/src/components/ui/TokenSelect.tsx +++ b/src/components/ui/TokenSelect.tsx @@ -13,7 +13,7 @@ type Props = { } export function TokenSelect({ label, isOrigin, token, onChange }: Props) { - const { originTokens, destinationTokens, tokens }: BridgeState = + const { originTokens, destinationTokens, targetTokens }: BridgeState = useBridgeState() const { balances } = useWalletState() @@ -23,10 +23,10 @@ export function TokenSelect({ label, isOrigin, token, onChange }: Props) { if (isOrigin) { options = originTokens - remaining = _.difference(tokens, options) + remaining = _.difference(targetTokens, originTokens) } else { - options = filterTokens(destinationTokens, tokens) - remaining = _.difference(tokens, options) + options = destinationTokens + remaining = _.difference(targetTokens, destinationTokens) } return ( @@ -41,12 +41,3 @@ export function TokenSelect({ label, isOrigin, token, onChange }: Props) { /> ) } - -const filterTokens = ( - destinationTokens: BridgeableToken[], - tokens: BridgeableToken[] -) => { - return destinationTokens.filter((destinationToken) => - tokens.some((token) => token.routeSymbol === destinationToken.routeSymbol) - ) -} diff --git a/src/index.tsx b/src/index.tsx index 03fdad22e5..ce46938167 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,6 +1,6 @@ import './index.css' ;('use client') -import { WidgetProps } from 'types' +import { BridgeProps } from 'types' import { Widget } from './components/Widget' import { Web3Provider } from 'providers/Web3Provider' import { Provider } from 'react-redux' @@ -21,9 +21,9 @@ export const Bridge = ({ theme, customTheme, container, - tokens, - toChainId, -}: WidgetProps) => { + targetChainIds, + targetTokens, +}: BridgeProps) => { return ( @@ -33,8 +33,8 @@ export const Bridge = ({ theme={theme} customTheme={customTheme} container={container} - tokens={tokens} - toChainId={toChainId} + targetChainIds={targetChainIds} + targetTokens={targetTokens} /> diff --git a/src/state/slices/bridge/reducer.ts b/src/state/slices/bridge/reducer.ts index fa774f19bf..aa1faead7c 100644 --- a/src/state/slices/bridge/reducer.ts +++ b/src/state/slices/bridge/reducer.ts @@ -23,12 +23,14 @@ export interface BridgeState { originTokens: BridgeableToken[] destinationChainIds: number[] destinationTokens: BridgeableToken[] - tokens: BridgeableToken[] + + targetTokens: BridgeableToken[] + targetChainIds: number[] } const initialState: BridgeState = { debouncedInputAmount: '', - originChainId: 42161, + originChainId: null, originToken: null, destinationChainId: null, destinationToken: null, @@ -36,7 +38,9 @@ const initialState: BridgeState = { originTokens: [], destinationChainIds: [], destinationTokens: [], - tokens: [], + + targetTokens: [], + targetChainIds: [], } export const bridgeSlice = createSlice({ @@ -414,11 +418,17 @@ export const bridgeSlice = createSlice({ state.destinationChainIds = toChainIds state.destinationTokens = toTokens }, - setTokens: ( + setTargetTokens: ( state: BridgeState, action: PayloadAction ) => { - state.tokens = action.payload + state.targetTokens = action.payload + }, + setTargetChainIds: ( + state: BridgeState, + action: PayloadAction + ) => { + state.targetChainIds = action.payload }, }, }) @@ -429,7 +439,8 @@ export const { setDestinationChainId, setOriginToken, setDestinationToken, - setTokens, + setTargetTokens, + setTargetChainIds, } = bridgeSlice.actions export default bridgeSlice.reducer diff --git a/src/types/index.d.ts b/src/types/index.d.ts index b61f2239db..5cac83e3bd 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -29,7 +29,7 @@ export type CustomRpcs = { [chainId: number]: string } -export interface WidgetProps { +export interface BridgeProps { /** Consumer Web3 Provider */ web3Provider?: JsonRpcApiProvider | BrowserProvider @@ -45,11 +45,11 @@ export interface WidgetProps { /** Containerize Widget */ container?: Boolean - /** Supported Tokens Metadata defined by Consumer */ - tokens: BridgeableToken[] + /** Target tokens supported for Consumer */ + targetTokens?: BridgeableToken[] - /** Destination chain selected by Consumer */ - toChainId: number + /* Target chain ids of Consumer */ + targetChainIds?: number[] } export interface Chain { @@ -64,7 +64,7 @@ export interface Chain { blockTime: number } -export declare function Bridge(props: WidgetProps): JSX.Element +export declare function Bridge(props: BridgeProps): JSX.Element export declare const AGEUR: BridgeableToken export declare const AVAX: BridgeableToken diff --git a/src/utils/actions/fetchTokenBalances.ts b/src/utils/actions/fetchTokenBalances.ts index 3dce64b54a..fc03166e8d 100644 --- a/src/utils/actions/fetchTokenBalances.ts +++ b/src/utils/actions/fetchTokenBalances.ts @@ -39,8 +39,8 @@ export async function fetchTokenBalances({ } const validTokens = tokens.filter((token: BridgeableToken) => { - const tokenAddress: string = token.addresses[chainId] - return tokenAddress !== undefined + const tokenAddress: string = token && token.addresses[chainId] + return token && tokenAddress !== undefined }) const calls = validTokens.map((token: BridgeableToken) => { @@ -81,11 +81,11 @@ export async function fetchTokenBalances({ const data = response.map((encodedBalance, index) => { const balance: bigint = coder.decode(['uint256'], encodedBalance)[0] - const token: BridgeableToken = tokens[index] + const token: BridgeableToken = validTokens[index] const decimals: number = token.decimals[chainId] return { - token: tokens[index], + token: validTokens[index], balance: String(balance), parsedBalance: formatBigIntToString(balance, decimals, 4), }