Skip to content

Commit

Permalink
add UI to bridge page (#1277)
Browse files Browse the repository at this point in the history
* add UI to bridge page

* remove UI from modal, add link.

* remove modal

* remove link from balance well
  • Loading branch information
sentilesdal authored Jul 16, 2024
1 parent 8bbedba commit 14625cd
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 192 deletions.
44 changes: 38 additions & 6 deletions apps/hyperdrive-trading/src/ui/bridge/Bridge.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,46 @@
import { ServerChainBalance } from "@delvtech/gopher";
import { ReactElement } from "react";
import Chains from "src/ui/bridge/Chains/Chains";
import TokenBalances from "src/ui/bridge/TokenBalances/TokenBalances";
import Tokens from "src/ui/bridge/Tokens/Tokens";
import { BridgeAssetsForm } from "src/ui/bridge/BridgeAssetsForm/BridgeAssetsForm";
import { useBridgeChainsByChainId } from "src/ui/bridge/hooks/useBridgeChainsByChainId";
import { useBridgeTokenBalances } from "src/ui/bridge/hooks/useBridgeTokenBalances";
import { useBridgeTokens } from "src/ui/bridge/hooks/useBridgeTokens";
import { Route } from "src/ui/routes/bridge";
import { useAccount } from "wagmi";

export function Bridge(): ReactElement {
const { token, destination } = Route.useSearch();
const { chains } = useBridgeChainsByChainId();
const { address: accountAddress } = useAccount();
const { tokens } = useBridgeTokens();
const { balances = [[]] } = useBridgeTokenBalances(
accountAddress,
tokens?.map((t) => t.symbol) || [],
);

const balancesByTokens: Record<string, ServerChainBalance[]> = {};
tokens?.forEach((token, index) => {
balancesByTokens[token.symbol] = balances[index];
});

// Double check the default token has a balance.
const tokenWithBalance = tokens?.find((t, index) => {
return (
t.symbol === token &&
balances[index]?.some((balance) => Number(balance.balance) > 0)
);
});

if (!tokenWithBalance) {
return <div>No token balances to bridge</div>;
}

return (
<div className="m-6 flex flex-col space-y-6">
<TokenBalances />
<Tokens />
<Chains />
<div>{`Destination Chain: ${chains?.[destination]?.name}`}</div>
<BridgeAssetsForm
destinationChainId={destination}
token={tokenWithBalance}
/>
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
import { EntityFungibleToken, ServerChainBalance } from "@delvtech/gopher";
import { MouseEvent, ReactElement, useEffect, useState } from "react";
import { TokenConfig } from "@hyperdrive/appconfig";
import { MouseEvent, ReactElement, useState } from "react";
import { formatBalance } from "src/ui/base/formatting/formatBalance";
import { useNumericInput } from "src/ui/base/hooks/useNumericInput";
import { BridgeAssetsPicker } from "src/ui/bridge/BridgeAssetsForm/BridgeAssetPicker";
import { BridgeAssetsActionButtons } from "src/ui/bridge/BridgeAssetsForm/BridgeAssetsActionButtons";
import { BridgePreview } from "src/ui/bridge/BridgeAssetsForm/BridgePreview";
import { useAggregationSolution } from "src/ui/bridge/hooks/useAggregationSolution";
import { useBridgeChainsByChainId } from "src/ui/bridge/hooks/useBridgeChainsByChainId";
import { useBridgeTokenBalances } from "src/ui/bridge/hooks/useBridgeTokenBalances";
import { useBridgeTokens } from "src/ui/bridge/hooks/useBridgeTokens";
import { TransactionView } from "src/ui/hyperdrive/TransactionView";
import { TokenInput } from "src/ui/token/TokenInput";
import { Address, formatUnits, parseUnits } from "viem";
import { TokenChoice, TokenPicker } from "src/ui/token/TokenPicker";
import { Address, parseUnits } from "viem";
import { useAccount, useChainId } from "wagmi";

interface BridgeAssetsFormProps {
destinationChainId: number;
token: EntityFungibleToken;
onCloseBridgeUI?: (e: MouseEvent<HTMLButtonElement>) => void;
}

export function BridgeAssetsForm({
token,
destinationChainId,
onCloseBridgeUI,
}: BridgeAssetsFormProps): ReactElement {
const { address: account } = useAccount();
const { chains = {} } = useBridgeChainsByChainId();
const activeChainId = useChainId();
const { balances } = useBridgeTokenBalances(account, [token.symbol]);
const [activeToken, setActiveToken] = useState<EntityFungibleToken>(token);
const { balances } = useBridgeTokenBalances(account, [activeToken.symbol]);

// Keep track of the value from TokenInput.
const { amount: bridgeAmount, setAmount } = useNumericInput({
Expand All @@ -44,11 +50,12 @@ export function BridgeAssetsForm({

// Calculates the sum of balances for the active chains.
const maxButtonValue = calculateMaxButtonValue(
activeChainId,
destinationChainId,
balances,
activeBridgeChains,
);

console.log("maxButtonValue", maxButtonValue);
// Fetch a quote based on the user's input.
const { solution, status: quoteStatus } = useQuote({
account,
Expand All @@ -60,11 +67,36 @@ export function BridgeAssetsForm({
// Keep track of whether we're showing the preview and bridge buttons.
const [showPreview, setShowPreview] = useState(false);

// Hide preview when we fetch a new quote.
useEffect(() => {
setShowPreview(false);
}, [quoteStatus]);
const { tokens } = useBridgeTokens();
const tokensWithBalances =
tokens?.filter((token) => {
const hasBalance = balances?.[0]?.some(
(chainBalance) => Number(chainBalance.balance) > 0,
);
return hasBalance;
}) ?? [];
const tokenChoices: TokenChoice[] =
tokens?.map((token) => {
return {
tokenConfig: {
address: token.addresses[destinationChainId],
name: token.name,
symbol: token.symbol,
decimals: token.decimals,
places: token.decimals,
tags: [],
iconUrl: token.logoURI,
extensions: {},
} as TokenConfig,
};
}) || [];

const maxValue = formatBalance({
balance: maxButtonValue,
decimals: token.decimals,
places: token.decimals,
includeCommas: false,
});
return (
<TransactionView
tokenInput={
Expand All @@ -79,13 +111,28 @@ export function BridgeAssetsForm({
}
name={token.symbol}
token={
<div className="daisy-join-item flex h-12 shrink-0 items-center gap-1.5 border border-neutral-content/30 bg-base-100 px-4">
<img src={token?.logoURI} className="h-5 " />{" "}
<span className="text-sm font-semibold">{token.symbol}</span>
</div>
<TokenPicker
tokens={tokenChoices}
activeTokenAddress={
activeToken.addresses[destinationChainId] as Address
}
onChange={(tokenAddress) => {
const token = tokens?.find(
(t) => t.addresses[destinationChainId] === tokenAddress,
);
if (token) {
setActiveToken(token);
}
}}
joined={true}
/>
}
value={bridgeAmount ?? ""}
maxValue={formatUnits(maxButtonValue, token.decimals)}
maxValue={formatBalance({
balance: maxButtonValue,
decimals: token.decimals,
includeCommas: false,
})}
inputLabel="Amount to bridge"
onChange={(newAmount) => setAmount(newAmount)}
/>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export function useBridgeTokenBalances(
balances: ServerChainBalance[][] | undefined;
status: QueryStatus;
} {
console.log("tokenSymbols", tokenSymbols);
const enabled = !!account;
const { data = [], status } = useQuery({
queryKey: makeQueryKey("gopher", {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
findYieldSourceToken,
HyperdriveConfig,
} from "@hyperdrive/appconfig";
import { Link } from "@tanstack/react-router";

import { MouseEvent, ReactElement } from "react";
import { getIsValidTradeSize } from "src/hyperdrive/getIsValidTradeSize";
Expand Down Expand Up @@ -35,19 +36,19 @@ import { TokenInputTwo } from "src/ui/token/TokenInputTwo";
import { TokenPicker } from "src/ui/token/TokenPicker";
import { TokenPickerTwo } from "src/ui/token/TokenPickerTwo";
import { formatUnits } from "viem";
import { useAccount } from "wagmi";
import { useAccount, useChainId } from "wagmi";

interface OpenLongFormProps {
hyperdrive: HyperdriveConfig;
onOpenLong?: (e: MouseEvent<HTMLButtonElement>) => void;
onOpenBridge?: (e: MouseEvent<HTMLButtonElement>) => void;
}

export function OpenLongForm({
hyperdrive: hyperdrive,
onOpenLong,
onOpenBridge,
}: OpenLongFormProps): ReactElement {
const { address: account } = useAccount();
const chainId = useChainId();
const { isFlagEnabled: isBridgingEnabled } = useFeatureFlag("bridge");
const { isFlagEnabled: isNewOpenLongFormEnabled } =
useFeatureFlag("new-open-long-form");
Expand Down Expand Up @@ -207,8 +208,20 @@ export function OpenLongForm({
activeToken.decimals,
);
}
const switchToBridgeUIButton = (
<button onClick={onOpenBridge}>{`Bridge ${tokenSymbol} from L2s`}</button>

const switchToBridgeUILink = (
<Link
to="/bridge"
search={{
token: activeToken.symbol,
destination: chainId,
}}
className="daisy-btn daisy-btn-link"
target="_blank"
rel="noopener noreferrer"
>
{`Bridge ${tokenSymbol} from L2s`}
</Link>
);

return (
Expand Down Expand Up @@ -300,9 +313,7 @@ export function OpenLongForm({
)
}
setting={
isBridgingEnabled && hasBridgeableBalance
? switchToBridgeUIButton
: null
isBridgingEnabled && hasBridgeableBalance ? switchToBridgeUILink : null
}
primaryStats={
isNewOpenLongFormEnabled ? (
Expand Down
Loading

0 comments on commit 14625cd

Please sign in to comment.