diff --git a/packages/dapp-example/src/SushiSwap.tsx b/packages/dapp-example/src/SushiSwap.tsx
index 0b184629..fd0fa704 100644
--- a/packages/dapp-example/src/SushiSwap.tsx
+++ b/packages/dapp-example/src/SushiSwap.tsx
@@ -9,10 +9,11 @@ import { SelectorOption, TokenListItem } from "./types";
import { getConfig, mapCollection, size, TooltipProps, Configs } from "@orbs-network/twap-ui";
import { DappProvider } from "./context";
import { baseSwapTokens } from "./BaseSwap";
-import { network } from "@defi.org/web3-candies";
+import { eqIgnoreCase, network } from "@defi.org/web3-candies";
const name = "SushiSwap";
const configs = [Configs.SushiArb, Configs.SushiBase, Configs.SushiEth];
+
export const useDappTokens = () => {
const config = useConfig();
const isBase = config?.chainId === Configs.SushiBase.chainId;
@@ -125,6 +126,12 @@ const Tooltip = (props: TooltipProps) => {
);
};
+const useToken = (address?: string) => {
+ const { data: tokens } = useDappTokens();
+
+ return useMemo(() => tokens?.find((it: any) => eqIgnoreCase(it.address, address || "")), [tokens, address]);
+};
+
const TWAPComponent = ({ limit }: { limit?: boolean }) => {
const { account, library, chainId } = useWeb3React();
const connect = useConnectWallet();
@@ -183,6 +190,7 @@ const TWAPComponent = ({ limit }: { limit?: boolean }) => {
onDstTokenSelected={(it: any) => setToToken(it)}
onSwitchTokens={onSwitchTokens}
Tooltip={Tooltip}
+ useToken={useToken}
/>
);
};
diff --git a/packages/lib/src/components/CreateOrderModal/Steps.tsx b/packages/lib/src/components/CreateOrderModal/Steps.tsx
index 586ebb54..832b5b9d 100644
--- a/packages/lib/src/components/CreateOrderModal/Steps.tsx
+++ b/packages/lib/src/components/CreateOrderModal/Steps.tsx
@@ -59,7 +59,7 @@ const StepStatus = ({ step }: { step: Step }) => {
);
}
- if (step.status === "pending") {
+ if (step.status === "loading") {
return ;
}
@@ -77,19 +77,12 @@ const useStep = (step?: SwapStep) => {
const nativeToken = useNetwork()?.native;
return useMemo((): Step | undefined => {
if (!step) return;
- const isWrapPending = swapStep === "wrap" && !wrapTxHash && !wrapSuccess;
- const isWrapLoading = swapStep === "wrap" && wrapTxHash && !wrapSuccess;
- const isApprovePending = swapStep === "approve" && !approveTxHash && !approveSuccess;
- const isApproveLoading = swapStep === "approve" && approveTxHash && !approveSuccess;
- const isCreatePending = swapStep === "createOrder" && !createOrdertxHash && !createOrderSuccess;
- const isCreateLoading = swapStep === "createOrder" && createOrdertxHash && !createOrderSuccess;
-
if (step === "wrap") {
return {
title: `Wrap ${nativeToken?.symbol}`,
Icon: RiSwapFill,
image: nativeToken?.logoUrl,
- status: wrapSuccess ? "completed" : isWrapLoading ? "loading" : isWrapPending ? "pending" : "disabled",
+ status: wrapSuccess ? "completed" : swapStep === "wrap" ? "loading" : "disabled",
};
}
@@ -97,7 +90,7 @@ const useStep = (step?: SwapStep) => {
return {
title: `Approve ${srcToken?.symbol}`,
Icon: RiCheckboxCircleFill,
- status: approveSuccess ? "completed" : isApproveLoading ? "loading" : isApprovePending ? "pending" : "disabled",
+ status: approveSuccess ? "completed" : swapStep === "approve" ? "loading" : "disabled",
};
}
@@ -105,10 +98,10 @@ const useStep = (step?: SwapStep) => {
return {
title: "Create Order",
Icon: RiSwapFill,
- status: createOrderSuccess ? "completed" : isCreateLoading ? "loading" : isCreatePending ? "pending" : "disabled",
+ status: createOrderSuccess ? "completed" : swapStep === "createOrder" ? "loading" : "disabled",
};
}
- }, [step, nativeToken, srcToken, createOrdertxHash, approveTxHash, wrapTxHash, swapStep, createOrderSuccess, wrapSuccess, approveSuccess, swapSteps]);
+ }, [createOrdertxHash, approveTxHash, wrapTxHash, swapStep, createOrderSuccess, wrapSuccess, approveSuccess, swapSteps, srcToken, nativeToken]);
};
const StepContainer = styled(StyledColumnFlex)<{ selected: number }>(({ selected }) => ({
diff --git a/packages/lib/src/components/OrderDisplay.tsx b/packages/lib/src/components/OrderDisplay.tsx
index 272bf44b..1e8ba269 100644
--- a/packages/lib/src/components/OrderDisplay.tsx
+++ b/packages/lib/src/components/OrderDisplay.tsx
@@ -27,7 +27,7 @@ const ChunkSize = ({ srcChunkAmount, srcToken }: { srcChunkAmount?: string; srcT
const _srcChunkAmount = useFormatNumberV2({ value: srcChunkAmount, decimalScale: 3 });
return (
- {`${_srcChunkAmount} ${srcToken?.symbol}`}
+ {`${srcChunkAmount ? _srcChunkAmount : "-"} ${srcToken?.symbol}`}
);
};
@@ -45,11 +45,12 @@ const MinDestAmount = ({
}) => {
const { translations } = useTwapContext();
const formattedValue = useFormatNumberV2({ value: dstMinAmountOut });
+
if (isMarketOrder) return null;
return (
- {`${formattedValue} ${dstToken?.symbol}`}
+ {`${dstMinAmountOut ? formattedValue : "-"} ${dstToken?.symbol}`}
);
};
diff --git a/packages/lib/src/components/OrderHistory/OrderHistoryList.tsx b/packages/lib/src/components/OrderHistory/OrderHistoryList.tsx
index d92ad30f..3091ae48 100644
--- a/packages/lib/src/components/OrderHistory/OrderHistoryList.tsx
+++ b/packages/lib/src/components/OrderHistory/OrderHistoryList.tsx
@@ -109,18 +109,26 @@ const ListOrder = React.memo(
setSize(index, root.current.getBoundingClientRect().height);
}, [index]);
- if (!order) return null;
+ const onClick = useCallback(() => {
+ if (!order?.isLoading) {
+ onSelect(parsedOrder?.id);
+ }
+ }, [order?.isLoading, onSelect, parsedOrder?.id]);
+
+ if (!order) {
+ return
;
+ }
return (
- onSelect(parsedOrder?.id)}>
+
-
+
-
+
@@ -184,18 +192,30 @@ const StyledListOrder = styled(StyledColumnFlex)({
},
});
-const TokenDisplay = ({ token, amount }: { token?: Token; amount?: string }) => {
+const TokenDisplay = ({ token, amount, isLoading }: { token?: Token; amount?: string; isLoading: boolean }) => {
const _amount = useFormatNumberV2({ value: amount, decimalScale: 4 });
return (
-
-
- {_amount} {token?.symbol}
-
+ {isLoading ? (
+
+ ) : (
+ <>
+
+
+ {_amount} {token?.symbol}
+
+ >
+ )}
);
};
+const StyledTokenDisplayLoader = styled(Loader)({
+ borderRadius: "50%",
+ width: 20,
+ height: 20,
+});
+
const StyledTokenDisplay = styled(StyledRowFlex)({
width: "auto",
".twap-order-token-text": {
diff --git a/packages/lib/src/components/OrderHistory/SelectedOrder.tsx b/packages/lib/src/components/OrderHistory/SelectedOrder.tsx
index e13121fb..1cbf4c74 100644
--- a/packages/lib/src/components/OrderHistory/SelectedOrder.tsx
+++ b/packages/lib/src/components/OrderHistory/SelectedOrder.tsx
@@ -149,7 +149,7 @@ const AmountOutFilled = ({ order }: { order: OrderUI }) => {
return (
- {amount || 0} {order?.dstToken.symbol}
+ {amount || 0} {order?.dstToken?.symbol}
);
@@ -161,7 +161,7 @@ const AmountIn = ({ order }: { order: OrderUI }) => {
return (
- {amount || 0} {order?.srcToken.symbol}
+ {amount || 0} {order?.srcToken?.symbol}
);
@@ -173,7 +173,7 @@ const AmountInFilled = ({ order }: { order: OrderUI }) => {
return (
- {amount || 0} {order?.srcToken.symbol}
+ {amount || 0} {order?.srcToken?.symbol}
);
diff --git a/packages/lib/src/components/base/Loader.tsx b/packages/lib/src/components/base/Loader.tsx
index c628d6e8..1f498144 100644
--- a/packages/lib/src/components/base/Loader.tsx
+++ b/packages/lib/src/components/base/Loader.tsx
@@ -1,11 +1,14 @@
import { keyframes, styled } from "styled-components";
-const shimmer = keyframes`
+const fade = keyframes`
0% {
- background-position: -468px 0;
+ opacity: 0.5;
+ }
+ 50% {
+ opacity: 1;
}
100% {
- background-position: 468px 0;
+ opacity: 0.5;
}
`;
@@ -21,12 +24,9 @@ const SkeletonWrapper = styled.div`
display: inline-block;
width: ${(props) => props.width || "100%"};
height: ${(props) => props.height || "100%"};
- background: #f6f7f8;
- background-image: linear-gradient(to right, #f6f7f8 0%, #edeef1 20%, #f6f7f8 40%, #f6f7f8 100%);
- background-repeat: no-repeat;
- background-size: 800px 104px;
+ background-color: #f6f7f8;
position: relative;
- animation: ${shimmer} 1.2s infinite linear;
+ animation: ${fade} 1.5s infinite ease-in-out;
border-radius: ${(props) => props.borderRadius || "4px"};
margin: ${(props) => props.margin || "0"};
`;
diff --git a/packages/lib/src/context/context.tsx b/packages/lib/src/context/context.tsx
index eadf477c..c0761259 100644
--- a/packages/lib/src/context/context.tsx
+++ b/packages/lib/src/context/context.tsx
@@ -163,7 +163,7 @@ export const Content = (props: TwapLibProps) => {
onSrcTokenSelected: props.onSrcTokenSelected,
onSwitchTokens: props.onSwitchTokens || (() => {}),
isLimitPanel: !!props.isLimitPanel,
- tokens: props.parsedTokens,
+ tokens: props.parsedTokens || [],
maxFeePerGas: props.maxFeePerGas,
priorityFeePerGas: props.priorityFeePerGas,
askDataParams: props.askDataParams,
@@ -173,6 +173,8 @@ export const Content = (props: TwapLibProps) => {
isExactAppoval: props.isExactAppoval,
fee: props.fee,
nativeUsd: props.nativeUsd,
+ useDappToken: props.useDappToken,
+ useParsedToken: props.useParsedToken,
}}
>
diff --git a/packages/lib/src/hooks/orders.ts b/packages/lib/src/hooks/orders.ts
index 42feb084..f4e28a2f 100644
--- a/packages/lib/src/hooks/orders.ts
+++ b/packages/lib/src/hooks/orders.ts
@@ -5,21 +5,25 @@ import { HistoryOrder } from "../types";
import { amountUiV2, flatMap, flatMapObject } from "../utils";
import BN from "bignumber.js";
import { query } from "./query";
-import { useEstimatedDelayBetweenChunksMillis } from "./hooks";
+import { useEstimatedDelayBetweenChunksMillis, useGetTokenFromParsedTokensList } from "./hooks";
export const useParseOrderUi = (order?: HistoryOrder) => {
- const config = useTwapContext()?.config;
+ const { config, useParsedToken } = useTwapContext();
const estimatedDelayBetweenChunksMillis = useEstimatedDelayBetweenChunksMillis();
+ const getTokensFromTokensList = useGetTokenFromParsedTokensList();
+ const srcTokenFromHook = useParsedToken?.(order?.srcTokenAddress);
+ const dstTokenFromHook = useParsedToken?.(order?.dstTokenAddress);
return useMemo(() => {
if (!config || !order) return;
- const { srcToken, dstToken, srcAmount, srcBidAmount, dstMinAmount, srcFilledAmount, fillDelay, createdAt, deadline, dollarValueOut, progress } = order;
- if (!srcToken || !dstToken) return;
+ const { srcAmount, srcBidAmount, dstMinAmount, srcFilledAmount, fillDelay, createdAt, deadline, dollarValueOut, progress } = order;
+ const srcToken = srcTokenFromHook || getTokensFromTokensList(order.srcTokenAddress);
+ const dstToken = dstTokenFromHook || getTokensFromTokensList(order.dstTokenAddress);
const isMarketOrder = BN(dstMinAmount || 0).lte(1);
- const srcChunkAmountUi = amountUiV2(srcToken.decimals, srcBidAmount) || "0";
- const dstMinAmountOutUi = amountUiV2(dstToken.decimals, dstMinAmount) || "0";
- const dstAmount = amountUiV2(dstToken.decimals, order.dstAmount) || "0";
- const srcFilledAmountUi = amountUiV2(srcToken.decimals, srcFilledAmount) || "0";
+ const srcChunkAmountUi = !srcToken ? "" : amountUiV2(srcToken.decimals, srcBidAmount) || "";
+ const dstMinAmountOutUi = !dstToken ? "" : amountUiV2(dstToken.decimals, dstMinAmount) || "0";
+ const dstAmount = !dstToken ? "" : amountUiV2(dstToken.decimals, order.dstAmount) || "0";
+ const srcFilledAmountUi = !srcToken ? "" : amountUiV2(srcToken.decimals, srcFilledAmount) || "0";
const totalChunks = order.totalChunks || 0;
return {
@@ -28,7 +32,7 @@ export const useParseOrderUi = (order?: HistoryOrder) => {
createdAtUi: moment(createdAt * 1000).format("ll HH:mm"),
deadlineUi: moment(deadline * 1000).format("ll HH:mm"),
isMarketOrder,
- srcAmountUi: amountUiV2(srcToken.decimals, srcAmount) || "0",
+ srcAmountUi: !srcToken ? "" : amountUiV2(srcToken.decimals, srcAmount) || "0",
srcAmountUsdUi: order.dollarValueIn || "0",
srcChunkAmountUi,
srcFilledAmountUi,
@@ -46,8 +50,9 @@ export const useParseOrderUi = (order?: HistoryOrder) => {
txHash: order.txHash,
limitPrice: isMarketOrder ? undefined : BN(dstMinAmountOutUi).div(srcChunkAmountUi).toString() || "0",
excecutionPrice: BN(dstAmount).gt(0) && BN(srcFilledAmountUi).gt(0) ? BN(dstAmount).div(srcFilledAmountUi).toString() : undefined,
+ isLoading: !srcToken || !dstToken,
};
- }, [config, order, estimatedDelayBetweenChunksMillis]);
+ }, [config, order, estimatedDelayBetweenChunksMillis, getTokensFromTokensList, srcTokenFromHook, dstTokenFromHook]);
};
export const useOrderById = (id?: number) => {
diff --git a/packages/lib/src/hooks/query.ts b/packages/lib/src/hooks/query.ts
index f551b91b..beeff69b 100644
--- a/packages/lib/src/hooks/query.ts
+++ b/packages/lib/src/hooks/query.ts
@@ -7,7 +7,7 @@ import { useTwapContext } from "../context/context";
import { QueryKeys } from "../enums";
import FEE_ON_TRANSFER_ABI from "../abi/FEE_ON_TRANSFER.json";
import { amountBNV2, compact, getTheGraphUrl, groupBy, logger, orderBy } from "../utils";
-import { HistoryOrder, OrdersData, Status, Token } from "../types";
+import { ExtendsOrderHistory, HistoryOrder, OrdersData, Status, Token } from "../types";
import { useGetHasAllowance, useGetTokenFromParsedTokensList, useNetwork } from "./hooks";
import { ordersStore } from "../store";
import { getGraphOrders } from "../order-history";
@@ -156,7 +156,7 @@ const useAddNewOrder = () => {
const config = useTwapContext().config;
return useCallback(
- (order: HistoryOrder) => {
+ (order: ExtendsOrderHistory) => {
try {
if (!config) return;
ordersStore.addOrder(config.chainId, order);
@@ -211,7 +211,7 @@ const useUpdateOrderStatusToCanceled = () => {
};
export const useOrdersHistory = () => {
- const { tokens, state, config, account } = useTwapContext();
+ const { state, config, account } = useTwapContext();
const QUERY_KEY = useOrderHistoryKey();
const getTokensFromTokensList = useGetTokenFromParsedTokensList();
@@ -241,21 +241,13 @@ export const useOrdersHistory = () => {
orders = orders.filter((o) => eqIgnoreCase(config.exchangeAddress, o.exchange || ""));
logger("filtered orders by exchange address", config.exchangeAddress, orders);
- orders = orders.map((order) => {
- return {
- ...order,
- srcToken: getTokensFromTokensList(order.srcTokenAddress),
- dstToken: getTokensFromTokensList(order.dstTokenAddress),
- };
- });
- let result = compact(orders.filter((o) => o.srcToken && o.dstToken));
- result = orderBy(result, (o) => o.createdAt, "desc");
- result = groupBy(result, "status");
+ orders = orderBy(orders, (o) => o.createdAt, "desc");
+ orders = groupBy(orders, "status");
- return result as any;
+ return orders as any;
},
{
- enabled: !!config && tokens?.length > 10 && !state.showConfirmation && !!account,
+ enabled: !!config && !state.showConfirmation && !!account,
refetchInterval: REFETCH_ORDER_HISTORY,
onError: (error: any) => console.log(error),
refetchOnWindowFocus: true,
diff --git a/packages/lib/src/store.ts b/packages/lib/src/store.ts
index 8323acd0..5f0741f9 100644
--- a/packages/lib/src/store.ts
+++ b/packages/lib/src/store.ts
@@ -29,7 +29,7 @@ class OrdersStore implements OrdersState {
}
private saveOrders(): void {
- localStorage.setItem("twap-orders", JSON.stringify(this.orders));
+ localStorage?.setItem("twap-orders", JSON.stringify(this.orders));
}
cancelOrder(chainId: number, orderId: number): void {
console.log("Cancelling order", orderId);
@@ -47,7 +47,7 @@ class OrdersStore implements OrdersState {
}
private loadOrders(): void {
- const storedOrders = localStorage.getItem("twap-orders");
+ const storedOrders = localStorage?.getItem("twap-orders");
if (storedOrders) {
this.orders = JSON.parse(storedOrders);
}
diff --git a/packages/lib/src/types.ts b/packages/lib/src/types.ts
index eef16022..914fe1e7 100644
--- a/packages/lib/src/types.ts
+++ b/packages/lib/src/types.ts
@@ -228,12 +228,15 @@ export interface HistoryOrder {
srcTokenAddress?: string;
dstTokenAddress?: string;
totalChunks?: number;
- srcToken?: Token;
- dstToken?: Token;
dex?: string;
exchange?: string;
}
+export interface ExtendsOrderHistory extends HistoryOrder {
+ srcToken?: Token;
+ dstToken?: Token;
+}
+
type UseTrade = (fromToken?: string, toToken?: string, amount?: string) => { isLoading?: boolean; outAmount?: string };
export interface TwapLibProps {
srcUsd?: string | number;
@@ -253,7 +256,7 @@ export interface TwapLibProps {
storeOverride?: StoreOverride;
srcToken?: Token;
dstToken?: Token;
- dappTokens: any;
+ dappTokens?: any;
uiPreferences?: TwapContextUIPreferences;
onSrcTokenSelected: (token: any) => void;
onDstTokenSelected: (token: any) => void;
@@ -263,12 +266,14 @@ export interface TwapLibProps {
enableQueryParams?: boolean;
minNativeTokenBalance?: string;
isLimitPanel?: boolean;
- parsedTokens: Token[];
+ parsedTokens?: Token[];
onSwitchTokens?: () => void;
isWrongChain?: boolean;
isExactAppoval?: boolean;
fee?: string;
nativeUsd?: string;
+ useParsedToken?: (address?: string) => Token | undefined;
+ useDappToken?: (address?: string) => any;
}
export type Token = {
@@ -495,6 +500,8 @@ export interface TWAPContextProps {
isExactAppoval?: boolean;
fee?: string;
nativeUsd?: string;
+ useParsedToken?: (address?: string) => Token | undefined;
+ useDappToken?: (address?: string) => any;
}
export enum Status {
diff --git a/packages/sushiswap/src/index.tsx b/packages/sushiswap/src/index.tsx
index eb5a3c2a..791a13a2 100644
--- a/packages/sushiswap/src/index.tsx
+++ b/packages/sushiswap/src/index.tsx
@@ -205,14 +205,14 @@ const useParseToken = () => {
return {
...nativeToken,
logoUrl: getTokenLogo(token) || nativeToken.logoUrl,
- };
+ } as Token;
}
return {
address: Web3.utils.toChecksumAddress(token.address),
decimals: token.decimals,
symbol: token.symbol,
logoUrl: getTokenLogo(token),
- };
+ } as Token;
} catch (error) {
console.error("Invalid token", token);
}
@@ -240,6 +240,7 @@ interface SushiProps extends TWAPProps {
connector?: any;
NetworkSelector?: FC<{ children: ReactNode }>;
Button?: FC<{ children: ReactNode; disabled?: boolean }>;
+ useToken: (address?: string) => any;
}
interface AdapterContextProps extends SushiProps {
@@ -253,11 +254,8 @@ const useAdapterContext = () => useContext(AdapterContext);
const useWToken = () => {
const context = useAdapterContext();
-
- return useMemo(() => {
- const wTokenAddress = network(context.config.chainId).wToken.address;
- return context.dappTokens?.find((it: any) => eqIgnoreCase(it.address || "", wTokenAddress || ""));
- }, [context.dappTokens, context.config]);
+ const token = context.useToken(network(context.config.chainId).wToken.address);
+ return token;
};
const useIsNative = () => {
@@ -356,6 +354,15 @@ const useParsedTokens = () => {
}, [context.dappTokens, parseToken]);
};
+const useParsedToken = (address?: string) => {
+ const { useToken } = useAdapterContext();
+ const parseToken = useParseToken();
+
+ const token = useToken(address);
+
+ return useMemo(() => parseToken(token), [token, parseToken]);
+};
+
const useIsWrongChain = () => {
const context = useAdapterContext();
@@ -406,8 +413,8 @@ const TWAPContent = () => {
translations={translations as Translations}
provider={provider}
account={!context.configChainId ? undefined : context.account}
- dappTokens={context.dappTokens}
- parsedTokens={parsedTokens}
+ useParsedToken={useParsedToken}
+ useDappToken={context.useToken}
srcToken={srcToken}
dstToken={dstToken}
onDstTokenSelected={context.onDstTokenSelected}