Skip to content

Commit

Permalink
feat: integrate TWAP UI for new DEX
Browse files Browse the repository at this point in the history
  • Loading branch information
oxbyte-monterrosa committed Jul 26, 2024
1 parent 1c48996 commit a9e402d
Show file tree
Hide file tree
Showing 6 changed files with 1,071 additions and 5 deletions.
305 changes: 305 additions & 0 deletions packages/dapp-example/src/TradingPost.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
import { StyledModalContent, StyledTradingPost, StyledPancakeBackdrop, StyledTradingPostLayout, StyledPancakeOrders, StyledPancakeTwap } from "./styles";
import { TWAP, Orders, parseToken } from "@orbs-network/twap-ui-tradingpost";
import { useConnectWallet, useGetTokens, useIsMobile, usePriceUSD, useTheme, useTrade } from "./hooks";
import { Configs } from "@orbs-network/twap";
import { useWeb3React } from "@web3-react/core";
import { Dapp, TokensList, UISelector } from "./Components";
import { Popup } from "./Components";
import { createContext, ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
import _ from "lodash";
import { erc20s, isNativeAddress, zeroAddress } from "@defi.org/web3-candies";
import { SelectorOption, TokenListItem } from "./types";
import { Box } from "@mui/system";
import { Button, styled, Tooltip, Typography } from "@mui/material";
import { Components, hooks, Styles } from "@orbs-network/twap-ui";
import BN from "bignumber.js";
const config = Configs.PancakeSwap;

const tradingPostConfig = {
...config,
name: "TradingPost",
};

let native = {
...tradingPostConfig.nativeToken,
logoURI: tradingPostConfig.nativeToken.logoUrl,
};

const parseListToken = (tokenList: any) => {
const result = tokenList.tokens.map(({ symbol, address, decimals, logoURI, name }: any) => ({
decimals,
symbol,
name,
address,
logoURI: logoURI.replace("_1", ""),
}));

return [native, ...result];
};
export const useDappTokens = () => {
return useGetTokens({
chainId: config.chainId,
parse: parseListToken,
modifyList: (tokens: any) => ({ ..._.mapKeys(tokens, (t) => t.address) }),
baseAssets: erc20s.bsc,
url: `https://tokens.pancakeswap.finance/pancakeswap-extended.json`,
});
};

interface TokenSelectModalProps {
onCurrencySelect: (value: any) => void;
selectedCurrency?: any;
otherSelectedCurrency?: any;
}

const parseList = (rawList?: any): TokenListItem[] => {
return _.map(rawList, (rawToken) => {
return {
token: {
address: rawToken.address,
decimals: rawToken.decimals,
symbol: rawToken.symbol,
logoUrl: rawToken.logoURI,
},
rawToken,
};
});
};

const ConnectButton = () => {
const connect = useConnectWallet();
return (
<div onClick={connect}>
<Components.SubmitButton isMain={true} />
</div>
);
};

interface ContextProps {
openModal: (value: boolean) => void;
close: () => void;
showModal?: boolean;
isFrom?: boolean;
setIsFrom?: (value: boolean) => void;
}
const Context = createContext({} as ContextProps);

const ContextWrapper = ({ children }: { children: ReactNode }) => {
const [showModal, setShowModal] = useState(false);
const [isFrom, setIsFrom] = useState(true);

const openModal = (value: boolean) => {
setIsFrom(value);
setShowModal(true);
};

return <Context.Provider value={{ isFrom, setIsFrom, showModal, openModal, close: () => setShowModal(false) }}>{children}</Context.Provider>;
};

const TokenSelectModal = ({ onCurrencySelect }: TokenSelectModalProps) => {
const { data: dappTokens } = useDappTokens();

const tokensListSize = _.size(dappTokens);
const parsedList = useMemo(() => parseList(dappTokens), [tokensListSize]);

return (
<StyledModalContent>
<TokensList tokens={parsedList} onClick={onCurrencySelect} />
</StyledModalContent>
);
};

const useDecimals = (fromToken?: string, toToken?: string) => {
const { data: dappTokens } = useDappTokens();
const fromTokenDecimals = dappTokens?.[fromToken || ""]?.decimals;
const toTokenDecimals = dappTokens?.[toToken || ""]?.decimals;

return { fromTokenDecimals, toTokenDecimals };
};

const handleAddress = (address?: string) => {
return !address ? "" : "BNB" ? zeroAddress : address;
};

const useTokenModal = (item1: any, item2: any, item3: any, isFrom?: boolean) => {
const context = useContext(Context);
return () => context.openModal(!!isFrom);
};

const useTooltip = (content: ReactNode, options?: any, children?: ReactNode) => {
const targetRef = useRef<any>(null);

const tooltip = (
<Tooltip title={content}>
<span>{children}</span>
</Tooltip>
);

return {
targetRef,
tooltip,
};
};

const DappButton = ({ isLoading, disabled, children, onClick }: any) => {
return (
<StyledButton variant="contained" fullWidth disabled={isLoading || disabled} onClick={onClick}>
{children}
</StyledButton>
);
};

const StyledButton = styled(Button)({
width: "100%",
});

const ApproveModalContent = ({ title, isBonus, isMM }: { title: string; isBonus: boolean; isMM: boolean }) => {
return <p>Approving</p>;
};

const SwapTransactionErrorContent = ({ message }: { message: string }) => {
return <p>{message}</p>;
};
const SwapPendingModalContent = ({ title }: { title: string }) => {
return <p>{title}</p>;
};

const TWAPComponent = ({ limit }: { limit?: boolean }) => {
const { isDarkTheme } = useTheme();
const { account, library, chainId } = useWeb3React();
const { data: dappTokens } = useDappTokens();
const isMobile = useIsMobile();

const _useTrade = (fromToken?: string, toToken?: string, amount?: string) => {
const { fromTokenDecimals, toTokenDecimals } = useDecimals(handleAddress(fromToken), handleAddress(toToken));
return useTrade(fromToken, toToken, amount, fromTokenDecimals, toTokenDecimals);
};

const connector = useMemo(() => {
return {
getProvider: () => library,
};
}, [library]);

return (
<StyledPancakeTwap isDarkTheme={isDarkTheme ? 1 : 0}>
<TWAP
account={account}
srcToken="CAKE"
dstToken={config.wToken.address}
dappTokens={dappTokens}
isDarkTheme={isDarkTheme}
limit={limit}
ConnectButton={ConnectButton}
usePriceUSD={usePriceUSD}
connectedChainId={chainId}
useTrade={_useTrade}
useTokenModal={useTokenModal}
onDstTokenSelected={(it: any) => console.log(it)}
nativeToken={native}
connector={connector}
isMobile={isMobile}
useTooltip={useTooltip}
Button={DappButton}
ApproveModalContent={ApproveModalContent}
SwapTransactionErrorContent={SwapTransactionErrorContent}
SwapPendingModalContent={SwapPendingModalContent}
SwapTransactionReceiptModalContent={SwapPendingModalContent}
TradePrice={TradePrice}
TradePriceToggle={TradePriceToggle}
/>
</StyledPancakeTwap>
);
};

const logo = "https://avatars.githubusercontent.com/u/170947423?s=200&v=4";
const DappComponent = () => {
const { isDarkTheme } = useTheme();
const [selected, setSelected] = useState(SelectorOption.TWAP);
const isMobile = useIsMobile();

return (
<ContextWrapper>
<Tokens />
<StyledTradingPost isDarkTheme={isDarkTheme ? 1 : 0}>
{isMobile && (
<StyledPancakeOrders isDarkTheme={isDarkTheme ? 1 : 0}>
<Orders />
</StyledPancakeOrders>
)}
<StyledTradingPostLayout name={config.name}>
<UISelector selected={selected} select={setSelected} limit={true} />
<Wrapper>
<TWAPComponent limit={selected === SelectorOption.LIMIT} />
</Wrapper>
</StyledTradingPostLayout>
{!isMobile && (
<StyledPancakeOrders isDarkTheme={isDarkTheme ? 1 : 0}>
<Orders />
</StyledPancakeOrders>
)}
</StyledTradingPost>
</ContextWrapper>
);
};

const Tokens = () => {
const context = useContext(Context);

const selectToken = hooks.useSelectTokenCallback(parseToken);

const onSelect = useCallback(
(token: any) => {
selectToken({ isSrc: !!context.isFrom, token });
context.close();
},
[selectToken, context.isFrom, context.close]
);

return (
<Popup isOpen={!!context.showModal} onClose={context.close}>
<TokenSelectModal onCurrencySelect={onSelect} />;
</Popup>
);
};
const Wrapper = ({ children, className = "" }: { children: ReactNode; className?: string }) => {
const { isDarkTheme } = useTheme();

return (
<StyledWrapper className={className}>
<StyledPancakeBackdrop isDarkTheme={isDarkTheme ? 1 : 0} />
<div style={{ position: "relative", width: "100%" }}>{children}</div>
</StyledWrapper>
);
};

const StyledWrapper = styled(Box)({
position: "relative",
width: "100%",
});

const dapp: Dapp = {
Component: DappComponent,
logo,
config: tradingPostConfig,
};

export default dapp;

const TradePriceToggle = ({ onClick }: { onClick: () => void }) => {
return <button onClick={onClick}>T</button>;
};

const TradePrice = (props: { leftSymbol?: string; rightSymbol?: string; price?: string }) => {
return (
<Typography>
1 {props.leftSymbol} = {props.price} {props.rightSymbol}
</Typography>
);
};

export const amountUi = (decimals?: number, amount?: BN) => {
if (!decimals || !amount) return "";
const percision = BN(10).pow(decimals || 0);
return amount.times(percision).idiv(percision).div(percision).toString();
};
22 changes: 20 additions & 2 deletions packages/dapp-example/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,24 @@ import lynex from "./Lynex";
import arbidex from "./Arbidex";
import syncswap from "./SyncSwap";
import kinetix from "./kinetix";
import tradingpost from "./TradingPost";

export const defaultDapp = quickswap;
export const dapps = [quickswap, spookyswap, spiritswap, pangolin, pangolinDaas, chronos, thena, baseswap, arbidex, lynex, stellaswap, pancake, sushiswap, syncswap, kinetix];
export const defaultDapp = tradingpost;
export const dapps = [
quickswap,
spookyswap,
spiritswap,
pangolin,
pangolinDaas,
chronos,
thena,
baseswap,
arbidex,
lynex,
stellaswap,
pancake,
tradingpost,
sushiswap,
syncswap,
kinetix,
];
30 changes: 29 additions & 1 deletion packages/dapp-example/src/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,25 @@ export const StyledPancake = styled(StyledDapp)<{ isDarkTheme: number }>(({ isDa
},
}));

export const StyledTradingPost = styled(StyledDapp)<{ isDarkTheme: number }>(({ isDarkTheme }) => ({
background: isDarkTheme ? "#131311" : "#F7E4D4",
".ui-selector-btn": {
background: "#1fc7d4",
color: isDarkTheme ? "white" : "black",
},
".ui-selector-btn-selected": {
background: "#7a6eaa",
color: "white",
},
".menu-button": {
svg: {
"* ": {
color: isDarkTheme ? "#FBFBFB" : "#000315",
},
},
},
}));

export const StyledStella = styled(StyledDapp)<{ isDarkMode: number }>(({ isDarkMode }) => ({
background: isDarkMode ? "#251842" : "#F4F5F6",
".ui-selector-btn": {
Expand Down Expand Up @@ -421,7 +440,7 @@ export const StyledThenaLayout = styled(DappLayout)({
});

export const StyledPancakeTwap = styled(Box)<{ isDarkTheme: number }>(({ isDarkTheme }) => ({
background: isDarkTheme ? "#27262C" : "#FFFFFF",
background: isDarkTheme ? "#27262C" : "#F7E4D4",
padding: 16,
borderRadius: 24,
position: "relative",
Expand Down Expand Up @@ -458,6 +477,15 @@ export const StyledPancakeLayout = styled(DappLayout)({
maxWidth: 326,
});

export const StyledTradingPostLayout = styled(DappLayout)({
width: "calc(100% - 30px)",
display: "flex",
flexDirection: "column",
alignItems: "center",
position: "relative",
maxWidth: 540,
});

export const StyledSushiLayout = styled(DappLayout)({
maxWidth: 490,
width: "calc(100% - 30px)",
Expand Down
4 changes: 2 additions & 2 deletions packages/lib/src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1367,8 +1367,8 @@ export const useLimitPriceV2 = () => {
original: BN(original || "0").isZero() ? "" : original,
};
}, [marketPrice, enableQueryParams, limitPriceStore.inverted, limitPriceStore.limitPrice, limitPriceStore.isCustom, limitPriceStore.priceFromQueryParams]);
console.log({limitPrice});
console.log({ limitPrice });

const onInvert = useCallback(() => {
limitPriceStore.toggleInverted();
}, [limitPriceStore.toggleInverted, limitPrice]);
Expand Down
Loading

0 comments on commit a9e402d

Please sign in to comment.