Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing exhaustive-deps lint errors for hooks #2901

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 5 additions & 4 deletions wormhole-connect/.eslintrc.strict.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
"prettier"
],
"rules": {
"comma-dangle": ["error", "always-multiline"],
"semi": ["error", "always"],
"@typescript-eslint/no-explicit-any": ["error", { "ignoreRestArgs": true }],
"@typescript-eslint/explicit-module-boundary-types": ["error"],
"@typescript-eslint/no-explicit-any": ["error", { "ignoreRestArgs": true }],
"@typescript-eslint/no-non-null-assertion": ["error"],
"@typescript-eslint/no-unused-vars": ["warn", { "args": "none" }],
"comma-dangle": ["error", "always-multiline"],
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["warn", { "args": "none" }]
"react-hooks/exhaustive-deps": ["error"],
"semi": ["error", "always"]
}
}
2 changes: 1 addition & 1 deletion wormhole-connect/src/hooks/useAvailableWallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const useAvailableWallets = (props: Props): ReturnProps => {
});
}
} catch (e) {
console.error(`Error loading wallet options for ${props.chain}: ${e}`);
console.error(`Error loading wallet options for ${chain}: ${e}`);
setWalletOptionsResult({ state: 'error', error: FAILED_TO_LOAD_ERR });
}
})();
Expand Down
1 change: 1 addition & 0 deletions wormhole-connect/src/hooks/useComputeFees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ const useComputeFees = (props: Props): returnProps => {
sourceChain,
destChain,
tokenPrices,
getEstimatedTime,
]);

return {
Expand Down
7 changes: 5 additions & 2 deletions wormhole-connect/src/hooks/useComputeSourceTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,11 @@ const useComputeSourceTokens = (props: Props): ReturnProps => {
return () => {
active = false;
};
// IMPORTANT: do not include token in dependency array
}, [route, sourceChain, destToken, dispatch]);
// IMPORTANT: do not include sourceToken in dependency array,
// because it's not needed and it will also cause an extra round unnecessary updates when the side-affect automatically sets the sourceToken.
// Please See dispatch(setToken(...)) calls above.
// eslint-disable-next-line react-hooks/exhaustive-deps
emreboga marked this conversation as resolved.
Show resolved Hide resolved
}, [destChain, destToken, dispatch, route, sourceChain]);

return { isFetching };
};
Expand Down
2 changes: 1 addition & 1 deletion wormhole-connect/src/hooks/useFetchRedeemTx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const useFetchRedeemTx = (): void => {
return () => {
isActive = false;
};
}, [receipt]);
}, [dispatch, receipt]);
};

export default useFetchRedeemTx;
2 changes: 1 addition & 1 deletion wormhole-connect/src/hooks/useGetTokenBalances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ const useGetTokenBalances = (
return () => {
isActive = false;
};
}, [cachedBalances, walletAddress, chain, tokens]);
}, [cachedBalances, chain, dispatch, tokens, walletAddress]);

return { isFetching, balances };
};
Expand Down
14 changes: 12 additions & 2 deletions wormhole-connect/src/hooks/useRoutesQuotesBulk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,11 @@ const useRoutesQuotesBulk = (routes: string[], params: Params): HookReturn => {
clearTimeout(refreshTimeout);
}
};
// Important: We should not include routes property in deps. See routes.join() below.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
routes.join(),
// eslint-disable-next-line react-hooks/exhaustive-deps
emreboga marked this conversation as resolved.
Show resolved Hide resolved
routes.join(), // .join() is necessary to prevent unncessary updates when routes array's ref changed but its content did not
params.sourceChain,
params.sourceToken,
params.destChain,
Expand All @@ -110,6 +113,8 @@ const useRoutesQuotesBulk = (routes: string[], params: Params): HookReturn => {
params.nativeGas,
nonce,
isTransactionInProgress,
params,
refreshTimeout,
]);

const quotesMap = useMemo(
Expand All @@ -118,7 +123,12 @@ const useRoutesQuotesBulk = (routes: string[], params: Params): HookReturn => {
acc[route] = quotes[index];
return acc;
}, {} as Record<string, QuoteResult | undefined>),
[routes.join(), quotes],
[
// eslint-disable-next-line react-hooks/exhaustive-deps
routes.join(), // .join() is necessary to prevent unncessary updates when routes array's ref changed but its content did not
routes,
quotes,
],
);

// Filter out quotes that would result in a large instant loss
Expand Down
12 changes: 9 additions & 3 deletions wormhole-connect/src/hooks/useSortedRoutesWithQuotes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const useSortedRoutesWithQuotes = (): HookReturn => {
destToken,
nativeGas: toNativeToken,
}),
[parseFloat(amount), fromChain, token, toChain, destToken, toNativeToken],
[amount, fromChain, token, toChain, destToken, toNativeToken],
);

const { quotesMap, isFetching } = useRoutesQuotesBulk(
Expand Down Expand Up @@ -122,7 +122,7 @@ export const useSortedRoutesWithQuotes = (): HookReturn => {
// Returning BigInt results in TypeError
return Number(destAmountB - destAmountA);
});
}, [routesWithQuotes]);
}, [preferredRouteName, routesWithQuotes]);

const sortedRoutes = useMemo(
() => sortedRoutesWithQuotes.map((r) => r.route),
Expand All @@ -137,6 +137,12 @@ export const useSortedRoutesWithQuotes = (): HookReturn => {
quotesMap,
isFetchingQuotes: isFetching,
}),
[supportedRoutes, sortedRoutesWithQuotes, quotesMap, isFetching],
[
supportedRoutes,
sortedRoutes,
sortedRoutesWithQuotes,
quotesMap,
isFetching,
],
);
};
4 changes: 3 additions & 1 deletion wormhole-connect/src/hooks/useTransactionHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const useTransactionHistory = (
if (hasMoreWHScan && whScanPage !== page) {
setWHScanPage(page);
}
}, [hasMoreMayan, hasMoreWHScan, page]);
}, [hasMoreMayan, hasMoreWHScan, mayanPage, page, whScanPage]);

// Side-effect to merge transactions in time-order whenever there is new data
useEffect(() => {
Expand Down Expand Up @@ -180,6 +180,8 @@ const useTransactionHistory = (
updateMayanIndex(mayanLocalIdx);
// Append the merged transactions and exit
setTransactions((txs) => appendTxs(txs, mergedTxs));
// We only need to re-run this side-effect when either of the transaction data changes
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [whScanTxs, mayanTxs]);

return {
Expand Down
2 changes: 1 addition & 1 deletion wormhole-connect/src/hooks/useTransactionHistoryMayan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ const useTransactionHistoryMayan = (
return () => {
cancelled = true;
};
}, [page, pageSize]);
}, [address, page, pageSize, parseTransactions]);

return {
transactions,
Expand Down
177 changes: 99 additions & 78 deletions wormhole-connect/src/hooks/useTransactionHistoryWHScan.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useState } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import {
amount as sdkAmount,
chainIdToChain,
Expand Down Expand Up @@ -118,7 +118,10 @@ const useTransactionHistoryWHScan = (

const { address, page = 0, pageSize = 30 } = props;

const parseSingleTx = (tx: WormholeScanTransaction) => {
// Common parsing logic for a single transaction from WHScan API.
// IMPORTANT: Anything specific to a route, please use that route's parser:
// parseTokenBridgeTx | parseNTTTx | parseCCTPTx | parsePorticoTx
const parseSingleTx = useCallback((tx: WormholeScanTransaction) => {
const { content, data, sourceChain, targetChain } = tx;
const { tokenAmount, usdAmount } = data || {};
const { standarizedProperties } = content || {};
Expand Down Expand Up @@ -219,97 +222,115 @@ const useTransactionHistoryWHScan = (
};

return txData;
};
}, []);

// Parser for Portal Token Bridge transactions (appId === PORTAL_TOKEN_BRIDGE)
// IMPORTANT: This is where we can add any customizations specific to Token Bridge data
// that we have retrieved from WHScan API
const parseTokenBridgeTx = (tx: WormholeScanTransaction) => {
return parseSingleTx(tx);
};
const parseTokenBridgeTx = useCallback(
(tx: WormholeScanTransaction) => {
return parseSingleTx(tx);
},
[parseSingleTx],
);

// Parser for NTT transactions (appId === NATIVE_TOKEN_TRANSFER)
// IMPORTANT: This is where we can add any customizations specific to NTT data
// that we have retrieved from WHScan API
const parseNTTTx = (tx: WormholeScanTransaction) => {
return parseSingleTx(tx);
};
const parseNTTTx = useCallback(
(tx: WormholeScanTransaction) => {
return parseSingleTx(tx);
},
[parseSingleTx],
);

// Parser for CCTP transactions (appId === CCTP_WORMHOLE_INTEGRATION)
// IMPORTANT: This is where we can add any customizations specific to CCTP data
// that we have retrieved from WHScan API
const parseCCTPTx = (tx: WormholeScanTransaction) => {
return parseSingleTx(tx);
};
const parseCCTPTx = useCallback(
(tx: WormholeScanTransaction) => {
return parseSingleTx(tx);
},
[parseSingleTx],
);

// Parser for Portico transactions (appId === ETH_BRIDGE or USDT_BRIDGE)
// IMPORTANT: This is where we can add any customizations specific to Portico data
// that we have retrieved from WHScan API
const parsePorticoTx = (tx: WormholeScanTransaction) => {
const txData = parseSingleTx(tx);
if (!txData) return;

const payload = tx.content.payload
.parsedPayload as unknown as WormholeScanPorticoParsedPayload;

const {
finalTokenAddress,
flagSet,
minAmountFinish,
recipientAddress,
relayerFee,
} = payload;

const nativeTokenKey = getNativeVersionOfToken(
tx.data.symbol,
txData.fromChain,
);
const nativeToken = config.tokens[nativeTokenKey];
if (!nativeToken) return;

const startToken = flagSet.flags.shouldWrapNative
? getGasToken(txData.fromChain)
: nativeToken;

const finalTokenConfig = config.sdkConverter.findTokenConfigV1(
Wormhole.tokenId(
txData.toChain,
toNative(txData.toChain, finalTokenAddress).toString(),
),
config.tokensArr,
);
if (!finalTokenConfig) return;

const receiveAmount = BigInt(minAmountFinish) - BigInt(relayerFee);

// Override with Portico specific data
txData.tokenKey = startToken.key;
txData.tokenAddress = startToken.tokenId?.address || 'native';
txData.receivedTokenKey = flagSet.flags.shouldUnwrapNative
? getGasToken(txData.toChain).key
: finalTokenConfig.key;
txData.receiveAmount =
receiveAmount > 0
? toFixedDecimals(
sdkAmount.display(
sdkAmount.fromBaseUnits(receiveAmount, finalTokenConfig.decimals),
0,
),
DECIMALS,
)
: '';
txData.recipient = toNative(txData.toChain, recipientAddress).toString();

return txData;
};
const parsePorticoTx = useCallback(
(tx: WormholeScanTransaction) => {
const txData = parseSingleTx(tx);
if (!txData) return;

const payload = tx.content.payload
.parsedPayload as unknown as WormholeScanPorticoParsedPayload;

const {
finalTokenAddress,
flagSet,
minAmountFinish,
recipientAddress,
relayerFee,
} = payload;

const nativeTokenKey = getNativeVersionOfToken(
tx.data.symbol,
txData.fromChain,
);
const nativeToken = config.tokens[nativeTokenKey];
if (!nativeToken) return;

const startToken = flagSet.flags.shouldWrapNative
? getGasToken(txData.fromChain)
: nativeToken;

const finalTokenConfig = config.sdkConverter.findTokenConfigV1(
Wormhole.tokenId(
txData.toChain,
toNative(txData.toChain, finalTokenAddress).toString(),
),
config.tokensArr,
);
if (!finalTokenConfig) return;

const receiveAmount = BigInt(minAmountFinish) - BigInt(relayerFee);

// Override with Portico specific data
txData.tokenKey = startToken.key;
txData.tokenAddress = startToken.tokenId?.address || 'native';
txData.receivedTokenKey = flagSet.flags.shouldUnwrapNative
? getGasToken(txData.toChain).key
: finalTokenConfig.key;
txData.receiveAmount =
receiveAmount > 0
? toFixedDecimals(
sdkAmount.display(
sdkAmount.fromBaseUnits(
receiveAmount,
finalTokenConfig.decimals,
),
0,
),
DECIMALS,
)
: '';
txData.recipient = toNative(txData.toChain, recipientAddress).toString();

return txData;
},
[parseSingleTx],
);

const PARSERS = {
PORTAL_TOKEN_BRIDGE: parseTokenBridgeTx,
NATIVE_TOKEN_TRANSFER: parseNTTTx,
CCTP_WORMHOLE_INTEGRATION: parseCCTPTx,
ETH_BRIDGE: parsePorticoTx,
USDT_BRIDGE: parsePorticoTx,
};
const PARSERS = useMemo(
() => ({
PORTAL_TOKEN_BRIDGE: parseTokenBridgeTx,
NATIVE_TOKEN_TRANSFER: parseNTTTx,
CCTP_WORMHOLE_INTEGRATION: parseCCTPTx,
ETH_BRIDGE: parsePorticoTx,
USDT_BRIDGE: parsePorticoTx,
}),
[parseCCTPTx, parseNTTTx, parsePorticoTx, parseTokenBridgeTx],
);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const parseTransactions = useCallback(
Expand Down Expand Up @@ -339,7 +360,7 @@ const useTransactionHistoryWHScan = (
})
.filter((tx) => !!tx); // Filter out unsupported transactions
},
[],
[PARSERS, parsePorticoTx],
);

useEffect(() => {
Expand Down Expand Up @@ -413,7 +434,7 @@ const useTransactionHistoryWHScan = (
return () => {
cancelled = true;
};
}, [page, pageSize]);
}, [address, page, pageSize, parseTransactions]);

return {
transactions,
Expand Down
Loading