diff --git a/package.json b/package.json index a053711..813b919 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@ethersproject/hash": "^5.7.0", "@orbs-network/liquidity-hub-sdk": "^1.0.40", "@orbs-network/swap-ui": "^0.0.14", - "@orbs-network/twap-sdk": "^2.0.37", + "@orbs-network/twap-sdk": "^2.0.38", "@paraswap/sdk": "^6.10.0", "@radix-ui/react-accordion": "^1.2.1", "@radix-ui/react-avatar": "^1.1.0", diff --git a/src/components/tokens/token-card.tsx b/src/components/tokens/token-card.tsx index 65edb42..c437d87 100644 --- a/src/components/tokens/token-card.tsx +++ b/src/components/tokens/token-card.tsx @@ -7,7 +7,6 @@ import { format, cn, fromBigNumber, - fromBigNumberToStr, ErrorCodes, } from '@/lib' import { Skeleton } from '../ui/skeleton' @@ -30,7 +29,7 @@ export type TokenCardProps = { label: string amount: string amountUsd?: string - balance: string + balance: any selectedToken: Token tokens: TokensWithBalances onSelectToken: (token: Token) => void diff --git a/src/lib/useHandleInputError.ts b/src/lib/useHandleInputError.ts index 652a335..5e4a806 100644 --- a/src/lib/useHandleInputError.ts +++ b/src/lib/useHandleInputError.ts @@ -7,14 +7,14 @@ import { } from "./useTokensWithBalances"; /* Handles amount input errors */ -type UseHandleInputError = { - inToken: Token | null; - inputAmount: string; -}; + export function useInputError({ inputAmount, inToken, -}: UseHandleInputError) { +}: { + inToken: Token | null; + inputAmount: string; +}) { const tokensWithBalances = useTokensWithBalances(); const tokenBalance = useTokenBalance(inToken?.address); return useMemo(() => { diff --git a/src/lib/useTokensWithBalances.ts b/src/lib/useTokensWithBalances.ts index 640b23d..9a93cf4 100644 --- a/src/lib/useTokensWithBalances.ts +++ b/src/lib/useTokensWithBalances.ts @@ -5,9 +5,7 @@ import { networks } from '@/lib/networks' export function useTokensWithBalances() { const account = useAccount() - const { data: tokens, isLoading: tokensLoading } = useTokensList({ - chainId: networks.poly.id, - }) + const { data: tokens, isLoading: tokensLoading } = useTokensList() const { query: { data: balances, isLoading: balancesLoading, refetch }, queryKey, diff --git a/src/lib/wrapToken.ts b/src/lib/wrapToken.ts index aff2a20..bdad0a4 100644 --- a/src/lib/wrapToken.ts +++ b/src/lib/wrapToken.ts @@ -1,4 +1,5 @@ import { toast } from "sonner" +import { Address } from "viem" import { simulateContract, writeContract } from 'wagmi/actions' import { IWETHabi } from "./abis" import { networks } from "./networks" @@ -13,7 +14,7 @@ export const wrapToken = async (account: string, inAmount: string) => { functionName: 'deposit', account: account as Address, address: networks.poly.wToken.address as Address, - value: inAmount + value: BigInt(inAmount.replace('.', '')) }) // Perform the deposit contract function @@ -21,8 +22,6 @@ export const wrapToken = async (account: string, inAmount: string) => { await waitForConfirmations(txHash, 1, 20) return txHash } catch (error) { - console.log({ error }); - const errorMessage = getErrorMessage( error, 'An error occurred while wrapping your token' diff --git a/src/trade/hooks.ts b/src/trade/hooks.ts index 925cd13..9681e40 100644 --- a/src/trade/hooks.ts +++ b/src/trade/hooks.ts @@ -1,4 +1,4 @@ -import { network, networks, toExactAmount, toRawAmount } from "@/lib"; +import { network, toExactAmount, toRawAmount } from "@/lib"; import { useMemo } from "react"; import { useChainId } from "wagmi"; diff --git a/src/trade/liquidity-hub/liquidity-hub-confirmation-dialog.tsx b/src/trade/liquidity-hub/liquidity-hub-confirmation-dialog.tsx new file mode 100644 index 0000000..db8df57 --- /dev/null +++ b/src/trade/liquidity-hub/liquidity-hub-confirmation-dialog.tsx @@ -0,0 +1,197 @@ +import { Button } from '@/components/ui/button' +import { + Dialog, + DialogContent, + DialogDescription, + DialogTitle, +} from '@/components/ui/dialog' +import { LiquidityProvider, SwapSteps, Token } from '@/types' +import { Card } from '@/components/ui/card' +import { SwapFlow, SwapStep, SwapStatus } from '@orbs-network/swap-ui' +import { useMemo } from 'react' +import { DataDetails } from '@/components/ui/data-details' +import { + format, + fromBigNumber, + getLiquidityProviderName, + getSteps, + resolveNativeTokenAddress, + toBigNumber, + useGetRequiresApproval, +} from '@/lib' +import { useAccount } from 'wagmi' +import { Address } from 'viem' + +export type SwapConfirmationDialogProps = { + inToken: Token + outToken: Token + isOpen: boolean + onClose: () => void + confirmSwap: () => void + swapStatus?: SwapStatus + currentStep?: SwapSteps + signature?: string + gasAmountOut?: string + liquidityProvider: LiquidityProvider + inAmount?: number + inAmountUsd?: string + outAmount?: number + outAmountUsd?: string + allowancePermitAddress: string +} + +// Construct steps for swap to display in UI +const useSteps = ( + liquidityProvider: LiquidityProvider, + requiresApproval: boolean, + inToken?: Token, + signature?: string +) => { + return useMemo((): SwapStep[] => { + if (!inToken) return [] + + const steps = getSteps({ + noWrap: liquidityProvider === 'paraswap', + inTokenAddress: inToken.address, + requiresApproval, + }) + + return steps.map((step) => { + if (step === SwapSteps.Wrap) { + return { + id: SwapSteps.Wrap, + title: `Wrap ${inToken.symbol}`, + description: `Wrap ${inToken.symbol}`, + image: inToken?.logoUrl, + } + } + if (step === SwapSteps.Approve) { + return { + id: SwapSteps.Approve, + title: `Approve ${inToken.symbol}`, + description: `Approve ${inToken.symbol}`, + image: inToken?.logoUrl, + } + } + return { + id: SwapSteps.Swap, + title: `Swap ${inToken.symbol}`, + description: `Swap ${inToken.symbol}`, + image: inToken?.logoUrl, + timeout: signature ? 60_000 : 40_000, + } + }) + }, [inToken, liquidityProvider, requiresApproval, signature]) +} + +export function SwapConfirmationDialog({ + inToken, + outToken, + isOpen, + onClose, + confirmSwap, + swapStatus, + currentStep, + signature, + gasAmountOut, + liquidityProvider, + inAmount, + inAmountUsd, + outAmount, + outAmountUsd, + allowancePermitAddress, +}: SwapConfirmationDialogProps) { + const { address } = useAccount() + + const gasPrice = useMemo(() => { + if (!outAmountUsd || !gasAmountOut) return 0 + const gas = fromBigNumber(gasAmountOut, outToken.decimals) + const usd = Number(outAmountUsd) / Number(outAmount) + return Number(gas) * usd + }, [outAmountUsd, gasAmountOut, outToken.decimals, outAmount]) + + const { requiresApproval, approvalLoading } = useGetRequiresApproval( + allowancePermitAddress as Address, + resolveNativeTokenAddress(inToken?.address), + toBigNumber(inAmount || 0, inToken?.decimals) + ) + + const steps = useSteps( + liquidityProvider, + requiresApproval, + inToken, + signature + ) + + return ( + + + Swap + +
+
+ + } + swapStatus={swapStatus} + successContent={} + failedContent={} + inToken={{ + symbol: inToken.symbol, + logo: inToken.logoUrl, + }} + outToken={{ + symbol: outToken.symbol, + logo: outToken.logoUrl, + }} + /> +
+ + {!swapStatus && address && ( + <> + +
+ +
+
+ +
+ +
+
+ + + + )} +
+
+
+ ) +} \ No newline at end of file diff --git a/src/trade/swap/swap.tsx b/src/trade/liquidity-hub/liquidity-hub-swap.tsx similarity index 96% rename from src/trade/swap/swap.tsx rename to src/trade/liquidity-hub/liquidity-hub-swap.tsx index 62ba905..fa76047 100644 --- a/src/trade/swap/swap.tsx +++ b/src/trade/liquidity-hub/liquidity-hub-swap.tsx @@ -5,14 +5,13 @@ import { useCallback, useMemo, useState } from 'react' import { SwapStatus } from '@orbs-network/swap-ui' import { useAccount } from 'wagmi' import { SwapDetails } from '../../components/swap-details' -import { SwapConfirmationDialog } from './swap-confirmation-dialog' -import { useLiquidityHubQuote } from './liquidity-hub/useLiquidityHubQuote' +import { SwapConfirmationDialog } from './liquidity-hub-confirmation-dialog' +import { useLiquidityHubQuote } from './useLiquidityHubQuote' import { Button } from '@/components/ui/button' -import { useLiquidityHubSwapCallback } from './liquidity-hub/useLiquidityHubSwapCallback' +import { useLiquidityHubSwapCallback } from './useLiquidityHubSwapCallback' import { permit2Address, Quote } from '@orbs-network/liquidity-hub-sdk' import { useDefaultTokens, - useHandleInputError, ErrorCodes, fromBigNumber, toBigNumber, @@ -37,6 +36,7 @@ import { import { Switch } from '@/components/ui/switch' import { Label } from '@/components/ui/label' import { Input } from '@/components/ui/input' +import { useInputError } from '../../lib/useHandleInputError' export function Swap() { const { tokensWithBalances, refetch: refetchBalances } = @@ -44,7 +44,6 @@ export function Swap() { const [inToken, setInToken] = useState(null) const [outToken, setOutToken] = useState(null) const [inputAmount, setInputAmount] = useState('') - const [inputError, setInputError] = useState(null) const [acceptedQuote, setAcceptedQuote] = useState() const [liquidityHubDisabled, setLiquidityHubDisabled] = useState(false) const [currentStep, setCurrentStep] = useState( @@ -71,11 +70,9 @@ export function Swap() { }) // Handle Amount Input Error - useHandleInputError({ + const inputError = useInputError({ inputAmount, inToken, - tokensWithBalances, - setInputError, }) // Handle Token Switch @@ -88,7 +85,6 @@ export function Swap() { const resetSwap = useCallback(() => { setAcceptedQuote(undefined) setInputAmount('') - setInputError(null) setCurrentStep(undefined) setSignature(undefined) setSwapStatus(undefined) diff --git a/src/trade/swap/liquidity-hub/useLiquidityHubQuote.ts b/src/trade/liquidity-hub/useLiquidityHubQuote.ts similarity index 100% rename from src/trade/swap/liquidity-hub/useLiquidityHubQuote.ts rename to src/trade/liquidity-hub/useLiquidityHubQuote.ts diff --git a/src/trade/swap/liquidity-hub/useLiquidityHubSDK.ts b/src/trade/liquidity-hub/useLiquidityHubSDK.ts similarity index 100% rename from src/trade/swap/liquidity-hub/useLiquidityHubSDK.ts rename to src/trade/liquidity-hub/useLiquidityHubSDK.ts diff --git a/src/trade/swap/liquidity-hub/useLiquidityHubSwapCallback.ts b/src/trade/liquidity-hub/useLiquidityHubSwapCallback.ts similarity index 98% rename from src/trade/swap/liquidity-hub/useLiquidityHubSwapCallback.ts rename to src/trade/liquidity-hub/useLiquidityHubSwapCallback.ts index 0005250..3a8901a 100644 --- a/src/trade/swap/liquidity-hub/useLiquidityHubSwapCallback.ts +++ b/src/trade/liquidity-hub/useLiquidityHubSwapCallback.ts @@ -1,15 +1,12 @@ import { useMutation } from '@tanstack/react-query' -import { signTypedData, simulateContract, writeContract } from 'wagmi/actions' +import { signTypedData } from 'wagmi/actions' import { _TypedDataEncoder } from '@ethersproject/hash' import { permit2Address, Quote } from '@orbs-network/liquidity-hub-sdk' import { SwapStatus } from '@orbs-network/swap-ui' import { useLiquidityHubSDK } from './useLiquidityHubSDK' import { SwapSteps } from '@/types' -import { Address } from 'viem' import { wagmiConfig, - IWETHabi, - networks, waitForConfirmations, promiseWithTimeout, getSteps, diff --git a/src/trade/swap/swap-confirmation-dialog.tsx b/src/trade/swap-confirmation-dialog.tsx similarity index 100% rename from src/trade/swap/swap-confirmation-dialog.tsx rename to src/trade/swap-confirmation-dialog.tsx diff --git a/src/trade/trade.tsx b/src/trade/trade.tsx index 192f1b1..aa8f880 100644 --- a/src/trade/trade.tsx +++ b/src/trade/trade.tsx @@ -1,4 +1,5 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' +import { Swap } from './liquidity-hub/liquidity-hub-swap' import { Twap } from './twap/twap' export function Trade() { @@ -6,23 +7,20 @@ export function Trade() {

Trade

- + Swap TWAP Limit - {/* */} + -
- -
Coming soon
-
+
diff --git a/src/trade/twap/components/limit-price-input.tsx b/src/trade/twap/components/limit-price-input.tsx index dfb2f2c..3d20d76 100644 --- a/src/trade/twap/components/limit-price-input.tsx +++ b/src/trade/twap/components/limit-price-input.tsx @@ -111,7 +111,7 @@ export function LimitPriceInput() { if (isMarketOrder) return null; return ( - +

when 1

diff --git a/src/trade/twap/hooks.ts b/src/trade/twap/hooks.ts index 2a42ca2..4c25cd6 100644 --- a/src/trade/twap/hooks.ts +++ b/src/trade/twap/hooks.ts @@ -11,7 +11,7 @@ import { useTwapContext } from "./twap-context"; import BN from "bignumber.js"; import { useToExactAmount } from "../hooks"; import { - MAX_FILL_DELAY_FORMATTED, + MAX_FILL_DELAY_DAYS, MIN_DURATION_MINUTES, MIN_FILL_DELAY_MINUTES, } from "@orbs-network/twap-sdk"; @@ -118,7 +118,7 @@ const useFillDelayWarning = () => { return `Min. trade interval is ${MIN_FILL_DELAY_MINUTES} minutes`; } if (warnings.minFillDelay) { - return `Max. trade interval is ${MAX_FILL_DELAY_FORMATTED} days`; + return `Max. trade interval is ${MAX_FILL_DELAY_DAYS} days`; } }, [warnings.maxFillDelay, warnings.minFillDelay]); }; diff --git a/src/trade/twap/orders/orders.tsx b/src/trade/twap/orders/orders.tsx index e86b8dc..d346732 100644 --- a/src/trade/twap/orders/orders.tsx +++ b/src/trade/twap/orders/orders.tsx @@ -19,9 +19,11 @@ import { format, makeElipsisAddress, useTokensList, + wagmiConfig, + waitForConfirmations, } from "@/lib"; import { Token } from "@/types"; -import { Order, OrderStatus, OrderType } from "@orbs-network/twap-sdk"; +import { Order, OrderStatus, OrderType, TwapAbi } from "@orbs-network/twap-sdk"; import { AvatarImage } from "@radix-ui/react-avatar"; import { ArrowRightIcon, ChevronDownIcon } from "lucide-react"; import { useCallback, useMemo } from "react"; @@ -30,6 +32,14 @@ import { OrdersContextProvider, useOrdersContext } from "./orders-context"; import { useGroupedOrders, useOrdersQuery } from "./use-orders-query"; import { useExplorer, useToExactAmount } from "@/trade/hooks"; import moment from "moment"; +import { useMutation } from "@tanstack/react-query"; +import { useTwapContext } from "../twap-context"; +import { + writeContract, + simulateContract, + getTransactionReceipt, +} from "wagmi/actions"; +import { useAccount } from "wagmi"; export function Orders() { return ( @@ -41,19 +51,17 @@ export function Orders() { } const OrdersModal = () => { - const { isOpen, setIsOpen, selectedOrderID,setSelectedOrderID } = useOrdersContext(); - - const onClose = useCallback( - () => { - if(selectedOrderID){ - setSelectedOrderID(undefined); - }else{ - setIsOpen(false); - } - }, - [setIsOpen, selectedOrderID, setSelectedOrderID], - ) - + const { isOpen, setIsOpen, selectedOrderID, setSelectedOrderID } = + useOrdersContext(); + + const onClose = useCallback(() => { + if (selectedOrderID) { + setSelectedOrderID(undefined); + } else { + setIsOpen(false); + } + }, [setIsOpen, selectedOrderID, setSelectedOrderID]); + return ( @@ -69,10 +77,11 @@ const OrdersModal = () => { const OrdersMenu = () => { const groupedOrders = useGroupedOrders(); - const { selectedOrdersGroup, setSelectedOrdersGroup , selectedOrderID} = useOrdersContext(); + const { selectedOrdersGroup, setSelectedOrdersGroup, selectedOrderID } = + useOrdersContext(); const selectedOrderCount = groupedOrders?.[selectedOrdersGroup]?.length || 0; - if(selectedOrderID) return null; + if (selectedOrderID) return null; return ( @@ -131,6 +140,42 @@ const getOrderTitle = (order: Order) => { } }; +const useCancelOrder = () => { + const { twapSDK } = useTwapContext(); + const { refetch } = useOrdersQuery(); + const {address: account} = useAccount() + return useMutation({ + mutationFn: async (orderID: number) => { + twapSDK.analytics.onCancelOrderRequest(orderID); + const simulatedData = await simulateContract(wagmiConfig, { + abi: TwapAbi, + functionName: "cancel", + address: twapSDK.config.twapAddress as any, + account, + args: [orderID], + }); + + const hash = await writeContract(wagmiConfig, simulatedData.request); + await waitForConfirmations(hash, 1, 20); + await getTransactionReceipt(wagmiConfig, { + hash, + }); + twapSDK.analytics.onCancelOrderSuccess(); + await refetch(); + }, + onError: (error) => { + + twapSDK.analytics.onCancelOrderError(error); + }, + }); +}; + + +const CancelOrderButton = ({ order }: { order: Order }) => { + const {isPending, mutate} =useCancelOrder(); + return +} + const SelectedOrder = () => { const { data } = useOrdersQuery(); const { selectedOrderID } = useOrdersContext(); @@ -147,10 +192,12 @@ const SelectedOrder = () => { return (
-

+

#{order.id} {getOrderTitle(order)}

-

{order.status}

+

+ {order.status} +

@@ -161,6 +208,7 @@ const SelectedOrder = () => { outToken={outToken} />
+ {order.status === OrderStatus.Open && }
); }; @@ -338,105 +386,113 @@ export const SelectedOrderDetails = ({ return ( - - - - -
- Execution summary - -
-
-
- - -

{order.status}

-
- - -

- {amountSent - ? `${format.crypto(Number(amountSent))} ${inToken?.symbol}` - : ` - ${inToken?.symbol}`} -

-
- -

- {amountReceived - ? `${format.crypto(Number(amountReceived))} ${ - outToken?.symbol - }` - : ` - ${outToken?.symbol}`} -

-
- -

{`${order.progress}%`}

-
- -

- {executionPrice - ? `${format.crypto(Number(executionPrice))}` - : "-"} -

-
-
-
- -
- - - - -
- Order info - -
-
-
- - {!order.isMarketOrder && ( - -

{limitPrice}

-
- )} - - -

{moment(order.createdAt).format("DD/MM/YY HH:mm")} UTC

-
- - -

{`${ - amountOut - ? `${format.crypto(Number(amountOut))} ${inToken?.symbol}` - : `- ${inToken?.symbol}` - }`}

-
- {order.totalChunks && ( - + + +
+ Execution summary + - )} - {order.totalChunks > 1 && ( - -

{order.totalChunks}

-
- )} - {!order.isMarketOrder && ( - + + + + +

{order.status}

+
+ + +

+ {amountSent + ? `${format.crypto(Number(amountSent))} ${inToken?.symbol}` + : ` - ${inToken?.symbol}`} +

+
+ +

+ {amountReceived + ? `${format.crypto(Number(amountReceived))} ${outToken?.symbol}` + : ` - ${outToken?.symbol}`} +

+
+ +

{`${order.progress}%`}

+
+ +

+ {executionPrice + ? `${format.crypto(Number(executionPrice))}` + : "-"} +

+
+
+
+ + + + +
+ Order info + - )} - - - - {makeElipsisAddress(order.txHash)} - +
+
+
+ + {!order.isMarketOrder && ( + +

{limitPrice}

-
-
- + )} + + +

{moment(order.createdAt).format("DD/MM/YY HH:mm")} UTC

+
+ + +

{`${ + amountOut + ? `${format.crypto(Number(amountOut))} ${inToken?.symbol}` + : `- ${inToken?.symbol}` + }`}

+
+ {order.totalChunks && ( + + )} + {order.totalChunks > 1 && ( + +

{order.totalChunks}

+
+ )} + {!order.isMarketOrder && ( + + )} + + + + {makeElipsisAddress(order.txHash)} + + +
+
); diff --git a/src/trade/twap/orders/use-orders-query.ts b/src/trade/twap/orders/use-orders-query.ts index 08545a7..8bf6649 100644 --- a/src/trade/twap/orders/use-orders-query.ts +++ b/src/trade/twap/orders/use-orders-query.ts @@ -24,6 +24,7 @@ export function useOrdersQuery() { }, enabled: !!address, staleTime: Infinity, + refetchInterval: 20_000, }); } diff --git a/src/trade/twap/twap-confirmation-dialog.tsx b/src/trade/twap/twap-confirmation-dialog.tsx index 71a8eb7..39cbbc3 100644 --- a/src/trade/twap/twap-confirmation-dialog.tsx +++ b/src/trade/twap/twap-confirmation-dialog.tsx @@ -1,7 +1,7 @@ import { Button } from "@/components/ui/button"; import { SwapSteps } from "@/types"; import { useCallback, useMemo } from "react"; -import { SwapConfirmationDialog } from "../swap/swap-confirmation-dialog"; +import { SwapConfirmationDialog } from "../swap-confirmation-dialog"; import { useDerivedTwapSwapData, useInputLabels, @@ -11,16 +11,15 @@ import { import { useTwapContext } from "./twap-context"; import { format, - makeElipsisAddress, resolveNativeTokenAddress, useGetRequiresApproval, } from "@/lib"; import { OrderDetails } from "@/components/order-details"; -import { useExplorer, useToExactAmount } from "../hooks"; +import { useToExactAmount } from "../hooks"; import { useAccount } from "wagmi"; import { useSwapState } from "../use-swap-state"; import { SwapStatus } from "@orbs-network/swap-ui"; -import { Address } from "viem"; +import { Address, hexToNumber } from "viem"; import { getSteps, isNativeAddress, @@ -41,6 +40,7 @@ import { import { SwapState } from "../use-swap-state"; import { useWaitForNewOrderCallback } from "./orders/use-orders-query"; + export function TwapConfirmationDialog({ isOpen, onClose: _onClose, @@ -49,13 +49,13 @@ export function TwapConfirmationDialog({ onClose: (swapStatus?: SwapStatus) => void; }) { const context = useTwapContext(); - const { twapSDK, parsedInputAmount } = context; + const { twapSDK, parsedInputAmount, isMarketOrder } = context; const { outToken, inToken, typedAmount } = context.state.values; const { destTokenAmount } = useDerivedTwapSwapData(); const dstAmount = useToExactAmount(destTokenAmount, outToken?.decimals); const outAmountUsd = useOutTokenUsd(); const inAmountUsd = useInTokenUsd(); - const { state, updateState } = useSwapState(); + const { state, updateState, resetState } = useSwapState(); const parsedSteps = useParsedSteps(state.steps); const { inputLabel, outputLabel } = useInputLabels(); const { requiresApproval, approvalLoading } = useGetRequiresApproval( @@ -70,14 +70,17 @@ export function TwapConfirmationDialog({ const onClose = useCallback(() => { _onClose(state.swapStatus); - }, [_onClose, state.swapStatus]); + if(state.currentStep) { + resetState(); + } + }, [_onClose, state.swapStatus, state.currentStep, resetState]); return ( { const Details = () => { const { deadline, srcChunkAmount, chunks, fillDelay, destTokenMinAmount } = useDerivedTwapSwapData(); - const { inToken, outToken } = useTwapContext().state.values; + const context = useTwapContext(); + const { isMarketOrder } = context; + const { inToken, outToken } = context.state.values; return ( - - + {chunks > 1 && ( + + )} + {chunks > 1 && } - + {!isMarketOrder && ( + + )} ); @@ -189,6 +203,45 @@ const TradePrice = () => { ); }; +const useWrapCallback = () => { + const { twapSDK } = useTwapContext(); + + return useCallback( + async (account: string, inAmount: string) => { + try { + twapSDK.analytics.onWrapRequest(); + await wrapToken(account, inAmount); + twapSDK.analytics.onWrapSuccess(); + } catch (error) { + twapSDK.analytics.onWrapError(error); + throw error; + } + }, + [twapSDK] + ); +}; + +const useApproveCallback = () => { + const { twapSDK } = useTwapContext(); + + return useCallback( + async (account: string, inTokenAddress: string) => { + try { + twapSDK.analytics.onApproveRequest(); + await approveAllowance( + account, + inTokenAddress, + twapSDK.config.twapAddress as Address + ); + twapSDK.analytics.onApproveSuccess(); + } catch (error) { + twapSDK.analytics.onApproveError(error); + throw error; + } + }, + [twapSDK] + ); +}; function useCreateOrder( updateState: (state: Partial) => void, @@ -203,7 +256,9 @@ function useCreateOrder( } = useTwapContext(); const derivedValues = useDerivedTwapSwapData(); const { address: account } = useAccount(); - const {mutateAsync: waitForNewOrder} = useWaitForNewOrderCallback() + const { mutateAsync: waitForNewOrder } = useWaitForNewOrderCallback(); + const wrapTokenCallback = useWrapCallback(); + const approveAllowanceCallback = useApproveCallback(); return useMutation({ mutationFn: async () => { @@ -211,6 +266,7 @@ function useCreateOrder( if (!inToken || !account || !parsedInputAmount || !outToken) { throw new Error("Missing required dependencies"); } + updateState({ swapStatus: SwapStatus.LOADING }); const steps = getSteps({ @@ -221,40 +277,36 @@ function useCreateOrder( if (steps.includes(SwapSteps.Wrap)) { updateState({ currentStep: SwapSteps.Wrap }); - await wrapToken(account, parsedInputAmount); + await wrapTokenCallback(account, parsedInputAmount); // wrap } if (steps.includes(SwapSteps.Approve)) { - await approveAllowance( - account, - inToken.address, - twapSDK.config.twapAddress as Address - ); updateState({ currentStep: SwapSteps.Approve }); + await approveAllowanceCallback(account, inToken.address); } updateState({ currentStep: SwapSteps.Swap }); - const askParams = twapSDK - .prepareOrderArgs({ - fillDelay: derivedValues.fillDelay, - deadline: derivedValues.deadline, - srcAmount: parsedInputAmount ?? "0", - destTokenMinAmount: derivedValues.destTokenMinAmount, - srcChunkAmount: derivedValues.srcChunkAmount, - srcTokenAddress: inToken.address, - destTokenAddress: isNativeAddress(outToken?.address) - ? zeroAddress - : outToken.address, - }) - .map((it) => it.toString()); + .prepareOrderArgs({ + fillDelay: derivedValues.fillDelay, + deadline: derivedValues.deadline, + srcAmount: parsedInputAmount ?? "0", + destTokenMinAmount: derivedValues.destTokenMinAmount, + srcChunkAmount: derivedValues.srcChunkAmount, + srcTokenAddress: resolveNativeTokenAddress(inToken.address)!, + destTokenAddress: isNativeAddress(outToken?.address) + ? zeroAddress + : outToken.address, + }) + .map((it) => it.toString()); + twapSDK.analytics.onCreateOrderRequest(askParams, account); const simulatedData = await simulateContract(wagmiConfig, { abi: TwapAbi, functionName: "ask", - account: account as any, - address: twapSDK.config.twapAddress as any, + account: account as Address, + address: twapSDK.config.twapAddress as Address, args: [askParams], }); @@ -264,17 +316,20 @@ function useCreateOrder( hash, }); - console.log({receipt}); - - - updateState({ swapStatus: SwapStatus.SUCCESS }); + const orderID = hexToNumber(receipt.logs[0].topics[1]!) + + await waitForNewOrder(orderID); + twapSDK.analytics.onCreateOrderSuccess(hash); toast.success("Order created successfully!"); - await waitForNewOrder(undefined) + updateState({ swapStatus: SwapStatus.SUCCESS }); + return receipt; } catch (error) { + if (isTxRejected(error)) { updateState({ swapStatus: undefined }); } else { + twapSDK.analytics.onCreateOrderError(error); updateState({ swapStatus: SwapStatus.FAILED }); } } diff --git a/src/trade/twap/twap-context.tsx b/src/trade/twap/twap-context.tsx index fa8a2cd..29a9e53 100644 --- a/src/trade/twap/twap-context.tsx +++ b/src/trade/twap/twap-context.tsx @@ -129,7 +129,7 @@ export const useTwapStateActions = () => { state: { updateState, values }, } = useTwapContext(); - const { inToken, outToken, isTradePriceInverted } = values; + const { inToken, outToken } = values; const setOutToken = useCallback( (outToken: Token) => { diff --git a/src/trade/twap/twap.tsx b/src/trade/twap/twap.tsx index ec66cbc..af220c2 100644 --- a/src/trade/twap/twap.tsx +++ b/src/trade/twap/twap.tsx @@ -46,11 +46,13 @@ export function Panel() { // Get wagmi account const account = useAccount(); + const { state } = useTwapContext(); + const { updateState, resetState, values: { inToken, outToken, typedAmount }, - } = useTwapContext().state; + } = state; // Set Initial Tokens const defaultTokens = useDefaultTokens({ diff --git a/src/types.ts b/src/types.ts index 9715999..9346d5d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,3 @@ -import { SwapStatus } from "@orbs-network/swap-ui" export type Token = { address: string diff --git a/tsconfig.app.tsbuildinfo b/tsconfig.app.tsbuildinfo new file mode 100644 index 0000000..c110155 --- /dev/null +++ b/tsconfig.app.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./src/app.tsx","./src/main.tsx","./src/root.tsx","./src/types.ts","./src/vite-env.d.ts","./src/components/header.tsx","./src/components/order-details.tsx","./src/components/spinner.tsx","./src/components/swap-details.tsx","./src/components/theme-toggle.tsx","./src/components/tokens/token-card.tsx","./src/components/tokens/token-select.tsx","./src/components/ui/avatar.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/data-details.tsx","./src/components/ui/dialog.tsx","./src/components/ui/dropdown-menu.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/popover.tsx","./src/components/ui/separator.tsx","./src/components/ui/skeleton.tsx","./src/components/ui/sonner.tsx","./src/components/ui/switch-button.tsx","./src/components/ui/switch.tsx","./src/components/ui/tabs.tsx","./src/components/ui/tooltip.tsx","./src/lib/abis.ts","./src/lib/approveallowance.ts","./src/lib/getrequiresapproval.ts","./src/lib/index.ts","./src/lib/networks.ts","./src/lib/usebalances.ts","./src/lib/usedebounce.ts","./src/lib/usedefaulttokens.ts","./src/lib/usegetrequiresapproval.ts","./src/lib/usehandleinputerror.ts","./src/lib/useparaswap.ts","./src/lib/usepriceusd.ts","./src/lib/usetokenlist.ts","./src/lib/usetokenswithbalances.ts","./src/lib/usewraporunwraponly.ts","./src/lib/utils.ts","./src/lib/wagmi-config.ts","./src/lib/wraptoken.ts","./src/providers/rainbow-provider.tsx","./src/providers/theme-provider.tsx","./src/trade/hooks.ts","./src/trade/swap-confirmation-dialog.tsx","./src/trade/trade.tsx","./src/trade/use-swap-state.ts","./src/trade/liquidity-hub/liquidity-hub-confirmation-dialog.tsx","./src/trade/liquidity-hub/liquidity-hub-swap.tsx","./src/trade/liquidity-hub/useliquidityhubquote.ts","./src/trade/liquidity-hub/useliquidityhubsdk.ts","./src/trade/liquidity-hub/useliquidityhubswapcallback.ts","./src/trade/twap/hooks.ts","./src/trade/twap/twap-confirmation-dialog.tsx","./src/trade/twap/twap-context.tsx","./src/trade/twap/twap.tsx","./src/trade/twap/usetwapsdk.ts","./src/trade/twap/utils.ts","./src/trade/twap/components/inputs.tsx","./src/trade/twap/components/limit-price-input.tsx","./src/trade/twap/components/price-toggle.tsx","./src/trade/twap/components/src-chunk-size.tsx","./src/trade/twap/orders/orders-context.tsx","./src/trade/twap/orders/orders.tsx","./src/trade/twap/orders/use-orders-query.ts"],"version":"5.6.3"} \ No newline at end of file diff --git a/tsconfig.node.tsbuildinfo b/tsconfig.node.tsbuildinfo new file mode 100644 index 0000000..75ea001 --- /dev/null +++ b/tsconfig.node.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./vite.config.ts"],"version":"5.6.3"} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 5194f38..f9bd531 100644 --- a/yarn.lock +++ b/yarn.lock @@ -993,10 +993,10 @@ resolved "https://registry.yarnpkg.com/@orbs-network/swap-ui/-/swap-ui-0.0.14.tgz#7604c3604d9bb089c07b1ea1f222f2719d26bb23" integrity sha512-19Blk3JYsxae6Eu8a/nsLA8EbNSMQSJfsgV7Tg52RPs6IglTjEwfGyjy3HUPzRqEYXiHCQFo8xGNHjSKx3HJ5g== -"@orbs-network/twap-sdk@^2.0.37": - version "2.0.37" - resolved "https://registry.yarnpkg.com/@orbs-network/twap-sdk/-/twap-sdk-2.0.37.tgz#2f8a4248702cdaa8e65c2538d18c47529f99efff" - integrity sha512-lBW+BO6QksAk/f9Fp+L3KYivBRaUGNV8bWErh8Nn5Uedrb1dcnCBxvIqEGWer0iQFzl0PlKhvthmSLFYRRejcw== +"@orbs-network/twap-sdk@^2.0.38": + version "2.0.38" + resolved "https://registry.yarnpkg.com/@orbs-network/twap-sdk/-/twap-sdk-2.0.38.tgz#c2f268da1c14e10f475f79e50d85e237d704b867" + integrity sha512-U7nBRA7tghIWQPbhdqqPOTm6VyoEVGHmjkZKE1ddYyAvQLSi+V/7Pnn1xi7OP7xYSBCl0YmmA3C/GPYGJGdfVA== dependencies: "@orbs-network/twap" "^2.0.1" bignumber.js "9.x"