Skip to content

Commit

Permalink
feat: add tx error popup
Browse files Browse the repository at this point in the history
  • Loading branch information
naturexie committed Jan 14, 2025
1 parent 24a274f commit 1a737ca
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 42 deletions.
10 changes: 6 additions & 4 deletions screens/Trading/components/ClosePositionMobile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useAppSelector } from "../../../redux/hooks";
import { Wrapper } from "../../../components/Modal/style";
import { DEFAULT_POSITION } from "../../../utils/config";
import { CloseIcon } from "../../../components/Modal/svg";
import { RefLogoIcon, RightArrow, MaxPositionIcon } from "./TradingIcon";
import { RightArrow, MaxPositionIcon } from "./TradingIcon";
import { toInternationalCurrencySystem_number, toDecimal } from "../../../utils/uiNumber";
import { closePosition } from "../../../store/marginActions/closePosition";
import { useEstimateSwap } from "../../../hooks/useEstimateSwap";
Expand All @@ -22,15 +22,14 @@ import {
YellowSolidSubmitButton as YellowSolidButton,
RedSolidSubmitButton as RedSolidButton,
} from "../../../components/Modal/button";
import { showPositionClose } from "../../../components/HashResultModal";
import { beautifyPrice } from "../../../utils/beautyNumber";
import { findPathReserve } from "../../../api/get-swap-path";
import { getAssets, getAssetsMEME } from "../../../redux/assetsSelectors";
import { useMarginAccount } from "../../../hooks/useMarginAccount";
import { IClosePositionMobileProps } from "../comInterface";
import { getMarginConfig, getMarginConfigMEME } from "../../../redux/marginConfigSelectors";
import { handleTransactionHash } from "../../../services/transaction";
import DataSource from "../../../data/datasource";
import { showPositionFailure } from "../../../components/HashResultModal";
import { useRegisterTokenType } from "../../../hooks/useRegisterTokenType";

export const ModalContext = createContext(null) as any;
Expand Down Expand Up @@ -204,7 +203,10 @@ const ClosePositionMobile: React.FC<IClosePositionMobileProps> = ({
await handleTransactionHash(transactionHashes);
}
} catch (error) {
console.error("Failed to close position:", error);
showPositionFailure({
title: "Transactions error",
errorMessage: error instanceof Error ? error.message : JSON.stringify(error),
});
} finally {
setIsDisabled(false);
}
Expand Down
41 changes: 8 additions & 33 deletions screens/Trading/components/ConfirmMobile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@ import {
} from "../../../components/Modal/button";
import { shrinkToken, expandToken } from "../../../store";
import { beautifyPrice } from "../../../utils/beautyNumber";
import { getAccountId } from "../../../redux/accountSelectors";
import { handleTransactionHash } from "../../../services/transaction";
import { showPositionFailure } from "../../../components/HashResultModal";
import { getBurrow } from "../../../utils";
import { getSymbolById } from "../../../transformers/nearSymbolTrans";
import { IConfirmMobileProps } from "../comInterface";
import { useRegisterTokenType } from "../../../hooks/useRegisterTokenType";
Expand All @@ -31,20 +29,6 @@ const ConfirmMobile: React.FC<IConfirmMobileProps | any> = ({
action,
confirmInfo,
}) => {
const [burrowData, setBurrowData] = useState<{
selector?: {
wallet: () => Promise<{ id: string }>;
};
} | null>(null);

useEffect(() => {
const initBurrow = async () => {
const data: any = await getBurrow();
setBurrowData(data);
};
initBurrow();
}, []);
const accountId = useAppSelector(getAccountId);
const theme = useTheme();
const [selectedCollateralType, setSelectedCollateralType] = useState(DEFAULT_POSITION);
const { ReduxcategoryAssets1 } = useAppSelector((state) => state.category);
Expand Down Expand Up @@ -193,26 +177,17 @@ const ConfirmMobile: React.FC<IConfirmMobileProps | any> = ({
: minAmountOutForPopUp / confirmInfo.tokenInAmount,
}),
);

const wallet = await burrowData?.selector?.wallet();
if (wallet?.id && ["my-near-wallet", "mintbase-wallet", "bitte-wallet"].includes(wallet.id)) {
await openPosition(openPositionParams);
return;
}

const res: any = await openPosition(openPositionParams);
if (!res || !Array.isArray(res)) {
throw new Error("Invalid response from openPosition");
if (res) {
const transactionHashes = res.map((item) => {
if (!item?.transaction?.hash) {
throw new Error("Invalid transaction hash");
}
return item.transaction.hash;
});
await handleTransactionHash(transactionHashes);
}
const transactionHashes = res.map((item) => {
if (!item?.transaction?.hash) {
throw new Error("Invalid transaction hash");
}
return item.transaction.hash;
});
await handleTransactionHash(transactionHashes);
} catch (error) {
console.error("Open position error:", error);
showPositionFailure({
title: "Transactions error",
errorMessage: error instanceof Error ? error.message : JSON.stringify(error),
Expand Down
18 changes: 13 additions & 5 deletions services/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ import {
showPositionResult,
showPositionClose,
showChangeCollateralPosition,
showPositionFailure,
} from "../components/HashResultModal";
import { store } from "../redux/store";
import DataSource from "../data/datasource";
import { getErrorMessage } from "../utils/transactionUtils";

interface ITransactionResult {
txHash: string;
result: any;
isOpenPosition?: boolean;
isCloseMTPosition?: boolean;
isDecreaseCollateral?: boolean;
isIncreaseCollateral?: boolean;
action?: Record<string, string>;
error?: string | null | undefined;
}
export const handleTransactionHash = async (
transactionHashes: string | string[] | undefined,
Expand Down Expand Up @@ -48,22 +50,22 @@ export const handleTransactionHash = async (
: JSON.parse(parsed_Args.msg)?.MarginExecute?.actions?.[0];
return {
txHash,
result,
isOpenPosition: Reflect.has(action, "OpenPosition"),
isCloseMTPosition: Reflect.has(action, "CloseMTPosition"),
isDecreaseCollateral: Reflect.has(action, "DecreaseCollateral"),
isIncreaseCollateral: Reflect.has(action, "IncreaseCollateral"),
action,
error: getErrorMessage(result?.receipts_outcome),
};
}
return {
txHash,
result,
isOpenPosition: false,
isCloseMTPosition: false,
isDecreaseCollateral: false,
isIncreaseCollateral: false,
action: undefined,
error: undefined,
};
}),
);
Expand All @@ -73,8 +75,9 @@ export const handleTransactionHash = async (
const targetCollateralTx = results.find(
(item) => item.isDecreaseCollateral || item.isIncreaseCollateral,
);
const hasErrorTx = results.find((item) => item.error);
// Reporting transactions
if (targetPositionTx) {
if (targetPositionTx && !hasErrorTx) {
const currentState = store.getState();
await DataSource.shared.postMarginTradingPosition({
addr: currentState?.account?.accountId,
Expand All @@ -83,7 +86,12 @@ export const handleTransactionHash = async (
});
}
// Show transactions pop
if (targetPositionTx?.isCloseMTPosition) {
if (hasErrorTx) {
showPositionFailure({
title: "Transactions error",
errorMessage: hasErrorTx.error || "Unknown error",
});
} else if (targetPositionTx?.isCloseMTPosition) {
// close position
const marginPopType = localStorage.getItem("marginPopType") as "Long" | "Short" | undefined;
showPositionClose({ type: marginPopType || "Long" });
Expand Down
90 changes: 90 additions & 0 deletions utils/transactionUtils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
export const ERROR_PATTERN = {
slippageErrorPattern: /ERR_MIN_AMOUNT|slippage error/i,
invaliParamsErrorPattern: /invalid params/i,
ratesExpiredErrorPattern: /Rates expired/i,
integerOverflowErrorPattern: /Integer overflow/i,
ShareSupplyOverflowErrorPattern: /shares_total_supply overflow/i,
tokenFrozenErrorPattern: /token frozen/i,
poolBalanceLessPattern: /pool reserved token balance less than MIN_RESERVE/i,
nethErrorPattern: /Smart contract panicked: explicit guest panic/i,
};
export enum TRANSACTION_ERROR_TYPE {
SLIPPAGE_VIOLATION = "Slippage Violation",
INVALID_PARAMS = "Invalid Params",
RATES_EXPIRED = "Rates Expired",
INTEGEROVERFLOW = "Integer Overflow",
SHARESUPPLYOVERFLOW = "Share Supply Overflow",
TOKEN_FROZEN = "Token Frozen",
POOL_BALANCE_LESS = "Pool Balance Less Than MIN_RESERVE",
NETH_ERROR = "Smart contract panicked",
}

export const getErrorMessage = (receipts_outcome: any) => {
const isSlippageError = receipts_outcome.some((outcome: any) => {
return ERROR_PATTERN.slippageErrorPattern.test(
outcome?.outcome?.status?.Failure?.ActionError?.kind?.FunctionCallError?.ExecutionError,
);
});

const isInvalidAmountError = receipts_outcome.some((outcome: any) => {
return ERROR_PATTERN.invaliParamsErrorPattern.test(
outcome?.outcome?.status?.Failure?.ActionError?.kind?.FunctionCallError?.ExecutionError,
);
});

const isRatesExpiredError = receipts_outcome.some((outcome: any) => {
return ERROR_PATTERN.ratesExpiredErrorPattern.test(
outcome?.outcome?.status?.Failure?.ActionError?.kind?.FunctionCallError?.ExecutionError,
);
});

const isIntegerOverFlowError = receipts_outcome.some((outcome: any) => {
return ERROR_PATTERN.integerOverflowErrorPattern.test(
outcome?.outcome?.status?.Failure?.ActionError?.kind?.FunctionCallError?.ExecutionError,
);
});

const isShareSupplyOerflowError = receipts_outcome.some((outcome: any) => {
return ERROR_PATTERN.ShareSupplyOverflowErrorPattern.test(
outcome?.outcome?.status?.Failure?.ActionError?.kind?.FunctionCallError?.ExecutionError,
);
});

const isTokenFrozen = receipts_outcome.some((outcome: any) => {
return ERROR_PATTERN.tokenFrozenErrorPattern.test(
outcome?.outcome?.status?.Failure?.ActionError?.kind?.FunctionCallError?.ExecutionError,
);
});

const isPoolBalanceLess = receipts_outcome.some((outcome: any) => {
return ERROR_PATTERN.poolBalanceLessPattern.test(
outcome?.outcome?.status?.Failure?.ActionError?.kind?.FunctionCallError?.ExecutionError,
);
});

const isNETHErrpr = receipts_outcome.some((outcome: any) => {
return ERROR_PATTERN.nethErrorPattern.test(
outcome?.outcome?.status?.Failure?.ActionError?.kind?.FunctionCallError?.ExecutionError,
);
});

if (isSlippageError) {
return TRANSACTION_ERROR_TYPE.SLIPPAGE_VIOLATION;
} else if (isInvalidAmountError) {
return TRANSACTION_ERROR_TYPE.INVALID_PARAMS;
} else if (isRatesExpiredError) {
return TRANSACTION_ERROR_TYPE.RATES_EXPIRED;
} else if (isIntegerOverFlowError) {
return TRANSACTION_ERROR_TYPE.INTEGEROVERFLOW;
} else if (isShareSupplyOerflowError) {
return TRANSACTION_ERROR_TYPE.SHARESUPPLYOVERFLOW;
} else if (isTokenFrozen) {
return TRANSACTION_ERROR_TYPE.TOKEN_FROZEN;
} else if (isPoolBalanceLess) {
return TRANSACTION_ERROR_TYPE.POOL_BALANCE_LESS;
} else if (isNETHErrpr) {
return TRANSACTION_ERROR_TYPE.NETH_ERROR;
} else {
return null;
}
};

0 comments on commit 1a737ca

Please sign in to comment.