From b350cf7a8c7d72b3512f7be6dffeeaf83b99f17d Mon Sep 17 00:00:00 2001 From: Ken Vu <97480229+ken-centrality@users.noreply.github.com> Date: Fri, 1 Apr 2022 09:44:41 +1300 Subject: [PATCH] Add confirming state to the Bridge (#151) * Reduce the space between `value` and `symbol` * Add `selectMap` * Update progress title during deposit confirming state * Update progress status for withdraw confirming state * Allow mix casing in Progress title --- components/BridgeForm.tsx | 6 +++++- components/BridgeProgress.tsx | 9 +++++++++ providers/BridgeProvider.tsx | 27 +++++++++++++++++++++------ types/index.d.ts | 14 +++++++++++++- utils/ensureRelayerDepositDone.ts | 29 +++++++++++++++++++---------- utils/fetchDepositRelayerStatus.ts | 10 +++------- utils/index.ts | 1 + utils/selectMap.ts | 16 ++++++++++++++++ 8 files changed, 87 insertions(+), 25 deletions(-) create mode 100644 utils/selectMap.ts diff --git a/components/BridgeForm.tsx b/components/BridgeForm.tsx index b4ccfa3f..15944883 100644 --- a/components/BridgeForm.tsx +++ b/components/BridgeForm.tsx @@ -75,7 +75,8 @@ const BridgeForm: FC = ({ metaMaskWallet.getSigner() ); - if (tx !== "cancelled") await ensureRelayerDepositDone(tx.hash); + if (tx !== "cancelled") + await ensureRelayerDepositDone(tx.hash, 600000, setProgressStatus); } catch (error) { console.info(error); return setFailStatus(error?.code); @@ -114,6 +115,7 @@ const BridgeForm: FC = ({ try { await ensureEthereumChain(extension); await ensureBridgeWithdrawActive(api, metaMaskWallet); + setProgressStatus("CennznetConfirming"); eventProof = await sendWithdrawCENNZRequest( api, transferAmount, @@ -131,6 +133,7 @@ const BridgeForm: FC = ({ let tx: Awaited>; try { + setProgressStatus("EthereumConfirming"); tx = await sendWithdrawEthereumRequest( api, eventProof, @@ -182,6 +185,7 @@ const BridgeForm: FC = ({ let tx: Awaited>; try { + setProgressStatus("EthereumConfirming"); tx = await sendWithdrawEthereumRequest( api, eventProof, diff --git a/components/BridgeProgress.tsx b/components/BridgeProgress.tsx index 0519a535..f6866867 100644 --- a/components/BridgeProgress.tsx +++ b/components/BridgeProgress.tsx @@ -97,6 +97,10 @@ const styles = { text-align: center; text-transform: uppercase; color: ${palette.primary.main}; + + span { + text-transform: none !important; + } `, message: ({ palette }: Theme) => css` @@ -114,6 +118,11 @@ const styles = { font-weight: bold; font-style: normal; color: ${palette.primary.main}; + font-size: 0.5em; + span { + font-size: 2em; + letter-spacing: -0.025em; + } } `, diff --git a/providers/BridgeProvider.tsx b/providers/BridgeProvider.tsx index e9439090..35c23c45 100644 --- a/providers/BridgeProvider.tsx +++ b/providers/BridgeProvider.tsx @@ -5,9 +5,10 @@ import { BridgeAction, BridgedEthereumToken, EthereumToken, + RelayerConfirmingStatus, TxStatus, } from "@/types"; -import { Balance } from "@/utils"; +import { Balance, selectMap } from "@/utils"; import { createContext, Dispatch, @@ -42,7 +43,7 @@ interface BridgeContextType { txStatus: TxStatus; setTxStatus: Dispatch>; - setProgressStatus: () => void; + setProgressStatus: (status?: RelayerConfirmingStatus) => void; setSuccessStatus: () => void; setFailStatus: (errorCode?: string) => void; @@ -91,10 +92,24 @@ const BridgeProvider: FC = ({ const [txStatus, setTxStatus] = useState(null); - const setProgressStatus = useCallback(() => { + const setProgressStatus = useCallback((status?: RelayerConfirmingStatus) => { + const title = selectMap( + status, + new Map([ + ["EthereumConfirming", <>Confirming on Ethereum], + [ + "CennznetConfirming", + <> + Confirming on CENNZnet + , + ], + ]), + "Transaction In Progress" + ); + setTxStatus({ status: "in-progress", - title: "Transaction In Progress", + title, message: (
Please sign the transaction when prompted and wait until it's @@ -137,7 +152,7 @@ const BridgeProvider: FC = ({ You successfully withdrew{" "}
 							
-								{trValue} {trSymbol}
+								{trValue} {trSymbol}
 							
 						
{" "} from CENNZnet. @@ -151,7 +166,7 @@ const BridgeProvider: FC = ({ You successfully deposited{" "}
 							
-								{trValue} {trSymbol}
+								{trValue} {trSymbol}
 							
 						
{" "} to CENNZnet. diff --git a/types/index.d.ts b/types/index.d.ts index 8a561c38..d7ff86b8 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -74,6 +74,18 @@ export interface MetaMaskAccount { export interface TxStatus { status: "in-progress" | "success" | "fail"; - title: string; + title: string | ReactElement; message: string | ReactElement; } + +export type RelayerStatus = + | "Successful" + | "Failed" + | "Confirming" + | "EthereumConfirming" + | "CennznetConfirming"; + +export type RelayerConfirmingStatus = Extract< + RelayerStatus, + "EthereumConfirming" | "CennznetConfirming" +>; diff --git a/utils/ensureRelayerDepositDone.ts b/utils/ensureRelayerDepositDone.ts index afce4d8c..86595dbd 100644 --- a/utils/ensureRelayerDepositDone.ts +++ b/utils/ensureRelayerDepositDone.ts @@ -1,16 +1,19 @@ import { fetchDepositRelayerStatus, waitUntil } from "@/utils"; +import { RelayerStatus, RelayerConfirmingStatus } from "@/types"; -type RelayerStatusReturn = Awaited< - ReturnType ->; type TimoutReturn = Awaited>; // TODO: Needs test export default async function ensureRelayerDepositDone( txHash: string, - timeout: number = 60000 -): Promise { - const status = await waitUntilDepositDone(txHash, timeout); + timeout: number = 60000, + confirmingCallback?: (status: RelayerConfirmingStatus) => void +): Promise { + const status = await waitUntilDepositDone( + txHash, + timeout, + confirmingCallback + ); if (status === "timeout") throw { code: "RELAYER_TIMEOUT" }; if (status === "Failed") throw { code: "RELAYER_STATUS_FAILED" }; @@ -20,16 +23,22 @@ export default async function ensureRelayerDepositDone( export async function waitUntilDepositDone( txHash: string, - timeout: number = 60000 -): Promise { + timeout: number = 60000, + confirmingCallback?: (status: RelayerConfirmingStatus) => void +): Promise { let timedOut = false; const pollDepositRelayerStatus = () => { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const intervalId = setInterval(() => { fetchDepositRelayerStatus(txHash) .then((status) => { - if (!timedOut && status === "Confirming") return; + if ( + !timedOut && + (status === "EthereumConfirming" || + status === "CennznetConfirming") + ) + return confirmingCallback?.(status); clearInterval(intervalId); resolve(status); }) diff --git a/utils/fetchDepositRelayerStatus.ts b/utils/fetchDepositRelayerStatus.ts index b3002218..936895dc 100644 --- a/utils/fetchDepositRelayerStatus.ts +++ b/utils/fetchDepositRelayerStatus.ts @@ -1,20 +1,16 @@ import { BRIDGE_RELAYER_URL } from "@/constants"; - -type RelayerStatus = "Successful" | "Failed" | "Confirming"; +import { RelayerStatus } from "@/types"; // TODO: Needs test export default async function fetchDepositRelayerStatus( txHash: string ): Promise { - const response = await fetch( + const relayerResponse = await fetch( `${BRIDGE_RELAYER_URL}/transactions/${txHash}` ).then((response) => { if (response.status !== 200) throw { code: `RELAYER_${response.status}` }; return response.json(); }); - if (response.status === "Successful" || response.status === "Failed") - return response.status; - - return "Confirming"; + return relayerResponse.status; } diff --git a/utils/index.ts b/utils/index.ts index 7bf1efc5..8a5bec12 100644 --- a/utils/index.ts +++ b/utils/index.ts @@ -37,3 +37,4 @@ export { default as ensureRelayerDepositDone } from "@/utils/ensureRelayerDeposi export { default as sendWithdrawEthereumRequest } from "@/utils/sendWithdrawEthereumRequest"; export { default as trackPageView } from "@/utils/trackPageView"; export { default as getSellAssetExtrinsic } from "@/utils/getSellAssetExtrinsic"; +export { default as selectMap } from "@/utils/selectMap"; diff --git a/utils/selectMap.ts b/utils/selectMap.ts new file mode 100644 index 00000000..756161d4 --- /dev/null +++ b/utils/selectMap.ts @@ -0,0 +1,16 @@ +/** + * A utility that return value by key from a map + * + * @param {K} key + * @param {Map} map + * @param {V} defaultValue + * @return {V} + */ +export default function selectMap( + key: K, + map: Map, + defaultValue?: V +): V { + if (!map.has(key)) return defaultValue; + return map.get(key); +}