Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4c18696
Refactor multichain integration by removing unused IStargateAbi impor…
midas-myth Dec 12, 2025
078283a
Remove unused Typechain files for IStargate, including common types, …
midas-myth Dec 12, 2025
fb899ad
Enhance error handling and refactor event subscription methods across…
midas-myth Dec 13, 2025
f83c75a
Refactor transaction encoding in synthetic markets and multichain dep…
midas-myth Dec 13, 2025
dac148e
Remove unused Typechain files and factories to streamline the codebas…
midas-myth Dec 13, 2025
753c55a
Refactor address handling across multiple components to utilize and …
midas-myth Dec 13, 2025
2407fe9
Refactor multichain and transaction handling by introducing ISigner f…
midas-myth Dec 13, 2025
65031fc
Merge branch 'roll-out-rpc-fallbacks' of github.com:gmx-io/gmx-interf…
midas-myth Dec 24, 2025
f60a8aa
Remove unused typechain types and related factory files from the proj…
midas-myth Dec 24, 2025
b77d1d8
Refactor address validation to use non-strict mode across multiple co…
midas-myth Dec 26, 2025
e5e17eb
Enhance RPC transport configuration by introducing type safety for pr…
midas-myth Dec 26, 2025
87c501f
Refactor error handling in trade history utilities by introducing a n…
midas-myth Dec 26, 2025
4232eb7
Merge branch 'release' of github.com:gmx-io/gmx-interface into remove…
midas-myth Jan 7, 2026
e8c8e26
Update subsquid URLs in indexers configuration to use production endp…
midas-myth Jan 7, 2026
17ed4af
Merge branch 'release' of github.com:gmx-io/gmx-interface into remove…
midas-myth Jan 7, 2026
2c7170d
Merge branch 'release' of github.com:gmx-io/gmx-interface into remove…
midas-myth Jan 8, 2026
7880857
Refactor multichain event handling and websocket context. Simplified …
midas-myth Jan 8, 2026
e3b357e
Remove WebsocketContextProvider and related references. Update event …
midas-myth Jan 9, 2026
2ee3104
Refactor block timestamp and block number retrieval in simulateExecut…
midas-myth Jan 9, 2026
913e803
Refactor error handling in simulateExecuteTxn and simulation functions
midas-myth Jan 14, 2026
430cb61
Merge branch 'release' of github.com:gmx-io/gmx-interface into remove…
midas-myth Jan 14, 2026
5064962
Enhance error handling in parseError and related utilities; add tests…
midas-myth Jan 15, 2026
91678db
Refactor useMultichainEvents to utilize getByKey for token ID retriev…
midas-myth Jan 15, 2026
4847e92
Merge branch 'release' of github.com:gmx-io/gmx-interface into remove…
midas-myth Jan 15, 2026
580cbc7
Merge branch 'release' of github.com:gmx-io/gmx-interface into remove…
midas-myth Jan 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"local-rules/no-logical-bigint": "off",

"es-x/no-bigint": "off",
"es-x/no-optional-catch-binding": "off",
"es-x/no-optional-chaining": "off",
"es-x/no-import-meta": "off",
"es-x/no-dynamic-import": "off",
Expand Down
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
.pnp.js
.vscode

# typechain-types
/src/typechain-types

# lingui
/src/locales/**/*.js
Expand Down
2 changes: 0 additions & 2 deletions sdk/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ yarn-error.log*
# For publish
.npmrc

typechain-types

package-lock.json

.yarn/*
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/types/tradeHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export type PositionTradeAction = {
orderKey: string;
isLong: boolean;
reason?: string;
reasonBytes?: string | Uint8Array;
reasonBytes?: string;
shouldUnwrapNativeToken: boolean;
totalImpactUsd?: bigint;
liquidationFeeAmount?: bigint;
Expand Down Expand Up @@ -78,7 +78,7 @@ export type SwapTradeAction = {
orderType: OrderType;
orderKey: string;
reason?: string;
reasonBytes?: string | Uint8Array;
reasonBytes?: string;
twapParams:
| {
twapGroupId: string;
Expand Down
73 changes: 72 additions & 1 deletion sdk/src/utils/__tests__/parseError.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import {
CallExecutionError,
ContractFunctionExecutionError,
ContractFunctionRevertedError,
InvalidInputRpcError,
RpcRequestError,
InsufficientFundsError,
} from "viem";
import { describe, expect, it } from "vitest";

import { parseError, ErrorLike } from "utils/errors";
import { ErrorLike, parseError } from "utils/errors";
import { TxErrorType } from "utils/errors/transactionsErrors";

describe("parseError", () => {
Expand Down Expand Up @@ -337,4 +345,67 @@ describe("parseError", () => {
);
});
});

describe("viem errors", () => {
it("should handle viem ContractFunctionExecutionError", () => {
const error = new ContractFunctionExecutionError(
new ContractFunctionRevertedError({
abi: [],
functionName: "test_function",
data: "0x4e48dcda",
message: "test message",
}),
{
abi: [],
functionName: "test_function",
}
);

const result = parseError(error);

expect(result).toEqual(
expect.objectContaining({
contractError: "EndOfOracleSimulation",
})
);
});

it("should handle viem InsufficientFundsError", () => {
const error = new ContractFunctionExecutionError(
new CallExecutionError(
new InsufficientFundsError({
cause: new InvalidInputRpcError(
new InvalidInputRpcError(
new RpcRequestError({
error: {
message:
"err: insufficient funds for gas * price + value: address 0x6f9f3106F0209dc560A53C6808f8BF32E38468C3 have 4174472651641805 want 10000000000000000000 (supplied gas 1100000000)",
code: -32000,
},
body: {},
url: "https://example.com",
})
)
),
}),
{}
),
{
abi: [],
functionName: "test_function",
}
);

const result = parseError(error);

expect(result).toEqual(
expect.objectContaining({
txErrorType: TxErrorType.NotEnoughFunds,
isUserError: true,
isUserRejectedError: false,
errorGroup: "Txn Error: NOT_ENOUGH_FUNDS",
})
);
});
});
});
122 changes: 95 additions & 27 deletions sdk/src/utils/errors/parseError.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import cryptoJs from "crypto-js";
import { Abi, decodeErrorResult } from "viem";
import {
Abi,
AbiParameterToPrimitiveType,
ContractErrorName,
decodeErrorResult,
ExtractAbiItem,
BaseError as ViemBaseError,
} from "viem";

import { abis } from "abis";

Expand All @@ -12,6 +19,31 @@ import {
getIsUserRejectedError,
} from "./transactionsErrors";

export function extractErrorDataFromViemError(error: any): string | undefined {
if (!("walk" in error && typeof error.walk === "function")) {
return undefined;
}

let data: string | undefined;
(error as ViemBaseError).walk((e: any) => {
if (typeof e?.data === "string") {
data = e.data;
return true;
}
if (typeof e?.data?.data === "string") {
data = e.data.data;
return true;
}
if (typeof e?.raw === "string") {
data = e.raw;
return true;
}
return false;
});

return data;
}

export type OrderErrorContext =
| "simulation"
| "gasLimit"
Expand Down Expand Up @@ -150,17 +182,25 @@ export function parseError(error: ErrorLike | string | undefined, errorDepth = 0
//
}

if (errorMessage) {
const errorData = extractDataFromError(errorMessage) ?? extractDataFromError((error as any)?.message);
if (!contractError) {
const errorData =
(error && typeof error === "object" ? extractErrorDataFromViemError(error) : undefined) ??
extractDataFromError(errorMessage) ??
extractDataFromError((error as any)?.message);

if (errorData) {
const parsedError = decodeErrorResult({
abi: abis.CustomErrors as Abi,
data: errorData,
});

if (parsedError) {
contractError = parsedError.errorName;
contractErrorArgs = parsedError.args;
try {
const parsedError = decodeErrorResult({
abi: abis.CustomErrors as Abi,
data: errorData,
});

if (parsedError) {
contractError = parsedError.errorName;
contractErrorArgs = parsedError.args;
}
} catch {
//
}
}
}
Expand Down Expand Up @@ -244,28 +284,56 @@ export function isCustomError(error: Error | undefined): error is CustomError {
return (error as CustomError)?.isGmxCustomError === true;
}

export function getCustomError(error: Error): CustomError | Error {
const data = (error as any)?.info?.error?.data ?? (error as any)?.data;

let prettyErrorName = error.name;
let prettyErrorMessage = error.message;
let prettyErrorArgs: any = undefined;
export type ParsedCustomError = {
name: string;
args?: {
[key in ExtractAbiItem<
typeof abis.CustomErrors,
ContractErrorName<typeof abis.CustomErrors>
>["inputs"][number]["name"]]: AbiParameterToPrimitiveType<
Extract<
ExtractAbiItem<typeof abis.CustomErrors, ContractErrorName<typeof abis.CustomErrors>>["inputs"][number],
{
name: key;
}
>,
"inputs"
>;
};
};

export function tryDecodeCustomError(reasonBytes: string): ParsedCustomError | undefined {
try {
const parsedError = decodeErrorResult({
const decoded = decodeErrorResult({
abi: abis.CustomErrors,
data: data,
data: reasonBytes,
});

prettyErrorArgs = parsedError.args;
// Convert args array to key-value dictionary for backward compatibility
if (
decoded.args &&
Array.isArray(decoded.args) &&
decoded.abiItem &&
"inputs" in decoded.abiItem &&
decoded.abiItem.inputs
) {
const argsDict: Record<string, any> = {};
for (const [index, input] of decoded.abiItem.inputs.entries()) {
argsDict[input.name] = decoded.args[index];
}
return { name: decoded.errorName, args: argsDict as any };
}

prettyErrorName = parsedError.errorName;
prettyErrorMessage = JSON.stringify(parsedError, null, 2);
} catch (decodeError) {
return error;
return { name: decoded.errorName, args: undefined };
} catch {
return undefined;
}
}

const prettyError = new CustomError({ name: prettyErrorName, message: prettyErrorMessage, args: prettyErrorArgs });

return prettyError;
export function decodeErrorFromViemError(error: any): ParsedCustomError | undefined {
const data = extractErrorDataFromViemError(error);
if (!data) {
return undefined;
}
return tryDecodeCustomError(data);
}
2 changes: 0 additions & 2 deletions src/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import { ThemeProvider } from "context/ThemeContext/ThemeContext";
import { TokenPermitsContextProvider } from "context/TokenPermitsContext/TokenPermitsContextProvider";
import { TokensBalancesContextProvider } from "context/TokensBalancesContext/TokensBalancesContextProvider";
import { TokensFavoritesContextProvider } from "context/TokensFavoritesContext/TokensFavoritesContextProvider";
import { WebsocketContextProvider } from "context/WebsocketContext/WebsocketContextProvider";
import { useChainId } from "lib/chains";
import { defaultLocale, dynamicActivate } from "lib/i18n";
import { RainbowKitProviderWrapper } from "lib/wallets/WalletProvider";
Expand Down Expand Up @@ -72,7 +71,6 @@ function App() {
app = <SubaccountContextProvider>{app}</SubaccountContextProvider>;
app = <TokenPermitsContextProvider>{app}</TokenPermitsContextProvider>;
app = <TokensBalancesContextProvider>{app}</TokensBalancesContextProvider>;
app = <WebsocketContextProvider>{app}</WebsocketContextProvider>;
app = <SEO>{app}</SEO>;
app = <RainbowKitProviderWrapper>{app}</RainbowKitProviderWrapper>;
app = <I18nProvider i18n={i18n as any}>{app}</I18nProvider>;
Expand Down
7 changes: 3 additions & 4 deletions src/App/AppRoutes.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { ethers } from "ethers";
import { useCallback, useEffect, useState } from "react";
import { useHistory, useLocation } from "react-router-dom";
import { cssTransition, ToastContainer } from "react-toastify";
import { Hash } from "viem";
import { Hash, zeroHash } from "viem";

import { CONTRACTS_CHAIN_IDS, ContractsChainId } from "config/chains";
import { REFERRAL_CODE_KEY } from "config/localStorage";
Expand Down Expand Up @@ -71,7 +70,7 @@ export function AppRoutes() {

if (referralCode && referralCode.length <= 20) {
const encodedReferralCode = encodeReferralCode(referralCode);
if (encodedReferralCode !== ethers.ZeroHash) {
if (encodedReferralCode !== zeroHash) {
localStorage.setItem(REFERRAL_CODE_KEY, encodedReferralCode);
const queryParams = new URLSearchParams(location.search);
if (queryParams.has(REFERRAL_CODE_QUERY_PARAM)) {
Expand All @@ -96,7 +95,7 @@ export function AppRoutes() {
const localStorageCode = window.localStorage.getItem(REFERRAL_CODE_KEY);
const baseUrl = getAppBaseUrl();
let appRedirectUrl = baseUrl;
if (localStorageCode && localStorageCode.length > 0 && localStorageCode !== ethers.ZeroHash) {
if (localStorageCode && localStorageCode.length > 0 && localStorageCode !== zeroHash) {
const decodedRefCode = decodeReferralCode(localStorageCode as Hash);
if (decodedRefCode) {
appRedirectUrl = `${appRedirectUrl}?ref=${decodedRefCode}`;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Trans, t } from "@lingui/macro";
import cx from "classnames";
import { ZeroAddress, ethers } from "ethers";
import { ethers } from "ethers";
import { useCallback, useEffect, useMemo, useState } from "react";
import { zeroAddress } from "viem";

import { ARBITRUM, ContractsChainId } from "config/chains";
import { BASIS_POINTS_DIVISOR_BIGINT } from "config/factors";
Expand Down Expand Up @@ -121,7 +122,7 @@ export function StakeModal(props: {
}, [isVisible, setStakeValue, setUnstakeValue]);

const needApproval =
stakeFarmAddress !== ZeroAddress &&
stakeFarmAddress !== zeroAddress &&
tokenAllowance !== undefined &&
stakeAmount !== undefined &&
stakeAmount > tokenAllowance;
Expand Down
7 changes: 2 additions & 5 deletions src/components/GmxAccountModal/DepositView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import { Hex, decodeErrorResult, zeroAddress } from "viem";
import { useAccount, useChains } from "wagmi";

import {
AnyChainId,
AVALANCHE,
AnyChainId,
SettlementChainId,
SourceChainId,
getChainName,
Expand All @@ -31,8 +31,8 @@ import {
useGmxAccountDepositViewTokenAddress,
useGmxAccountDepositViewTokenInputValue,
useGmxAccountModalOpen,
useGmxAccountSelector,
useGmxAccountSelectedTransferGuid,
useGmxAccountSelector,
useGmxAccountSettlementChainId,
} from "context/GmxAccountContext/hooks";
import { selectGmxAccountDepositViewTokenInputAmount } from "context/GmxAccountContext/selectors";
Expand Down Expand Up @@ -66,7 +66,6 @@ import {
} from "lib/metrics";
import { USD_DECIMALS, adjustForDecimals, formatAmountFree, formatUsd } from "lib/numbers";
import { EMPTY_ARRAY, EMPTY_OBJECT, getByKey } from "lib/objects";
import { useJsonRpcProvider } from "lib/rpc";
import { TxnCallback, TxnEventName, WalletTxnCtx } from "lib/transactions";
import { useHasOutdatedUi } from "lib/useHasOutdatedUi";
import { useIsNonEoaAccountOnAnyChain } from "lib/wallets/useAccountType";
Expand Down Expand Up @@ -124,7 +123,6 @@ export const DepositView = () => {
const [, setSettlementChainId] = useGmxAccountSettlementChainId();
const [depositViewChain, setDepositViewChain] = useGmxAccountDepositViewChain();
const walletSigner = useEthersSigner({ chainId: srcChainId });
const { provider: sourceChainProvider } = useJsonRpcProvider(depositViewChain);

const [isVisibleOrView, setIsVisibleOrView] = useGmxAccountModalOpen();
const [, setSelectedTransferGuid] = useGmxAccountSelectedTransferGuid();
Expand Down Expand Up @@ -349,7 +347,6 @@ export const DepositView = () => {
const quoteOft = useQuoteOft({
sendParams: sendParamsWithoutSlippage,
fromStargateAddress: selectedTokenSourceChainTokenId?.stargate,
fromChainProvider: sourceChainProvider,
fromChainId: depositViewChain,
toChainId: settlementChainId,
});
Expand Down
1 change: 0 additions & 1 deletion src/components/GmxAccountModal/WithdrawalView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,6 @@ export const WithdrawalView = () => {
const quoteOft = useQuoteOft({
sendParams: sendParamsWithoutSlippage,
fromStargateAddress: selectedTokenSettlementChainTokenId?.stargate,
fromChainProvider: provider,
fromChainId: chainId,
toChainId: withdrawalViewChain,
});
Expand Down
Loading