Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jonator committed Jul 2, 2024
1 parent 9f57f84 commit 48ce3b3
Show file tree
Hide file tree
Showing 27 changed files with 351 additions and 77 deletions.
11 changes: 11 additions & 0 deletions packages/trpc/src/chains.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { getChain } from "@osmosis-labs/server";
import { EthereumChainInfo } from "@osmosis-labs/utils";
import { z } from "zod";

import { createTRPCRouter, publicProcedure } from "./api";

export const chainsRouter = createTRPCRouter({
/** Get Cosmos chain. */
getChain: publicProcedure
.input(
z.object({
Expand All @@ -16,4 +18,13 @@ export const chainsRouter = createTRPCRouter({
chainNameOrId: findChainNameOrId,
})
),
getEvmChain: publicProcedure
.input(
z.object({
chainId: z.number(),
})
)
.query(async ({ input: { chainId } }) =>
Object.values(EthereumChainInfo).find((chain) => chain.id === chainId)
),
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,13 @@ import { getAddress } from "viem";
import { AmountScreen } from "~/components/bridge/immersive/amount-screen";
import { ImmersiveBridgeScreens } from "~/components/bridge/immersive/immersive-bridge";
import { useBridgeQuotes } from "~/components/bridge/immersive/use-bridge-quotes";
import { useBridgesSupportedAssets } from "~/components/bridge/immersive/use-bridges-supported-assets";
import { SupportedAsset } from "~/components/bridge/immersive/use-bridges-supported-assets";
import { Screen } from "~/components/screen-manager";
import { useEvmWalletAccount } from "~/hooks/evm-wallet";
import { useStore } from "~/stores";

import { ReviewScreen } from "./review-screen";

export type SupportedAsset = ReturnType<
typeof useBridgesSupportedAssets
>["supportedAssetsByChainId"][string][number];

export type SupportedAssetWithAmount = SupportedAsset & { amount: CoinPretty };

interface AmountAndConfirmationScreenProps {
Expand Down
9 changes: 4 additions & 5 deletions packages/web/components/bridge/immersive/amount-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ import { BridgeNetworkSelectModal } from "~/components/bridge/immersive/bridge-n
import { BridgeWalletSelectModal } from "~/components/bridge/immersive/bridge-wallet-select-modal";
import { ImmersiveBridgeScreens } from "~/components/bridge/immersive/immersive-bridge";
import { MoreBridgeOptions } from "~/components/bridge/immersive/more-bridge-options";
import { useBridgesSupportedAssets } from "~/components/bridge/immersive/use-bridges-supported-assets";
import {
SupportedAsset,
useBridgesSupportedAssets,
} from "~/components/bridge/immersive/use-bridges-supported-assets";
import { InputBox } from "~/components/input";
import { SkeletonLoader, Spinner } from "~/components/loaders";
import { useScreenManager } from "~/components/screen-manager";
Expand Down Expand Up @@ -58,10 +61,6 @@ import {
} from "./quote-detail";
import { BridgeQuotes } from "./use-bridge-quotes";

type SupportedAsset = ReturnType<
typeof useBridgesSupportedAssets
>["supportedAssetsByChainId"][string][number];

interface AmountScreenProps {
direction: "deposit" | "withdraw";
selectedDenom: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import classNames from "classnames";
import { FunctionComponent, useEffect, useState } from "react";

import { Spinner } from "~/components/loaders";

export const BridgeQuoteRemainingTime: FunctionComponent<{
className?: string;
refetchInterval: number;
expiredElement?: React.ReactNode;
dataUpdatedAt: number;
}> = ({ className, refetchInterval, expiredElement, dataUpdatedAt }) => {
}> = ({ className, refetchInterval, dataUpdatedAt }) => {
const [progress, setProgress] = useState(100);

useEffect(() => {
Expand All @@ -30,14 +31,14 @@ export const BridgeQuoteRemainingTime: FunctionComponent<{
return () => clearInterval(intervalId);
}, [dataUpdatedAt, refetchInterval]);

if (progress <= 0) {
return expiredElement;
}

return (
<div className={classNames("relative h-7 w-7", className)}>
<div className="absolute top-0 left-0 h-full w-full">
<RadialProgress progress={progress} />
{progress <= 0 ? (
<Spinner className="relative top-0 left-0 !h-full !w-full text-wosmongton-500" />
) : (
<RadialProgress progress={progress} />
)}
</div>
</div>
);
Expand Down
2 changes: 0 additions & 2 deletions packages/web/components/bridge/immersive/quote-detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import classNames from "classnames";
import { FunctionComponent, PropsWithChildren } from "react";

import { Icon } from "~/components/assets";
import { Spinner } from "~/components/loaders";
import { Tooltip } from "~/components/tooltip";
import { t } from "~/hooks";

Expand Down Expand Up @@ -187,7 +186,6 @@ export const ExpandDetailsControlContent: FunctionComponent<
<BridgeQuoteRemainingTime
dataUpdatedAt={selectedQuoteUpdatedAt}
refetchInterval={refetchInterval}
expiredElement={<Spinner className="!h-6 !w-6 text-wosmongton-500" />}
/>
)}
<div className="flex items-center gap-2">
Expand Down
110 changes: 77 additions & 33 deletions packages/web/components/bridge/immersive/review-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { CoinPretty, PricePretty } from "@keplr-wallet/unit";
import { BridgeChain } from "@osmosis-labs/bridge";
import { getShortAddress, isNil } from "@osmosis-labs/utils";
import Image from "next/image";
import Link from "next/link";
import { FunctionComponent, useState } from "react";
import { useMeasure } from "react-use";

Expand All @@ -10,7 +11,6 @@ import { Button } from "~/components/ui/button";
import { useTranslation } from "~/hooks";
import { api } from "~/utils/trpc";

import { SupportedAsset } from "./amount-and-review-screen";
import {
BridgeProviderDropdownRow,
EstimatedTimeRow,
Expand All @@ -20,6 +20,7 @@ import {
TotalFeesRow,
} from "./quote-detail";
import { BridgeQuotes } from "./use-bridge-quotes";
import { SupportedAsset } from "./use-bridges-supported-assets";

interface ConfirmationScreenProps {
direction: "deposit" | "withdraw";
Expand Down Expand Up @@ -64,6 +65,8 @@ export const ReviewScreen: FunctionComponent<ConfirmationScreenProps> = ({
onCancel,
onConfirm,
}) => {
const { t } = useTranslation();

const { data: assetsInOsmosis } =
api.edge.assets.getCanonicalAssetWithVariants.useQuery(
{
Expand All @@ -86,16 +89,34 @@ export const ReviewScreen: FunctionComponent<ConfirmationScreenProps> = ({
(asset) => asset.coinMinimalDenom === toAsset.address
) ?? assetsInOsmosis?.[0];

console.log({ can: quote.userCanInteract });

return (
<div className="mx-auto flex w-[512px] flex-col gap-1 py-12">
<h5>
Confirm {direction} {direction === "withdraw" ? "from" : "to"} Osmosis
<h5 className="pb-6 text-center">
{t(
direction === "withdraw"
? "transfer.confirmWithdrawTo"
: "transfer.confirmDepositTo",
{ chain: quote.toChainInfo?.prettyName ?? "" }
)}
</h5>
<p className="body1 pb-3 text-center text-osmoverse-400">
{t(
direction === "withdraw"
? "transfer.reviewWithdrawP"
: "transfer.reviewDepositP"
)}
</p>
{quote.selectedQuote && (
<AssetBox
type="from"
assetImageUrl={fromVariantAsset?.coinImageUrl ?? "/"}
chainName={fromChain.chainName ?? fromChain.chainId.toString()}
chainName={
quote.fromChainInfo?.prettyName ??
fromChain.chainName ??
fromChain.chainId.toString()
}
address={fromAddress}
walletImageUrl={fromWalletIcon}
value={quote.selectedQuote.quote.input.fiatValue}
Expand All @@ -107,7 +128,11 @@ export const ReviewScreen: FunctionComponent<ConfirmationScreenProps> = ({
<AssetBox
type="to"
assetImageUrl={toVariantAsset?.coinImageUrl ?? "/"}
chainName={toChain.chainName ?? toChain.chainId.toString()}
chainName={
quote.toChainInfo?.prettyName ??
toChain.chainName ??
toChain.chainId.toString()
}
address={toAddress}
walletImageUrl={toWalletIcon}
value={quote.selectedQuote.expectedOutputFiat}
Expand All @@ -116,16 +141,23 @@ export const ReviewScreen: FunctionComponent<ConfirmationScreenProps> = ({
)}
<div className="flex w-full items-center gap-3 py-3">
<Button className="w-full" variant="secondary" onClick={onCancel}>
<h6>Cancel</h6>
<h6>{t("transfer.cancel")}</h6>
</Button>
<Button
className="w-full"
onClick={onConfirm}
disabled={!quote.userCanInteract}
>
<h6>Confirm</h6>
<h6>{t("transfer.confirm")}</h6>
</Button>
</div>
<Link
href="/disclaimer#providers-and-bridge-disclaimer"
target="_blank"
className="mx-auto text-xs font-semibold text-wosmongton-100 hover:text-rust-200"
>
{t("disclaimer")}
</Link>
</div>
);
};
Expand All @@ -146,38 +178,50 @@ const AssetBox: FunctionComponent<{
walletImageUrl,
value,
coin,
}) => (
<div className="flex w-full flex-col gap-2 rounded-2xl border border-osmoverse-700">
<div className="flex place-content-between items-center px-6 pt-4 pb-2">
<div className="flex items-center gap-3">
<Image alt="token image" src={assetImageUrl} width={48} height={48} />
<h6>
{type === "from" ? "Transfer" : "Receive"} {coin.denom}
</h6>
</div>
<div className="text-right">
<div className="subtitle1">
{type === "to" && "~"} {value.toString()}
}) => {
const { t } = useTranslation();
return (
<div className="flex w-full flex-col gap-2 rounded-2xl border border-osmoverse-700">
<div className="flex place-content-between items-center px-6 pt-4 pb-2">
<div className="flex items-center gap-3">
<Image alt="token image" src={assetImageUrl} width={48} height={48} />
<h6>
{t(type === "from" ? "transfer.transfer" : "transfer.receive", {
denom: coin.denom,
})}
</h6>
</div>
<div className="body1 text-osmoverse-300">
{type === "to" && "~"} {coin.trim(true).toString()}
<div className="text-right">
<div className="subtitle1">
{type === "to" && "~"} {value.toString()}
</div>
<div className="body1 text-osmoverse-300">
{type === "to" && "~"} {coin.trim(true).toString()}
</div>
</div>
</div>
</div>
<div className="h-[1px] w-full self-center bg-osmoverse-700" />
<div className="flex place-content-between items-center px-6 pb-3 pt-1">
<div>
{type === "from" ? "From" : "To"} {chainName}
</div>
<div className="flex items-center gap-2">
<Image alt="wallet image" src={walletImageUrl} width={24} height={24} />
<div className="body1 text-wosmongton-200">
{getShortAddress(address)}
<div className="h-[1px] w-full self-center bg-osmoverse-700" />
<div className="flex place-content-between items-center px-6 pb-3 pt-1">
<div>
{t(type === "from" ? "transfer.from" : "transfer.to", {
network: chainName,
})}
</div>
<div className="flex items-center gap-2">
<Image
alt="wallet image"
src={walletImageUrl}
width={24}
height={24}
/>
<div className="body1 text-wosmongton-200">
{getShortAddress(address)}
</div>
</div>
</div>
</div>
</div>
);
);
};

/** Assumes the first provider in the list is the selected provider. */
const TransferDetails: FunctionComponent<BridgeQuotes> = (quote) => {
Expand Down
27 changes: 20 additions & 7 deletions packages/web/components/bridge/immersive/use-bridge-quotes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { BaseError } from "wagmi";

import { displayToast } from "~/components/alert/toast";
import { ToastType } from "~/components/alert/types";
import { useChainDisplayInfo } from "~/components/chain/use-chain-display-info";
import { useEvmWalletAccount, useSendEvmTransaction } from "~/hooks/evm-wallet";
import { useTranslation } from "~/hooks/language";
import { useStore } from "~/stores";
Expand Down Expand Up @@ -412,7 +413,7 @@ export const useBridgeQuotes = ({

const [isApprovingToken, setIsApprovingToken] = useState(false);

const isSendTxPending = (() => {
const isTxPending = (() => {
if (!toChain) return false;
return toChain.chainType === "cosmos"
? accountStore.getWallet(toChain.chainId)?.txTypeInProgress !== ""
Expand All @@ -421,10 +422,10 @@ export const useBridgeQuotes = ({

// close modal when initial eth transaction is committed
useEffect(() => {
if (transferInitiated && !isSendTxPending) {
if (transferInitiated && !isTxPending) {
onRequestClose();
}
}, [isSendTxPending, onRequestClose, transferInitiated]);
}, [isTxPending, onRequestClose, transferInitiated]);

const handleEvmTx = async (
quote: NonNullable<typeof selectedQuote>["quote"]
Expand Down Expand Up @@ -609,13 +610,19 @@ export const useBridgeQuotes = ({
quoteResults.some((quoteResult) => quoteResult.fetchStatus !== "idle");
const isLoadingBridgeTransaction =
bridgeTransaction.isLoading && bridgeTransaction.fetchStatus !== "idle";
const isWithdrawReady = isWithdraw && !isSendTxPending;
const isWithdrawReady = isWithdraw && !isTxPending;
const isWalletConnected =
fromChain?.chainType === "evm"
? isEvmWalletConnected
: fromChain?.chainId
? accountStore.getWallet(fromChain.chainId)?.isWalletConnected ?? false
: false;
const isDepositReady =
isDeposit &&
!isEvmWalletConnected &&
isWalletConnected &&
isCorrectEvmChainSelected &&
!isLoadingBridgeQuote &&
!isEthTxPending;
!isTxPending;
const userCanInteract = isDepositReady || isWithdrawReady;

let buttonText: string;
Expand All @@ -625,7 +632,7 @@ export const useBridgeQuotes = ({
buttonText = t("assets.transfer.transferAnyway");
} else if (isApprovingToken) {
buttonText = t("assets.transfer.approving");
} else if (isSendTxPending) {
} else if (isTxPending) {
buttonText = t("assets.transfer.sending");
} else if (
selectedQuote?.quote?.transactionRequest?.type === "evm" &&
Expand All @@ -644,6 +651,9 @@ export const useBridgeQuotes = ({
throw new Error("Expected output is not defined.");
}

const fromChainInfo = useChainDisplayInfo(fromChain?.chainId);
const toChainInfo = useChainDisplayInfo(toChain?.chainId);

return {
buttonText,
buttonErrorMessage,
Expand All @@ -661,6 +671,9 @@ export const useBridgeQuotes = ({
warnUserOfSlippage,
warnUserOfPriceImpact,

fromChainInfo,
toChainInfo,

successfulQuotes,
selectedBridgeProvider,
setSelectedBridgeProvider: onChangeBridgeProvider,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import { api, RouterOutputs } from "~/utils/trpc";

const bridgeKeys: Bridge[] = ["Skip", "Squid", "Axelar", "IBC"];

export type SupportedAsset = ReturnType<
typeof useBridgesSupportedAssets
>["supportedAssetsByChainId"][string][number];

export const useBridgesSupportedAssets = ({
assets,
chain,
Expand Down
Loading

0 comments on commit 48ce3b3

Please sign in to comment.