Skip to content

Commit

Permalink
Merge pull request #135 from axelarnetwork/refactor/transaction-progr…
Browse files Browse the repository at this point in the history
…ess-cards

several ux fixes and improvements
  • Loading branch information
canhtrinh authored Jan 17, 2024
2 parents 4cf6ec3 + 1214acd commit aedf5d9
Show file tree
Hide file tree
Showing 28 changed files with 338 additions and 236 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -116,21 +116,21 @@ export function useDeployAndRegisterRemoteCanonicalTokenMutation(
return [deployTxData, ...registerTxData];
}, [input, tokenId, destinationChainNames, originalChainName]);

const totalGasFee = useMemo(
() =>
Maybe.of(input?.remoteDeploymentGasFees).mapOrUndefined(
reduce((a, b) => a + b, 0n)
),
[input?.remoteDeploymentGasFees]
const totalGasFee = Maybe.of(input?.remoteDeploymentGasFees).mapOr(
0n,
reduce((a, b) => a + b, 0n)
);

const isMutationReady =
multicallArgs.length > 0 &&
// enable if there are no remote chains or if there are remote chains and the total gas fee is greater than 0
(!destinationChainNames.length || totalGasFee > 0n);

const prepareMulticall = usePrepareInterchainTokenFactoryMulticall({
chainId,
value: totalGasFee,
args: [multicallArgs],
enabled:
multicallArgs.length > 0 &&
(totalGasFee === undefined || totalGasFee > 0n),
enabled: isMutationReady,
});

const multicall = useInterchainTokenFactoryMulticall(prepareMulticall.config);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,14 @@ export const Step3: FC = () => {
type: "deploying",
txHash: tx.hash,
});

addTransaction({
status: "submitted",
hash: tx.hash,
chainId: sourceChain.chain_id,
});
if (rootState.selectedChains.length > 0) {
addTransaction({
status: "submitted",
hash: tx.hash,
chainId: sourceChain.chain_id,
txType: "INTERCHAIN_DEPLOYMENT",
});
}
},
onTransactionError(txError) {
rootActions.setTxState({
Expand All @@ -105,10 +107,10 @@ export const Step3: FC = () => {
});
},
[
rootState.selectedChains.length,
state.totalGasFee,
state.isEstimatingGasFees,
state.hasGasFeesEstimationError,
state.remoteDeploymentGasFees,
state.evmChains,
deployCanonicalTokenAsync,
actions,
sourceChain,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,30 +130,28 @@ export function useDeployAndRegisterRemoteInterchainTokenMutation(
...commonArgs,
originalChainName,
destinationChain,
gasValue: input.remoteDeploymentGasFees[i] ?? 0n,
gasValue: input.remoteDeploymentGasFees?.[i] ?? 0n,
})
);

return [deployTxData, ...registerTxData];
}, [input, tokenId, withDecimals, destinationChainNames, originalChainName]);

const totalGasFee = useMemo(() => {
const remoteDeploymentsGas = Maybe.of(
input?.remoteDeploymentGasFees
).mapOrUndefined(reduce((a, b) => a + b, 0n));
const totalGasFee = Maybe.of(input?.remoteDeploymentGasFees).mapOr(
0n,
reduce((a, b) => a + b, 0n)
);

// the total gas fee is the sum of the remote deployments gas fee,
// the remote transfers gas fee and the origin transfer gas fee
return remoteDeploymentsGas;
}, [input?.remoteDeploymentGasFees]);
const isMutationReady =
multicallArgs.length > 0 &&
// enable if there are no remote chains or if there are remote chains and the total gas fee is greater than 0
(!destinationChainNames.length || totalGasFee > 0n);

const prepareMulticall = usePrepareInterchainTokenFactoryMulticall({
chainId,
value: totalGasFee,
args: [multicallArgs],
enabled:
multicallArgs.length > 0 &&
(totalGasFee === undefined || totalGasFee > 0n),
enabled: isMutationReady,
});

const multicall = useInterchainTokenFactoryMulticall(prepareMulticall.config);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,14 @@ export const Step3: FC = () => {
txHash: tx.hash,
});

addTransaction({
status: "submitted",
hash: tx.hash,
chainId: sourceChain.chain_id,
});
if (rootState.selectedChains.length > 0) {
addTransaction({
status: "submitted",
hash: tx.hash,
chainId: sourceChain.chain_id,
txType: "INTERCHAIN_DEPLOYMENT",
});
}
},
onTransactionError(txError) {
rootActions.setTxState({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,6 @@ export const RegisterRemoteTokens: FC<RegisterRemoteTokensProps> = (props) => {
const { address: deployerAddress } = useAccount();
const [txState, setTxState] = useTransactionState();

useEffect(
() => {
props.onTxStateChange?.(txState);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[txState.status]
);

const { mutateAsync: recordRemoteTokenDeployment } =
trpc.interchainToken.recordRemoteTokensDeployment.useMutation();

Expand Down Expand Up @@ -72,21 +64,36 @@ export const RegisterRemoteTokens: FC<RegisterRemoteTokensProps> = (props) => {
},
});

const { writeAsync: registerCanonicalTokensAsync } =
const { writeAsync: registerCanonicalTokensAsync, reset: resetCanonical } =
useRegisterRemoteCanonicalTokens({
chainIds: props.chainIds,
deployerAddress: deployerAddress as `0x${string}`,
tokenAddress: props.tokenAddress,
originChainId: props.originChainId ?? -1,
});

const { writeAsync: registerInterchainTokensAsync } =
const { writeAsync: registerInterchainTokensAsync, reset: resetInterchain } =
useRegisterRemoteInterchainTokens({
chainIds: props.chainIds,
tokenAddress: props.tokenAddress,
originChainId: props.originChainId ?? -1,
});

useEffect(
() => {
props.onTxStateChange?.(txState);

if (txState.status === "confirmed") {
// reset muations & tx state
resetCanonical();
resetInterchain();
setTxState({ status: "idle" });
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[txState.status]
);

const registerTokensAsync = useMemo(() => {
switch (props.deploymentKind) {
case "canonical":
Expand Down Expand Up @@ -115,6 +122,7 @@ export const RegisterRemoteTokens: FC<RegisterRemoteTokensProps> = (props) => {
status: "submitted",
hash: tx.hash,
chainId: props.originChainId ?? -1,
txType: "INTERCHAIN_DEPLOYMENT",
});
},
onTransactionError(error) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import {
cn,
FormControl,
InputGroup,
SpinnerIcon,
TextInput,
Tooltip,
} from "@axelarjs/ui";
import { cn, FormControl, SpinnerIcon, TextInput, Tooltip } from "@axelarjs/ui";
import { useSessionStorageState } from "@axelarjs/utils/react";
import { useEffect, useMemo, useState, type ChangeEvent, type FC } from "react";

Expand Down Expand Up @@ -101,8 +94,8 @@ const SearchInterchainToken: FC<SearchInterchainTokenProps> = (props) => {
return (
<FormControl className="w-full max-w-xs md:max-w-md">
<div className="pb-2 text-center">Take your token interchain</div>
<InputGroup
className={cn("rounded-md transition-transform", {
<div
className={cn("join rounded-md transition-transform", {
"ring-error ring-offset-base-200 -translate-y-4 ring-1 ring-offset-2":
shouldRenderError,
"ring-offset-base-200 ring-1 ring-offset-2": isFocused,
Expand All @@ -120,11 +113,11 @@ const SearchInterchainToken: FC<SearchInterchainTokenProps> = (props) => {
onChange={(e: ChangeEvent<HTMLInputElement>) =>
setSearch(e.target.value)
}
className="bg-base-200 flex-1 focus:outline-none focus:ring-0"
className="bg-base-200 join-item flex-1 focus:outline-none focus:ring-0"
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
/>
<span>
<div className="btn join-item bg-base-300">
{isLoading && isAddress(search) ? (
<SpinnerIcon className="text-primary h-6 w-6 animate-spin" />
) : (
Expand All @@ -133,7 +126,7 @@ const SearchInterchainToken: FC<SearchInterchainTokenProps> = (props) => {
className="tooltip-left md:tooltip-top"
>
<EVMChainsDropdown
triggerClassName="btn-sm btn-circle"
triggerClassName="btn btn-sm btn-circle"
contentClassName="translate-x-4 translate-y-2 sm:w-96 md:w-[448px]"
compact
hideLabel
Expand All @@ -149,8 +142,8 @@ const SearchInterchainToken: FC<SearchInterchainTokenProps> = (props) => {
/>
</Tooltip>
)}
</span>
</InputGroup>
</div>
</div>
{shouldRenderError && (
<div
role="alert"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
import type { EVMChainConfig } from "@axelarjs/api";
import { Maybe } from "@axelarjs/utils";
import { useMemo, useState } from "react";

import { formatEther } from "viem";
import { useAccount, useBalance } from "wagmi";

import { trpc } from "~/lib/trpc";
import { getNativeToken } from "~/lib/utils/getNativeToken";
import { useEstimateGasFeeQuery } from "~/services/axelarjsSDK/hooks";
import { useEVMChainConfigsQuery } from "~/services/axelarscan/hooks";
import { useERC20TokenDetailsQuery } from "~/services/erc20";
import { useInterchainTokensQuery } from "~/services/gmp/hooks";
import { useTransactionsContainer } from "../Transactions";
import { useInterchainTokenServiceTransferMutation } from "./hooks/useInterchainTokenServiceTransferMutation";
import { useInterchainTransferMutation } from "./hooks/useInterchainTransferMutation";

const toNumericString = (num: bigint) =>
Number(formatEther(num)).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 4,
});

export function useSendInterchainTokenState(props: {
tokenAddress: `0x${string}`;
originTokenAddress?: `0x${string}`;
Expand Down Expand Up @@ -77,6 +89,30 @@ export function useSendInterchainTokenState(props: {
sourceChainName: props.sourceChain.chain_name,
});

const { address } = useAccount();

const { data: balance } = useBalance({
address,
watch: true,
});

const nativeTokenSymbol = getNativeToken(
props.sourceChain.chain_name.toLowerCase()
);
const { data: gas } = useEstimateGasFeeQuery({
sourceChainId: props.sourceChain.chain_name,
destinationChainId: selectedToChain?.chain_name,
sourceChainTokenSymbol: nativeTokenSymbol,
});

const hasInsufficientGasBalance = useMemo(() => {
if (!balance || !gas) {
return false;
}

return gas > balance.value;
}, [balance, gas]);

const {
mutateAsync: tokenManagerSendTokenAsync,
isLoading: isTokenManagerSending,
Expand All @@ -87,6 +123,7 @@ export function useSendInterchainTokenState(props: {
tokenId: props.tokenId,
destinationChainName: selectedToChain?.chain_name,
sourceChainName: props.sourceChain.chain_name,
gas,
});

const trpcContext = trpc.useUtils();
Expand Down Expand Up @@ -131,6 +168,9 @@ export function useSendInterchainTokenState(props: {
selectedToChain,
eligibleTargetChains,
tokenSymbol,
gasFee: Maybe.of(gas).mapOrUndefined(toNumericString),
nativeTokenSymbol,
hasInsufficientGasBalance,
},
{
setIsModalOpen,
Expand Down
Loading

2 comments on commit aedf5d9

@vercel
Copy link

@vercel vercel bot commented on aedf5d9 Jan 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

axelar-ui – ./packages/ui

ui.axelar.dev
axelar-ui.vercel.app
axelar-ui-axelar-network.vercel.app
axelar-ui-git-main-axelar-network.vercel.app

@vercel
Copy link

@vercel vercel bot commented on aedf5d9 Jan 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

axelar-registry – ./apps/registry

axelar-registry-axelar-network.vercel.app
axelar-registry-git-main-axelar-network.vercel.app

Please sign in to comment.