diff --git a/IPFS.json b/IPFS.json
index df2d553d1..df6502566 100644
--- a/IPFS.json
+++ b/IPFS.json
@@ -3,7 +3,8 @@
"cid": "bafybeib3zmyqlmantvdd6i5q4ehmo4larvorgquyanne3uoqdbedwgh3aq",
"leastSafeVersion": "0.36.1",
"config": {
- "enabledWithdrawalDexes": ["one-inch", "paraswap", "bebop"]
+ "enabledWithdrawalDexes": ["one-inch", "paraswap", "bebop"],
+ "multiChainBanner": [324, 10, 42161, 137, 8453, 5000, 59144, 534352, 56]
}
},
"5": {
@@ -16,7 +17,10 @@
"cid": "bafybeibbsoqlofslw273b4ih2pdxfaz2zbjmred2ijog725tcmfoewix7y",
"leastSafeVersion": "0.36.1",
"config": {
- "enabledWithdrawalDexes": ["one-inch", "paraswap", "bebop"]
+ "enabledWithdrawalDexes": ["one-inch", "paraswap", "bebop"],
+ "multiChainBanner": [
+ 324, 10, 42161, 137, 8453, 5000, 59144, 534352, 56, 34443
+ ]
}
}
}
diff --git a/assets/icons/lido-multichain/mode.svg b/assets/icons/lido-multichain/mode.svg
new file mode 100644
index 000000000..c3eaca426
--- /dev/null
+++ b/assets/icons/lido-multichain/mode.svg
@@ -0,0 +1,11 @@
+
diff --git a/config/external-config/types.ts b/config/external-config/types.ts
index 92ea1ad04..7c0435064 100644
--- a/config/external-config/types.ts
+++ b/config/external-config/types.ts
@@ -12,6 +12,7 @@ export type ManifestEntry = {
export type ManifestConfig = {
enabledWithdrawalDexes: DexWithdrawalApi[];
+ multiChainBanner: number[];
};
export type ExternalConfig = Omit &
diff --git a/config/external-config/utils.ts b/config/external-config/utils.ts
index 9dc7e8d86..ad7f72c1f 100644
--- a/config/external-config/utils.ts
+++ b/config/external-config/utils.ts
@@ -4,7 +4,45 @@ import { getDexConfig } from 'features/withdrawals/request/withdrawal-rates';
import FallbackLocalManifest from 'IPFS.json' assert { type: 'json' };
-// TODO: refactor on config expansion
+const isEnabledDexesValid = (config: object) => {
+ if (
+ !(
+ 'enabledWithdrawalDexes' in config &&
+ Array.isArray(config.enabledWithdrawalDexes)
+ )
+ )
+ return false;
+
+ const enabledWithdrawalDexes = config.enabledWithdrawalDexes;
+
+ if (
+ !enabledWithdrawalDexes.every(
+ (dex) => typeof dex === 'string' && dex !== '',
+ )
+ )
+ return false;
+
+ return new Set(enabledWithdrawalDexes).size === enabledWithdrawalDexes.length;
+};
+
+const isMultiChainBannerValid = (config: object) => {
+ // allow empty config
+ if (!('multiChainBanner' in config) || !config.multiChainBanner) return true;
+
+ if (!Array.isArray(config.multiChainBanner)) return false;
+
+ const multiChainBanner = config.multiChainBanner;
+
+ if (
+ !multiChainBanner.every(
+ (chainId) => typeof chainId === 'number' && chainId > 0,
+ )
+ )
+ return false;
+
+ return !(new Set(multiChainBanner).size !== multiChainBanner.length);
+};
+
export const isManifestEntryValid = (
entry?: unknown,
): entry is ManifestEntry => {
@@ -18,16 +56,10 @@ export const isManifestEntryValid = (
entry.config
) {
const config = entry.config;
- if (
- 'enabledWithdrawalDexes' in config &&
- Array.isArray(config.enabledWithdrawalDexes)
- ) {
- const enabledWithdrawalDexes = config.enabledWithdrawalDexes;
- return (
- new Set(enabledWithdrawalDexes).size === enabledWithdrawalDexes.length
- );
- }
- return false;
+
+ return [isEnabledDexesValid, isMultiChainBannerValid]
+ .map((validator) => validator(config))
+ .every((isValid) => isValid);
}
return false;
};
@@ -39,6 +71,7 @@ export const getBackwardCompatibleConfig = (
enabledWithdrawalDexes: config.enabledWithdrawalDexes.filter(
(dex) => !!getDexConfig(dex),
),
+ multiChainBanner: config.multiChainBanner ?? [],
};
};
diff --git a/config/groups/revalidation.ts b/config/groups/revalidation.ts
index 59c55f761..523d09e79 100644
--- a/config/groups/revalidation.ts
+++ b/config/groups/revalidation.ts
@@ -1,15 +1,2 @@
-import type { ManifestConfig, ManifestEntry } from 'config/external-config';
-
export const DEFAULT_REVALIDATION = 60 * 15; // 15 minutes
export const ERROR_REVALIDATION_SECONDS = 60; // 1 minute
-
-export const FALLBACK_CONFIG: ManifestConfig = {
- enabledWithdrawalDexes: [],
-};
-
-export const FALLBACK_MANIFEST_ENTRY: ManifestEntry = {
- cid: undefined,
- ens: undefined,
- leastSafeVersion: undefined,
- config: FALLBACK_CONFIG,
-};
diff --git a/config/groups/web3.ts b/config/groups/web3.ts
index 06f27f001..3e072920d 100644
--- a/config/groups/web3.ts
+++ b/config/groups/web3.ts
@@ -2,6 +2,8 @@ import { parseEther } from '@ethersproject/units';
// interval in ms for RPC event polling for token balance and tx updates
export const PROVIDER_POLLING_INTERVAL = 12_000;
+// how long in ms to wait for RPC batching(multicall and provider)
+export const PROVIDER_BATCH_TIME = 150;
// account for gas estimation
// will always have >=0.001 ether, >=0.001 stETH, >=0.001 wstETH
diff --git a/consts/chains.ts b/consts/chains.ts
index e5bb343be..506330d20 100644
--- a/consts/chains.ts
+++ b/consts/chains.ts
@@ -14,4 +14,5 @@ export enum LIDO_MULTICHAIN_CHAINS {
Linea = 59144,
Scroll = 534352,
'BNB Chain' = 56,
+ 'Mode Chain' = 34443,
}
diff --git a/consts/external-links.ts b/consts/external-links.ts
index af4db36ed..a62599c78 100644
--- a/consts/external-links.ts
+++ b/consts/external-links.ts
@@ -5,6 +5,6 @@ export const LINK_ADD_NFT_GUIDE = `${config.helpOrigin}/en/articles/7858367-how-
export const OPEN_OCEAN_REFERRAL_ADDRESS =
'0xbb1263222b2c020f155d409dba05c4a3861f18f8';
-// for dev and local testing you can set to 'http:/localhost:3000/runtime/IPFS.json' and have file at /public/runtime/IPFS.json
+// for dev and local testing you can set to 'http://localhost:3000/runtime/IPFS.json' and have file at /public/runtime/IPFS.json
export const IPFS_MANIFEST_URL =
'https://raw.githubusercontent.com/lidofinance/ethereum-staking-widget/main/IPFS.json';
diff --git a/consts/matomo-click-events.ts b/consts/matomo-click-events.ts
index 0955fc01f..91f34032c 100644
--- a/consts/matomo-click-events.ts
+++ b/consts/matomo-click-events.ts
@@ -63,6 +63,16 @@ export const enum MATOMO_CLICK_EVENTS_TYPES {
// /withdrawal/request and /withdrawal/claim shared events
withdrawalWhatAreStakingPenaltiesFAQ = 'withdrawalWhatAreStakingPenaltiesFAQ',
withdrawalNFTGuideFAQ = 'withdrawalNFTGuideFAQ',
+
+ // /rewards page
+ rewardsExportCSV = 'rewardsExportCSV',
+ rewardsHistoricalStethPriceCheck = 'rewardsHistoricalStethPriceCheck',
+ rewardsHistoricalStethPriceUncheck = 'rewardsHistoricalStethPriceUncheck',
+ rewardsIncludeTransfersCheck = 'rewardsIncludeTransfersCheck',
+ rewardsIncludeTransfersUncheck = 'rewardsIncludeTransfersUncheck',
+ rewardsHistoricalCurrencyUSD = 'rewardsHistoricalCurrencyUSD',
+ rewardsHistoricalCurrencyEUR = 'rewardsHistoricalCurrencyEUR',
+ rewardsHistoricalCurrencyGBP = 'rewardsHistoricalCurrencyGBP',
}
export const MATOMO_CLICK_EVENTS: Record<
@@ -339,4 +349,46 @@ export const MATOMO_CLICK_EVENTS: Record<
'Push on "How do I add the Lido NFT to my wallet" guide link in FAQ',
'eth_withdrawals_how_to_add_nft_guide_FAQ',
],
+
+ // /rewards page
+ [MATOMO_CLICK_EVENTS_TYPES.rewardsExportCSV]: [
+ 'Ethereum_Rewards_Widget',
+ 'Click on "Export CSV"',
+ 'eth_rewards_export_csv',
+ ],
+ [MATOMO_CLICK_EVENTS_TYPES.rewardsHistoricalStethPriceCheck]: [
+ 'Ethereum_Rewards_Widget',
+ 'Click check on "Historical stETH price" in check-box',
+ 'eth_historical_stETH_price_check_box_check',
+ ],
+ [MATOMO_CLICK_EVENTS_TYPES.rewardsHistoricalStethPriceUncheck]: [
+ 'Ethereum_Rewards_Widget',
+ 'Click uncheck on "Historical stETH price" in check-box',
+ 'eth_historical_stETH_price_check_box_uncheck',
+ ],
+ [MATOMO_CLICK_EVENTS_TYPES.rewardsIncludeTransfersCheck]: [
+ 'Ethereum_Rewards_Widget',
+ 'Click check on "Include transfers" in check-box',
+ 'eth_include_transfers_check_box_check',
+ ],
+ [MATOMO_CLICK_EVENTS_TYPES.rewardsIncludeTransfersUncheck]: [
+ 'Ethereum_Rewards_Widget',
+ 'Click uncheck on "Include transfers" in check-box',
+ 'eth_include_transfers_check_box_uncheck',
+ ],
+ [MATOMO_CLICK_EVENTS_TYPES.rewardsHistoricalCurrencyUSD]: [
+ 'Ethereum_Rewards_Widget',
+ 'Click on "USD" in currency choice',
+ 'eth_historical_usd_currency_choice',
+ ],
+ [MATOMO_CLICK_EVENTS_TYPES.rewardsHistoricalCurrencyEUR]: [
+ 'Ethereum_Rewards_Widget',
+ 'Click on "EUR" in currency choice',
+ 'eth_historical_eur_currency_choice',
+ ],
+ [MATOMO_CLICK_EVENTS_TYPES.rewardsHistoricalCurrencyGBP]: [
+ 'Ethereum_Rewards_Widget',
+ 'Click on "GBP" in currency choice',
+ 'eth_historical_gbp_currency_choice',
+ ],
};
diff --git a/features/ipfs/security-status-banner/use-version-check.ts b/features/ipfs/security-status-banner/use-version-check.ts
index 414a24e37..f74449dbf 100644
--- a/features/ipfs/security-status-banner/use-version-check.ts
+++ b/features/ipfs/security-status-banner/use-version-check.ts
@@ -1,12 +1,12 @@
import { useEffect, useState } from 'react';
-import { useLidoSWR } from '@lido-sdk/react';
-import { useWeb3 } from 'reef-knot/web3-react';
import { useForceDisconnect } from 'reef-knot/core-react';
+import { useLidoSWR } from '@lido-sdk/react';
import buildInfo from 'build-info.json';
import { config } from 'config';
import { useUserConfig } from 'config/user-config';
import { STRATEGY_IMMUTABLE } from 'consts/swr-strategies';
+import { useDappStatus } from 'shared/hooks/use-dapp-status';
import { overrideWithQAMockBoolean } from 'utils/qa';
import { isVersionLess } from './utils';
@@ -19,7 +19,7 @@ const URL_CID_REGEX =
/[/.](?Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,})([./#?]|$)/;
export const useVersionCheck = () => {
- const { active } = useWeb3();
+ const { isDappActive } = useDappStatus();
const { setIsWalletConnectionAllowed } = useUserConfig();
const { forceDisconnect } = useForceDisconnect();
const [areConditionsAccepted, setConditionsAccepted] = useState(false);
@@ -84,7 +84,7 @@ export const useVersionCheck = () => {
forceDisconnect();
}
}, [
- active,
+ isDappActive,
forceDisconnect,
isNotVerifiable,
isVersionUnsafe,
diff --git a/features/rewards/components/export/Export.tsx b/features/rewards/components/export/Export.tsx
index cb59ca184..3bea9230a 100644
--- a/features/rewards/components/export/Export.tsx
+++ b/features/rewards/components/export/Export.tsx
@@ -5,6 +5,8 @@ import { backendRequest } from 'features/rewards/fetchers/backend';
import { ButtonStyle } from './Exportstyled';
import type { CurrencyType } from 'features/rewards/constants';
+import { trackEvent } from '@lidofinance/analytics-matomo';
+import { MATOMO_CLICK_EVENTS } from 'consts/matomo-click-events';
type ExportProps = {
currency: CurrencyType;
@@ -33,6 +35,7 @@ export const Export = ({
});
const formatted = genExportData(currencyObject, result.events);
saveAsCSV(formatted);
+ trackEvent(...MATOMO_CLICK_EVENTS.rewardsExportCSV);
};
return (
diff --git a/features/rewards/components/rewardsListContent/RewardsListContent.tsx b/features/rewards/components/rewardsListContent/RewardsListContent.tsx
index e868152ae..b7c8ad636 100644
--- a/features/rewards/components/rewardsListContent/RewardsListContent.tsx
+++ b/features/rewards/components/rewardsListContent/RewardsListContent.tsx
@@ -1,13 +1,11 @@
import { FC } from 'react';
import { Loader, Divider } from '@lidofinance/lido-ui';
-import { useSDK, useTokenBalance } from '@lido-sdk/react';
-import { TOKENS, getTokenAddress } from '@lido-sdk/constants';
import { Zero } from '@ethersproject/constants';
-import { STRATEGY_LAZY } from 'consts/swr-strategies';
import { useRewardsHistory } from 'features/rewards/hooks';
import { ErrorBlockNoSteth } from 'features/rewards/components/errorBlocks/ErrorBlockNoSteth';
import { RewardsTable } from 'features/rewards/components/rewardsTable';
+import { useStethBalance } from 'shared/hooks/use-balance';
import { useDappStatus } from 'shared/hooks/use-dapp-status';
import { RewardsListsEmpty } from './RewardsListsEmpty';
@@ -19,6 +17,8 @@ import {
ErrorWrapper,
} from './RewardsListContentStyles';
+import type { Address } from 'viem';
+
export const RewardsListContent: FC = () => {
const { isWalletConnected, isSupportedChain } = useDappStatus();
const {
@@ -31,14 +31,11 @@ export const RewardsListContent: FC = () => {
setPage,
isLagging,
} = useRewardsHistory();
- // temporarily until we switched to a new SDK
- const { chainId } = useSDK();
- const { data: stethBalance, initialLoading: isStethBalanceLoading } =
- useTokenBalance(
- getTokenAddress(chainId || 1, TOKENS.STETH),
- address,
- STRATEGY_LAZY,
- );
+ const { data: stethBalance, isLoading: isStethBalanceLoading } =
+ useStethBalance({
+ account: address as Address,
+ shouldSubscribeToUpdates: false,
+ });
const hasSteth = stethBalance?.gt(Zero);
if (isWalletConnected && !isSupportedChain)
diff --git a/features/rewards/components/rewardsListHeader/LeftOptions.tsx b/features/rewards/components/rewardsListHeader/LeftOptions.tsx
index fef130268..fdb6e6bcc 100644
--- a/features/rewards/components/rewardsListHeader/LeftOptions.tsx
+++ b/features/rewards/components/rewardsListHeader/LeftOptions.tsx
@@ -3,6 +3,8 @@ import { Tooltip, Checkbox } from '@lidofinance/lido-ui';
import { useRewardsHistory } from 'features/rewards/hooks/useRewardsHistory';
import { LeftOptionsWrapper } from './styles';
+import { trackEvent } from '@lidofinance/analytics-matomo';
+import { MATOMO_CLICK_EVENTS } from 'consts/matomo-click-events';
export const LeftOptions: FC = () => {
const {
@@ -20,7 +22,14 @@ export const LeftOptions: FC = () => {
>
setIsIncludeTransfers(!isIncludeTransfers)}
+ onChange={() => {
+ trackEvent(
+ ...(!isIncludeTransfers
+ ? MATOMO_CLICK_EVENTS.rewardsIncludeTransfersCheck
+ : MATOMO_CLICK_EVENTS.rewardsIncludeTransfersUncheck),
+ );
+ setIsIncludeTransfers(!isIncludeTransfers);
+ }}
data-testid="includeTransfersCheckbox"
label="Include transfers"
/>
@@ -33,9 +42,14 @@ export const LeftOptions: FC = () => {
>
- setIsUseArchiveExchangeRate(!isUseArchiveExchangeRate)
- }
+ onChange={() => {
+ trackEvent(
+ ...(!isUseArchiveExchangeRate
+ ? MATOMO_CLICK_EVENTS.rewardsHistoricalStethPriceCheck
+ : MATOMO_CLICK_EVENTS.rewardsHistoricalStethPriceUncheck),
+ );
+ setIsUseArchiveExchangeRate(!isUseArchiveExchangeRate);
+ }}
data-testid="historicalStEthCheckbox"
label="Historical stETH price"
/>
diff --git a/features/rewards/components/rewardsListHeader/RightOptions.tsx b/features/rewards/components/rewardsListHeader/RightOptions.tsx
index 5b5632b6d..b323761c0 100644
--- a/features/rewards/components/rewardsListHeader/RightOptions.tsx
+++ b/features/rewards/components/rewardsListHeader/RightOptions.tsx
@@ -4,6 +4,14 @@ import { Export } from 'features/rewards/components/export';
import { RightOptionsWrapper } from './styles';
import { useRewardsHistory } from 'features/rewards/hooks/useRewardsHistory';
+import { MatomoEventType, trackEvent } from '@lidofinance/analytics-matomo';
+import { MATOMO_CLICK_EVENTS } from 'consts/matomo-click-events';
+
+const MATOMO_EVENTS_MAP_CURRENCY_SELECTOR: Record = {
+ usd: MATOMO_CLICK_EVENTS.rewardsHistoricalCurrencyUSD,
+ eur: MATOMO_CLICK_EVENTS.rewardsHistoricalCurrencyEUR,
+ gbp: MATOMO_CLICK_EVENTS.rewardsHistoricalCurrencyGBP,
+};
export const RightOptions: FC = () => {
const {
@@ -15,7 +23,14 @@ export const RightOptions: FC = () => {
} = useRewardsHistory();
return (
-
+ {
+ const event = MATOMO_EVENTS_MAP_CURRENCY_SELECTOR[value];
+ if (event) trackEvent(...event);
+ setCurrency(value);
+ }}
+ />
{
const useStakeFormNetworkData = (): StakeFormNetworkData => {
const {
data: stethBalance,
- update: updateStethBalance,
- initialLoading: isStethBalanceLoading,
- } = useSTETHBalance(STRATEGY_LAZY);
+ refetch: updateStethBalance,
+ isLoading: isStethBalanceLoading,
+ } = useStethBalance();
const { isMultisig, isLoading: isMultisigLoading } = useIsMultisig();
const gasLimit = useStethSubmitGasLimit();
const { maxGasPrice, initialLoading: isMaxGasPriceLoading } =
@@ -75,9 +74,10 @@ const useStakeFormNetworkData = (): StakeFormNetworkData => {
const {
data: etherBalance,
- update: updateEtherBalance,
- initialLoading: isEtherBalanceLoading,
- } = useEthereumBalance(undefined, STRATEGY_LAZY);
+ refetch: updateEtherBalance,
+ isLoading: isEtherBalanceLoading,
+ } = useEthereumBalance();
+
const {
data: stakingLimitInfo,
mutate: mutateStakeLimit,
diff --git a/features/stake/stake-form/stake-form-context/validation.ts b/features/stake/stake-form/stake-form-context/validation.ts
index 26d0cadcf..b908e6f9f 100644
--- a/features/stake/stake-form/stake-form-context/validation.ts
+++ b/features/stake/stake-form/stake-form-context/validation.ts
@@ -1,9 +1,9 @@
import { useMemo } from 'react';
import invariant from 'tiny-invariant';
-import { useWeb3 } from 'reef-knot/web3-react';
import { Zero } from '@ethersproject/constants';
import { validateEtherAmount } from 'shared/hook-form/validation/validate-ether-amount';
+import { useDappStatus } from 'shared/hooks/use-dapp-status';
import { VALIDATION_CONTEXT_TIMEOUT } from 'features/withdrawals/withdrawals-constants';
import { handleResolverValidationError } from 'shared/hook-form/validation/validation-error';
import { awaitWithTimeout } from 'utils/await-with-timeout';
@@ -72,26 +72,26 @@ export const stakeFormValidationResolver: Resolver<
export const useStakeFormValidationContext = (
networkData: StakeFormNetworkData,
): Promise => {
- const { active } = useWeb3();
+ const { isDappActive } = useDappStatus();
const { stakingLimitInfo, etherBalance, isMultisig, gasCost } = networkData;
const validationContextAwaited = useMemo(() => {
if (
stakingLimitInfo &&
// we ether not connected or must have all account related data
- (!active || (etherBalance && gasCost && isMultisig !== undefined))
+ (!isDappActive || (etherBalance && gasCost && isMultisig !== undefined))
) {
return {
- isWalletActive: active,
+ isWalletActive: isDappActive,
stakingLimitLevel: stakingLimitInfo.stakeLimitLevel,
currentStakeLimit: stakingLimitInfo.currentStakeLimit,
- // condition above guaranties stubs will only be passed when active = false
+ // condition above guaranties stubs will only be passed when isDappActive = false
etherBalance: etherBalance ?? Zero,
gasCost: gasCost ?? Zero,
isMultisig: isMultisig ?? false,
};
}
return undefined;
- }, [active, etherBalance, gasCost, isMultisig, stakingLimitInfo]);
+ }, [isDappActive, etherBalance, gasCost, isMultisig, stakingLimitInfo]);
return useAwaiter(validationContextAwaited).awaiter;
};
diff --git a/features/stake/stake-form/use-stake.ts b/features/stake/stake-form/use-stake.ts
index a772a63f5..33fe39827 100644
--- a/features/stake/stake-form/use-stake.ts
+++ b/features/stake/stake-form/use-stake.ts
@@ -1,7 +1,7 @@
import { BigNumber } from 'ethers';
import { useCallback } from 'react';
-import { useWeb3 } from 'reef-knot/web3-react';
import invariant from 'tiny-invariant';
+import { useAccount } from 'wagmi';
import {
useSDK,
@@ -18,6 +18,7 @@ import { MockLimitReachedError, getAddress } from './utils';
import { useTxModalStagesStake } from './hooks/use-tx-modal-stages-stake';
import { sendTx } from 'utils/send-tx';
+import { useTxConfirmation } from 'shared/hooks/use-tx-conformation';
type StakeArguments = {
amount: BigNumber | null;
@@ -31,18 +32,18 @@ type StakeOptions = {
export const useStake = ({ onConfirm, onRetry }: StakeOptions) => {
const stethContractWeb3 = useSTETHContractWeb3();
+ const { address } = useAccount();
const stethContract = useSTETHContractRPC();
- const { account, chainId } = useWeb3();
const { staticRpcProvider } = useCurrentStaticRpcProvider();
const { providerWeb3 } = useSDK();
const { txModalStages } = useTxModalStagesStake();
+ const waitForTx = useTxConfirmation();
return useCallback(
async ({ amount, referral }: StakeArguments): Promise => {
try {
invariant(amount, 'amount is null');
- invariant(chainId, 'chainId is not defined');
- invariant(account, 'account is not defined');
+ invariant(address, 'account is not defined');
invariant(providerWeb3, 'providerWeb3 not defined');
invariant(stethContractWeb3, 'steth is not defined');
@@ -56,7 +57,7 @@ export const useStake = ({ onConfirm, onRetry }: StakeOptions) => {
txModalStages.sign(amount);
const [isMultisig, referralAddress] = await Promise.all([
- isContract(account, staticRpcProvider),
+ isContract(address, staticRpcProvider),
referral
? getAddress(referral, staticRpcProvider)
: config.STAKE_FALLBACK_REFERRAL_ADDRESS,
@@ -92,13 +93,11 @@ export const useStake = ({ onConfirm, onRetry }: StakeOptions) => {
txModalStages.pending(amount, txHash);
- if (!isMultisig) {
- await runWithTransactionLogger('Stake block confirmation', () =>
- staticRpcProvider.waitForTransaction(txHash),
- );
- }
+ await runWithTransactionLogger('Stake block confirmation', () =>
+ waitForTx(txHash),
+ );
- const stethBalance = await stethContract.balanceOf(account);
+ const stethBalance = await stethContract.balanceOf(address);
await onConfirm?.();
@@ -112,14 +111,14 @@ export const useStake = ({ onConfirm, onRetry }: StakeOptions) => {
}
},
[
- chainId,
- account,
+ address,
providerWeb3,
stethContractWeb3,
txModalStages,
staticRpcProvider,
stethContract,
onConfirm,
+ waitForTx,
onRetry,
],
);
diff --git a/features/stake/stake.tsx b/features/stake/stake.tsx
index 15f3f451b..237eb888c 100644
--- a/features/stake/stake.tsx
+++ b/features/stake/stake.tsx
@@ -1,5 +1,5 @@
import { FaqPlaceholder } from 'features/ipfs';
-import { useWeb3Key } from 'shared/hooks/useWeb3Key';
+import { useWagmiKey } from 'shared/hooks/use-wagmi-key';
import NoSSRWrapper from 'shared/components/no-ssr-wrapper';
import { OnlyInfraRender } from 'shared/components/only-infra-render';
@@ -8,7 +8,7 @@ import { LidoStats } from './lido-stats/lido-stats';
import { StakeForm } from './stake-form';
export const Stake = () => {
- const key = useWeb3Key();
+ const key = useWagmiKey();
return (
<>
diff --git a/features/withdrawals/claim/claim-form-context/claim-form-context.tsx b/features/withdrawals/claim/claim-form-context/claim-form-context.tsx
index ac4c471b6..555257a7e 100644
--- a/features/withdrawals/claim/claim-form-context/claim-form-context.tsx
+++ b/features/withdrawals/claim/claim-form-context/claim-form-context.tsx
@@ -7,26 +7,29 @@ import {
useMemo,
} from 'react';
import { FormProvider, useForm } from 'react-hook-form';
-
import invariant from 'tiny-invariant';
+
+import { useClaim } from 'features/withdrawals/hooks';
+import { useClaimData } from 'features/withdrawals/contexts/claim-data-context';
+import { useFormControllerRetry } from 'shared/hook-form/form-controller/use-form-controller-retry-delegate';
+import {
+ FormControllerContext,
+ FormControllerContextValueType,
+} from 'shared/hook-form/form-controller';
+import { useDappStatus } from 'shared/hooks/use-dapp-status';
+
import { ClaimFormInputType, ClaimFormValidationContext } from './types';
import { claimFormValidationResolver } from './validation';
-import { useClaim } from 'features/withdrawals/hooks';
import { useMaxSelectedCount } from './use-max-selected-count';
-import { useFormControllerRetry } from 'shared/hook-form/form-controller/use-form-controller-retry-delegate';
import {
generateDefaultValues,
useGetDefaultValues,
} from './use-default-values';
import { ClaimFormHelperState, useHelperState } from './use-helper-state';
-import {
- FormControllerContext,
- FormControllerContextValueType,
-} from 'shared/hook-form/form-controller';
-import { useClaimData } from 'features/withdrawals/contexts/claim-data-context';
-import { useWeb3 } from 'reef-knot/web3-react';
-type ClaimFormDataContextValueType = ClaimFormHelperState;
+type ClaimFormDataContextValueType = ClaimFormHelperState & {
+ maxSelectedCountReason: string | null;
+};
const claimFormDataContext =
createContext(null);
@@ -39,25 +42,32 @@ export const useClaimFormData = () => {
};
export const ClaimFormProvider: FC = ({ children }) => {
- const { active } = useWeb3();
+ const { isDappActive } = useDappStatus();
const { data } = useClaimData();
- const { maxSelectedRequestCount, defaultSelectedRequestCount } =
- useMaxSelectedCount();
+ const {
+ maxSelectedRequestCount,
+ defaultSelectedRequestCount,
+ maxSelectedCountReason,
+ } = useMaxSelectedCount();
const { getDefaultValues } = useGetDefaultValues(defaultSelectedRequestCount);
const formObject = useForm({
defaultValues: getDefaultValues,
resolver: claimFormValidationResolver,
- context: { maxSelectedRequestCount, isWalletActive: active },
+ context: { maxSelectedRequestCount, isWalletActive: isDappActive },
mode: 'onChange',
reValidateMode: 'onChange',
});
const { watch, reset, setValue, getValues, formState } = formObject;
- const claimFormDataContextValue = useHelperState(
- watch,
- maxSelectedRequestCount,
+
+ const helperState = useHelperState(watch, maxSelectedRequestCount);
+
+ const claimFormDataContextValue = useMemo(
+ () => ({ ...helperState, maxSelectedCountReason }),
+ [helperState, maxSelectedCountReason],
);
+
const { retryEvent, retryFire } = useFormControllerRetry();
const claim = useClaim({ onRetry: retryFire });
diff --git a/features/withdrawals/claim/claim-form-context/use-max-selected-count.ts b/features/withdrawals/claim/claim-form-context/use-max-selected-count.ts
index caab735ad..d59b2cc3b 100644
--- a/features/withdrawals/claim/claim-form-context/use-max-selected-count.ts
+++ b/features/withdrawals/claim/claim-form-context/use-max-selected-count.ts
@@ -15,8 +15,14 @@ export const useMaxSelectedCount = () => {
DEFAULT_CLAIM_REQUEST_SELECTED,
maxSelectedRequestCount,
);
+
+ const maxSelectedCountReason = isLedgerLive
+ ? 'Ledger Clear Sign allows to claim up to 2 requests per transaction'
+ : null;
+
return {
maxSelectedRequestCount,
defaultSelectedRequestCount,
+ maxSelectedCountReason,
};
};
diff --git a/features/withdrawals/claim/form/requests-list/request-item.tsx b/features/withdrawals/claim/form/requests-list/request-item.tsx
index fcf25521d..a811f8cdd 100644
--- a/features/withdrawals/claim/form/requests-list/request-item.tsx
+++ b/features/withdrawals/claim/form/requests-list/request-item.tsx
@@ -1,8 +1,13 @@
import { forwardRef } from 'react';
-import { useWeb3 } from 'reef-knot/web3-react';
import { useFormState, useWatch } from 'react-hook-form';
+import { useAccount } from 'wagmi';
-import { Checkbox, CheckboxProps, External } from '@lidofinance/lido-ui';
+import {
+ Checkbox,
+ CheckboxProps,
+ External,
+ Tooltip,
+} from '@lidofinance/lido-ui';
import { FormatToken } from 'shared/formatters';
import { RequestStatus } from './request-item-status';
@@ -19,9 +24,9 @@ type RequestItemProps = {
export const RequestItem = forwardRef(
({ token_id, name, disabled, index, ...props }, ref) => {
- const { chainId } = useWeb3();
+ const { chainId } = useAccount();
const { isSubmitting } = useFormState();
- const { canSelectMore } = useClaimFormData();
+ const { canSelectMore, maxSelectedCountReason } = useClaimFormData();
const { checked, status } = useWatch<
ClaimFormInputType,
`requests.${number}`
@@ -42,15 +47,23 @@ export const RequestItem = forwardRef(
: status.amountOfStETH;
const symbol = isClaimable ? 'ETH' : 'stETH';
+ const showDisabledReasonTooltip =
+ maxSelectedCountReason &&
+ !canSelectMore &&
+ status.isFinalized &&
+ !checked;
+
const label = (
);
- return (
+ const requestBody = (
(
);
+
+ return showDisabledReasonTooltip ? (
+
+ {requestBody}
+
+ ) : (
+ requestBody
+ );
},
);
diff --git a/features/withdrawals/claim/form/requests-list/requests-list.tsx b/features/withdrawals/claim/form/requests-list/requests-list.tsx
index 4ed62d276..1e7ed79e8 100644
--- a/features/withdrawals/claim/form/requests-list/requests-list.tsx
+++ b/features/withdrawals/claim/form/requests-list/requests-list.tsx
@@ -1,11 +1,11 @@
+import { useFieldArray, useFormContext, useFormState } from 'react-hook-form';
import { useDappStatus } from 'shared/hooks/use-dapp-status';
+import { ClaimFormInputType } from '../../claim-form-context';
import { RequestItem } from './request-item';
import { RequestsEmpty } from './requests-empty';
import { Wrapper } from './styles';
import { RequestsLoader } from './requests-loader';
-import { useFieldArray, useFormContext, useFormState } from 'react-hook-form';
-import { ClaimFormInputType } from '../../claim-form-context';
export const RequestsList: React.FC = () => {
const { isWalletConnected, isDappActive } = useDappStatus();
diff --git a/features/withdrawals/hooks/contract/useClaim.ts b/features/withdrawals/hooks/contract/useClaim.ts
index 0e55e9bcf..f55dce17f 100644
--- a/features/withdrawals/hooks/contract/useClaim.ts
+++ b/features/withdrawals/hooks/contract/useClaim.ts
@@ -1,40 +1,43 @@
import { useCallback } from 'react';
import { BigNumber } from 'ethers';
+import invariant from 'tiny-invariant';
+import { useAccount } from 'wagmi';
-import { useClaimData } from 'features/withdrawals/contexts/claim-data-context';
-import { runWithTransactionLogger } from 'utils';
+import { useSDK } from '@lido-sdk/react';
-import { useWithdrawalsContract } from './useWithdrawalsContract';
+import { useClaimData } from 'features/withdrawals/contexts/claim-data-context';
import { RequestStatusClaimable } from 'features/withdrawals/types/request-status';
-import invariant from 'tiny-invariant';
-import { isContract } from 'utils/isContract';
-import { useWeb3 } from 'reef-knot/web3-react';
-import { useSDK } from '@lido-sdk/react';
import { useTxModalStagesClaim } from 'features/withdrawals/claim/transaction-modal-claim/use-tx-modal-stages-claim';
import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider';
+import { runWithTransactionLogger } from 'utils';
+import { isContract } from 'utils/isContract';
import { sendTx } from 'utils/send-tx';
+import { useTxConfirmation } from 'shared/hooks/use-tx-conformation';
+
+import { useWithdrawalsContract } from './useWithdrawalsContract';
type Args = {
onRetry?: () => void;
};
export const useClaim = ({ onRetry }: Args) => {
- const { account } = useWeb3();
+ const { address } = useAccount();
const { providerWeb3 } = useSDK();
const { contractWeb3 } = useWithdrawalsContract();
const { staticRpcProvider } = useCurrentStaticRpcProvider();
const { optimisticClaimRequests } = useClaimData();
const { txModalStages } = useTxModalStagesClaim();
+ const waitForTx = useTxConfirmation();
return useCallback(
async (sortedRequests: RequestStatusClaimable[]) => {
try {
invariant(contractWeb3, 'must have contract');
invariant(sortedRequests, 'must have requests');
- invariant(account, 'must have address');
+ invariant(address, 'must have address');
invariant(providerWeb3, 'must have provider');
- const isMultisig = await isContract(account, contractWeb3.provider);
+ const isMultisig = await isContract(address, contractWeb3.provider);
const amount = sortedRequests.reduce(
(s, r) => s.add(r.claimableEth),
@@ -70,8 +73,8 @@ export const useClaim = ({ onRetry }: Args) => {
txModalStages.pending(amount, txHash);
- await runWithTransactionLogger('Claim block confirmation', async () =>
- staticRpcProvider.waitForTransaction(txHash),
+ await runWithTransactionLogger('Claim block confirmation', () =>
+ waitForTx(txHash),
);
await optimisticClaimRequests(sortedRequests);
@@ -86,11 +89,12 @@ export const useClaim = ({ onRetry }: Args) => {
},
[
contractWeb3,
- account,
+ address,
providerWeb3,
txModalStages,
- staticRpcProvider,
optimisticClaimRequests,
+ staticRpcProvider,
+ waitForTx,
onRetry,
],
);
diff --git a/features/withdrawals/hooks/contract/useRequest.ts b/features/withdrawals/hooks/contract/useRequest.ts
index 16a4cfba2..82c7d17c3 100644
--- a/features/withdrawals/hooks/contract/useRequest.ts
+++ b/features/withdrawals/hooks/contract/useRequest.ts
@@ -2,7 +2,6 @@
import { useCallback } from 'react';
import { BigNumber } from 'ethers';
import invariant from 'tiny-invariant';
-import { useWeb3 } from 'reef-knot/web3-react';
import { useAccount } from 'wagmi';
import { Zero } from '@ethersproject/constants';
import {
@@ -29,12 +28,13 @@ import { useTxModalStagesRequest } from 'features/withdrawals/request/transactio
import { useTransactionModal } from 'shared/transaction-modal/transaction-modal';
import { sendTx } from 'utils/send-tx';
import { overrideWithQAMockBoolean } from 'utils/qa';
+import { useTxConfirmation } from 'shared/hooks/use-tx-conformation';
// this encapsulates permit/approval & steth/wsteth flows
const useWithdrawalRequestMethods = () => {
const { providerWeb3 } = useSDK();
const { staticRpcProvider } = useCurrentStaticRpcProvider();
- const { account, chainId, contractWeb3 } = useWithdrawalsContract();
+ const { address, contractWeb3 } = useWithdrawalsContract();
const permitSteth = useCallback(
async ({
@@ -44,8 +44,6 @@ const useWithdrawalRequestMethods = () => {
signature?: GatherPermitSignatureResult;
requests: BigNumber[];
}) => {
- invariant(chainId, 'must have chainId');
- invariant(account, 'must have account');
invariant(providerWeb3, 'must have providerWeb3');
invariant(signature, 'must have signature');
invariant(contractWeb3, 'must have contractWeb3');
@@ -73,7 +71,7 @@ const useWithdrawalRequestMethods = () => {
return callback;
},
- [account, chainId, contractWeb3, providerWeb3, staticRpcProvider],
+ [contractWeb3, providerWeb3, staticRpcProvider],
);
const permitWsteth = useCallback(
@@ -84,8 +82,6 @@ const useWithdrawalRequestMethods = () => {
signature?: GatherPermitSignatureResult;
requests: BigNumber[];
}) => {
- invariant(chainId, 'must have chainId');
- invariant(account, 'must have account');
invariant(signature, 'must have signature');
invariant(providerWeb3, 'must have providerWeb3');
invariant(contractWeb3, 'must have contractWeb3');
@@ -113,21 +109,20 @@ const useWithdrawalRequestMethods = () => {
return callback;
},
- [account, chainId, contractWeb3, providerWeb3, staticRpcProvider],
+ [contractWeb3, providerWeb3, staticRpcProvider],
);
const steth = useCallback(
async ({ requests }: { requests: BigNumber[] }) => {
- invariant(chainId, 'must have chainId');
- invariant(account, 'must have account');
+ invariant(address, 'must have account');
invariant(contractWeb3, 'must have contractWeb3');
invariant(providerWeb3, 'must have providerWeb3');
- const isMultisig = await isContract(account, contractWeb3.provider);
+ const isMultisig = await isContract(address, staticRpcProvider);
const tx = await contractWeb3.populateTransaction.requestWithdrawals(
requests,
- account,
+ address,
);
const callback = async () =>
@@ -140,21 +135,20 @@ const useWithdrawalRequestMethods = () => {
return callback;
},
- [account, chainId, contractWeb3, staticRpcProvider, providerWeb3],
+ [address, contractWeb3, staticRpcProvider, providerWeb3],
);
const wstETH = useCallback(
async ({ requests }: { requests: BigNumber[] }) => {
- invariant(chainId, 'must have chainId');
- invariant(account, 'must have account');
+ invariant(address, 'must have address');
invariant(contractWeb3, 'must have contractWeb3');
invariant(providerWeb3, 'must have providerWeb3');
- const isMultisig = await isContract(account, contractWeb3.provider);
+ const isMultisig = await isContract(address, staticRpcProvider);
const tx =
await contractWeb3.populateTransaction.requestWithdrawalsWstETH(
requests,
- account,
+ address,
);
const callback = async () =>
@@ -167,7 +161,7 @@ const useWithdrawalRequestMethods = () => {
return callback;
},
- [account, chainId, contractWeb3, staticRpcProvider, providerWeb3],
+ [address, contractWeb3, staticRpcProvider, providerWeb3],
);
return useCallback(
@@ -202,14 +196,13 @@ export const useWithdrawalRequest = ({
}: useWithdrawalRequestParams) => {
const { chainId } = useSDK();
const withdrawalQueueAddress = getWithdrawalQueueAddress(chainId);
- const { staticRpcProvider } = useCurrentStaticRpcProvider();
- const { connector } = useAccount();
- const { account } = useWeb3();
+ const { connector, address } = useAccount();
const { isBunker } = useWithdrawals();
const { txModalStages } = useTxModalStagesRequest();
const getRequestMethod = useWithdrawalRequestMethods();
const { isMultisig, isLoading: isMultisigLoading } = useIsMultisig();
+ const waitForTx = useTxConfirmation();
const wstethContract = useWSTETHContractRPC();
const stethContract = useSTETHContractRPC();
@@ -224,12 +217,13 @@ export const useWithdrawalRequest = ({
approve,
needsApprove,
allowance,
- initialLoading: loadingUseApprove,
+ isLoading: loadingUseApprove,
+ refetch: refetchAllowance,
} = useApprove(
valueBN,
tokenContract.address,
withdrawalQueueAddress,
- account ?? undefined,
+ address ?? undefined,
);
const { gatherPermitSignature } = useERC20PermitSignature({
@@ -322,12 +316,17 @@ export const useWithdrawalRequest = ({
txModalStages.pending(amount, token, txHash);
if (!isMultisig) {
- await runWithTransactionLogger('Stake block confirmation', () =>
- staticRpcProvider.waitForTransaction(txHash),
+ await runWithTransactionLogger(
+ 'Withdrawal Request block confirmation',
+ () => waitForTx(txHash),
);
}
- await onConfirm?.();
+ await Promise.all([
+ onConfirm?.(),
+ isApprovalFlow &&
+ refetchAllowance({ throwOnError: false, cancelRefetch: false }),
+ ]);
txModalStages.success(amount, token, txHash);
return true;
} catch (error) {
@@ -347,8 +346,9 @@ export const useWithdrawalRequest = ({
needsApprove,
onConfirm,
onRetry,
- staticRpcProvider,
+ refetchAllowance,
txModalStages,
+ waitForTx,
],
);
diff --git a/features/withdrawals/hooks/contract/useWithdrawalsContract.ts b/features/withdrawals/hooks/contract/useWithdrawalsContract.ts
index e874c7b84..f19c23cdb 100644
--- a/features/withdrawals/hooks/contract/useWithdrawalsContract.ts
+++ b/features/withdrawals/hooks/contract/useWithdrawalsContract.ts
@@ -1,14 +1,14 @@
+import { useAccount } from 'wagmi';
import {
useWithdrawalQueueContractWeb3,
useWithdrawalQueueContractRPC,
} from '@lido-sdk/react';
-import { useWeb3 } from 'reef-knot/web3-react';
export const useWithdrawalsContract = () => {
const contractWeb3 = useWithdrawalQueueContractWeb3();
const contractRpc = useWithdrawalQueueContractRPC();
- const { account, chainId } = useWeb3();
+ const { address, chainId } = useAccount();
- return { contractWeb3, contractRpc, account, chainId };
+ return { contractWeb3, contractRpc, address, chainId };
};
diff --git a/features/withdrawals/hooks/contract/useWithdrawalsData.ts b/features/withdrawals/hooks/contract/useWithdrawalsData.ts
index 592f97d8f..138078dec 100644
--- a/features/withdrawals/hooks/contract/useWithdrawalsData.ts
+++ b/features/withdrawals/hooks/contract/useWithdrawalsData.ts
@@ -80,15 +80,15 @@ const getRequestTimeForWQRequestIds = async (
};
export const useWithdrawalRequests = () => {
- const { contractRpc, account, chainId } = useWithdrawalsContract();
+ const { contractRpc, address, chainId } = useWithdrawalsContract();
// const { data: currentShareRate } = useLidoShareRate();
const swr = useLidoSWR(
// TODO: use this fragment for expected eth calculation
// currentShareRate
- // ? ['swr:withdrawals-requests', account, chainId, currentShareRate]
+ // ? ['swr:withdrawals-requests', address, chainId, currentShareRate]
// : false,
- ['swr:withdrawals-requests', account, chainId],
+ ['swr:withdrawals-requests', address, chainId],
async (...args: unknown[]) => {
const account = args[1] as string;
// const currentShareRate = args[3] as BigNumber;
diff --git a/features/withdrawals/hooks/useNftDataByTxHash.ts b/features/withdrawals/hooks/useNftDataByTxHash.ts
index 098f719c9..bbfd4ebaf 100644
--- a/features/withdrawals/hooks/useNftDataByTxHash.ts
+++ b/features/withdrawals/hooks/useNftDataByTxHash.ts
@@ -14,13 +14,13 @@ type NFTApiData = {
};
export const useNftDataByTxHash = (txHash: string | null) => {
- const { contractRpc, account } = useWithdrawalsContract();
+ const { contractRpc, address } = useWithdrawalsContract();
const { staticRpcProvider } = useCurrentStaticRpcProvider();
const swrNftApiData = useLidoSWR(
- account && txHash ? ['swr:nft-data-by-tx-hash', txHash, account] : null,
+ address && txHash ? ['swr:nft-data-by-tx-hash', txHash, address] : null,
async () => {
- if (!txHash || !account) return null;
+ if (!txHash || !address) return null;
const txReciept: TransactionReceipt =
await staticRpcProvider.getTransactionReceipt(txHash);
diff --git a/features/withdrawals/hooks/useTvlError.ts b/features/withdrawals/hooks/useTvlError.ts
new file mode 100644
index 000000000..707ae2f21
--- /dev/null
+++ b/features/withdrawals/hooks/useTvlError.ts
@@ -0,0 +1,26 @@
+import { useMemo } from 'react';
+import { useController } from 'react-hook-form';
+import {
+ TvlErrorPayload,
+ ValidationTvlJoke,
+} from '../request/request-form-context/validators';
+import { RequestFormInputType } from 'features/withdrawals/request/request-form-context';
+
+const getTvlError = (error?: unknown) =>
+ error &&
+ typeof error === 'object' &&
+ 'type' in error &&
+ error.type == ValidationTvlJoke.type &&
+ 'payload' in error
+ ? (error.payload as TvlErrorPayload)
+ : { balanceDiffSteth: undefined, tvlDiff: undefined };
+
+export const useTvlError = () => {
+ const {
+ fieldState: { error },
+ } = useController({
+ name: 'amount',
+ });
+
+ return useMemo(() => getTvlError(error), [error]);
+};
diff --git a/features/withdrawals/hooks/useTvlMessage.ts b/features/withdrawals/hooks/useTvlMessage.ts
index f9e0c9804..485bc6b6d 100644
--- a/features/withdrawals/hooks/useTvlMessage.ts
+++ b/features/withdrawals/hooks/useTvlMessage.ts
@@ -2,10 +2,7 @@ import { useMemo } from 'react';
import { formatEther } from '@ethersproject/units';
import { shortenTokenValue } from 'utils';
-import {
- TvlErrorPayload,
- ValidationTvlJoke,
-} from '../request/request-form-context/validators';
+import { useTvlError } from './useTvlError';
const texts: ((amount: string) => string)[] = [
(amount) =>
@@ -17,18 +14,11 @@ const texts: ((amount: string) => string)[] = [
const getText = () => texts[Math.floor(Math.random() * texts.length)];
-export const useTvlMessage = (error?: unknown) => {
+export const useTvlMessage = () => {
// To render one text per page before refresh
const textTemplate = useMemo(() => getText(), []);
- const { balanceDiffSteth, tvlDiff } =
- error &&
- typeof error === 'object' &&
- 'type' in error &&
- error.type == ValidationTvlJoke.type &&
- 'payload' in error
- ? (error.payload as TvlErrorPayload)
- : { balanceDiffSteth: undefined, tvlDiff: undefined };
+ const { balanceDiffSteth, tvlDiff } = useTvlError();
return {
balanceDiff: balanceDiffSteth,
diff --git a/features/withdrawals/hooks/useWithdrawTxPrice.ts b/features/withdrawals/hooks/useWithdrawTxPrice.ts
index 14af8fd1e..be986487e 100644
--- a/features/withdrawals/hooks/useWithdrawTxPrice.ts
+++ b/features/withdrawals/hooks/useWithdrawTxPrice.ts
@@ -1,7 +1,7 @@
import { useMemo } from 'react';
import { BigNumber } from 'ethers';
import invariant from 'tiny-invariant';
-import { useWeb3 } from 'reef-knot/web3-react';
+import { useAccount } from 'wagmi';
import { TOKENS } from '@lido-sdk/constants';
import { useLidoSWR, useSDK } from '@lido-sdk/react';
@@ -109,7 +109,7 @@ export const useRequestTxPrice = ({
export const useClaimTxPrice = (requests: RequestStatusClaimable[]) => {
const { contractRpc } = useWithdrawalsContract();
- const { account, chainId } = useWeb3();
+ const { address, chainId } = useAccount();
const requestCount = requests.length || 1;
const debouncedSortedSelectedRequests = useDebouncedValue(requests, 2000);
@@ -118,13 +118,13 @@ export const useClaimTxPrice = (requests: RequestStatusClaimable[]) => {
[
'swr:claim-request-gas-limit',
debouncedSortedSelectedRequests,
- account,
+ address,
chainId,
],
async () => {
if (
!chainId ||
- !account ||
+ !address ||
!contractRpc ||
debouncedSortedSelectedRequests.length === 0
)
@@ -135,12 +135,12 @@ export const useClaimTxPrice = (requests: RequestStatusClaimable[]) => {
.claimWithdrawals(
sortedRequests.map((r) => r.id),
sortedRequests.map((r) => r.hint),
- { from: account },
+ { from: address },
)
.catch((error) => {
console.warn('Could not estimate gas for claim', {
ids: sortedRequests.map((r) => r.id),
- account,
+ address,
error,
});
return undefined;
diff --git a/features/withdrawals/request/form/controls/input-group-request.tsx b/features/withdrawals/request/form/controls/input-group-request.tsx
index 5a5e7d516..290eb7421 100644
--- a/features/withdrawals/request/form/controls/input-group-request.tsx
+++ b/features/withdrawals/request/form/controls/input-group-request.tsx
@@ -1,14 +1,9 @@
import { FC, PropsWithChildren } from 'react';
import { useTvlMessage } from 'features/withdrawals/hooks';
-import { useFormState } from 'react-hook-form';
import { InputGroupHookForm } from 'shared/hook-form/controls/input-group-hook-form';
-import { RequestFormInputType } from '../../request-form-context';
export const InputGroupRequest: FC = ({ children }) => {
- const {
- errors: { amount: amountError },
- } = useFormState({ name: 'amount' });
- const { tvlMessage } = useTvlMessage(amountError);
+ const { tvlMessage } = useTvlMessage();
return (
{children}
diff --git a/features/withdrawals/request/form/controls/token-amount-input-request.tsx b/features/withdrawals/request/form/controls/token-amount-input-request.tsx
index ab5e9b255..da15fffa6 100644
--- a/features/withdrawals/request/form/controls/token-amount-input-request.tsx
+++ b/features/withdrawals/request/form/controls/token-amount-input-request.tsx
@@ -1,4 +1,4 @@
-import { useController, useWatch } from 'react-hook-form';
+import { useWatch } from 'react-hook-form';
import { MATOMO_CLICK_EVENTS_TYPES } from 'consts/matomo-click-events';
import { InputDecoratorTvlStake } from 'features/withdrawals/shared/input-decorator-tvl-stake';
@@ -17,13 +17,7 @@ export const TokenAmountInputRequest = () => {
const token = useWatch({ name: 'token' });
const { maxAmount, isTokenLocked } = useRequestFormData();
- const {
- fieldState: { error },
- } = useController({
- name: 'amount',
- });
-
- const { balanceDiff } = useTvlMessage(error);
+ const { balanceDiff } = useTvlMessage();
return (
= (props) => {
const [showMore, setShowMore] = useState(false);
const [buttonText, setButtonText] = useState('See all options');
+
+ const { balanceDiffSteth } = useTvlError();
+ const isPausedByTvlError = balanceDiffSteth !== undefined;
+
const { data, initialLoading, amount, selectedToken, enabledDexes } =
- useWithdrawalRates();
+ useWithdrawalRates({
+ isPaused: isPausedByTvlError,
+ });
const isAnyDexEnabled = enabledDexes.length > 0;
const allowExpand = enabledDexes.length > MAX_SHOWN_ELEMENTS;
+ const showLoader = !isPausedByTvlError && isAnyDexEnabled && initialLoading;
+ const showList = !isPausedByTvlError && isAnyDexEnabled && !initialLoading;
+ const showPausedList = isPausedByTvlError;
+
+ const dexesListData = useMemo(() => {
+ if (showList) return data;
+ if (showPausedList) {
+ return enabledDexes.map((dexId) => ({
+ ...getDexConfig(dexId),
+ toReceive: null,
+ rate: null,
+ }));
+ }
+ return null;
+ }, [data, enabledDexes, showList, showPausedList]);
+
return (
<>
Aggregator's prices are not available now
)}
- {isAnyDexEnabled &&
- initialLoading &&
- enabledDexes.map((_, i) => )}
- {isAnyDexEnabled &&
- !initialLoading &&
- data?.map(({ title, toReceive, link, rate, matomoEvent, icon }) => {
- return (
- trackMatomoEvent(matomoEvent)}
- url={link(amount, selectedToken)}
- key={title}
- toReceive={rate ? toReceive : null}
- />
- );
- })}
+ {showLoader && enabledDexes.map((_, i) => )}
+ {(showList || showPausedList) &&
+ dexesListData?.map(
+ ({ title, toReceive, link, rate, matomoEvent, icon }) => {
+ return (
+ trackMatomoEvent(matomoEvent)}
+ url={link(amount, selectedToken)}
+ key={title}
+ toReceive={rate ? toReceive : null}
+ />
+ );
+ },
+ )}
{allowExpand && (
(Math.floor(num * 10000) / 10000).toString();
const DexButton: React.FC = ({ isActive, onClick }) => {
+ const { balanceDiffSteth } = useTvlError();
+ const isPausedByTvlError = balanceDiffSteth !== undefined;
const { initialLoading, bestRate, enabledDexes } = useWithdrawalRates({
+ isPaused: isPausedByTvlError,
fallbackValue: DEFAULT_VALUE_FOR_RATE,
});
const isAnyDexEnabled = enabledDexes.length > 0;
+ const bestRateFloored = bestRate !== null && toFloor(bestRate);
const bestRateValue =
- bestRate && isAnyDexEnabled ? `1 : ${toFloor(bestRate)}` : '—';
+ !isPausedByTvlError &&
+ isAnyDexEnabled &&
+ bestRateFloored &&
+ bestRateFloored !== '0'
+ ? `1 : ${bestRateFloored}`
+ : '—';
+
return (
= ({ isActive, onClick }) => {
Best Rate:
- {initialLoading ? : bestRateValue}
+ {initialLoading && !isPausedByTvlError ? (
+
+ ) : (
+ bestRateValue
+ )}
Waiting time:{' '}
diff --git a/features/withdrawals/request/form/transaction-info.tsx b/features/withdrawals/request/form/transaction-info.tsx
index 995b806ae..1b0b53e8d 100644
--- a/features/withdrawals/request/form/transaction-info.tsx
+++ b/features/withdrawals/request/form/transaction-info.tsx
@@ -1,21 +1,23 @@
+import { useWatch } from 'react-hook-form';
import { TOKENS } from '@lido-sdk/constants';
import { DataTableRow } from '@lidofinance/lido-ui';
+
import { useRequestTxPrice } from 'features/withdrawals/hooks/useWithdrawTxPrice';
import { useApproveGasLimit } from 'features/wsteth/wrap/hooks/use-approve-gas-limit';
-import { useWatch } from 'react-hook-form';
+import { useDappStatus } from 'shared/hooks/use-dapp-status';
+import { AllowanceDataTableRow } from 'shared/components/allowance-data-table-row';
import { DataTableRowStethByWsteth } from 'shared/components/data-table-row-steth-by-wsteth';
import { FormatPrice } from 'shared/formatters';
import { useTxCostInUsd } from 'shared/hooks';
+
import {
RequestFormInputType,
useRequestFormData,
useValidationResults,
} from '../request-form-context';
-import { useWeb3 } from 'reef-knot/web3-react';
-import { AllowanceDataTableRow } from 'shared/components/allowance-data-table-row';
export const TransactionInfo = () => {
- const { active } = useWeb3();
+ const { isDappActive } = useDappStatus();
const { isApprovalFlow, isApprovalFlowLoading, allowance } =
useRequestFormData();
const token = useWatch({ name: 'token' });
@@ -55,7 +57,7 @@ export const TransactionInfo = () => {
data-testid="allowance"
token={token}
allowance={allowance}
- isBlank={!active}
+ isBlank={!isDappActive}
loading={isApprovalFlowLoading}
/>
{token === TOKENS.STETH ? (
diff --git a/features/withdrawals/request/request-form-context/use-request-form-data-context-value.ts b/features/withdrawals/request/request-form-context/use-request-form-data-context-value.ts
index 2d88b5683..86bddb7ac 100644
--- a/features/withdrawals/request/request-form-context/use-request-form-data-context-value.ts
+++ b/features/withdrawals/request/request-form-context/use-request-form-data-context-value.ts
@@ -1,14 +1,10 @@
-import {
- useSTETHContractRPC,
- useSTETHBalance,
- useWSTETHBalance,
- useContractSWR,
-} from '@lido-sdk/react';
+import { useSTETHContractRPC, useContractSWR } from '@lido-sdk/react';
import { useClaimData } from 'features/withdrawals/contexts/claim-data-context';
import { useWithdrawals } from 'features/withdrawals/contexts/withdrawals-context';
import { useUnfinalizedStETH } from 'features/withdrawals/hooks';
import { useCallback, useMemo } from 'react';
import { useWstethBySteth } from 'shared/hooks';
+import { useStethBalance, useWstethBalance } from 'shared/hooks/use-balance';
import { STRATEGY_LAZY } from 'consts/swr-strategies';
// Provides all data fetching for form to function
@@ -28,14 +24,14 @@ export const useRequestFormDataContextValue = () => {
} = useWithdrawals();
const {
data: balanceSteth,
- update: stethUpdate,
- initialLoading: isStethBalanceLoading,
- } = useSTETHBalance(STRATEGY_LAZY);
+ refetch: stethUpdate,
+ isLoading: isStethBalanceLoading,
+ } = useStethBalance();
const {
data: balanceWSteth,
- update: wstethUpdate,
- initialLoading: isWstethBalanceLoading,
- } = useWSTETHBalance(STRATEGY_LAZY);
+ refetch: wstethUpdate,
+ isLoading: isWstethBalanceLoading,
+ } = useWstethBalance();
const {
data: unfinalizedStETH,
update: unfinalizedStETHUpdate,
diff --git a/features/withdrawals/request/request-form-context/use-validation-context.ts b/features/withdrawals/request/request-form-context/use-validation-context.ts
index af171e763..904523adc 100644
--- a/features/withdrawals/request/request-form-context/use-validation-context.ts
+++ b/features/withdrawals/request/request-form-context/use-validation-context.ts
@@ -1,23 +1,23 @@
+import { useMemo } from 'react';
import {
MAX_REQUESTS_COUNT_LEDGER_LIMIT,
MAX_REQUESTS_COUNT,
} from 'features/withdrawals/withdrawals-constants';
-import { useMemo } from 'react';
import { useIsLedgerLive } from 'shared/hooks/useIsLedgerLive';
import { useAwaiter } from 'shared/hooks/use-awaiter';
+import { useDappStatus } from 'shared/hooks/use-dapp-status';
import type {
RequestFormDataType,
RequestFormValidationAsyncContextType,
RequestFormValidationContextType,
} from './types';
-import { useWeb3 } from 'reef-knot/web3-react';
// Prepares validation context object from request form data
export const useValidationContext = (
requestData: RequestFormDataType,
setIntermediateValidationResults: RequestFormValidationContextType['setIntermediateValidationResults'],
): RequestFormValidationContextType => {
- const { active } = useWeb3();
+ const { isDappActive } = useDappStatus();
const isLedgerLive = useIsLedgerLive();
const maxRequestCount = isLedgerLive
? MAX_REQUESTS_COUNT_LEDGER_LIMIT
@@ -68,7 +68,7 @@ export const useValidationContext = (
useAwaiter(context).awaiter;
return {
- isWalletActive: active,
+ isWalletActive: isDappActive,
asyncContext,
setIntermediateValidationResults,
};
diff --git a/features/withdrawals/request/withdrawal-rates/use-withdrawal-rates.ts b/features/withdrawals/request/withdrawal-rates/use-withdrawal-rates.ts
index 36d9da023..39128bedf 100644
--- a/features/withdrawals/request/withdrawal-rates/use-withdrawal-rates.ts
+++ b/features/withdrawals/request/withdrawal-rates/use-withdrawal-rates.ts
@@ -20,6 +20,7 @@ import { useConfig } from 'config';
export type useWithdrawalRatesOptions = {
fallbackValue?: BigNumber;
+ isPaused?: boolean;
};
const getWithdrawalRates = async (
@@ -52,6 +53,7 @@ const getWithdrawalRates = async (
export const useWithdrawalRates = ({
fallbackValue = Zero,
+ isPaused,
}: useWithdrawalRatesOptions = {}) => {
const [token, amount] = useWatch({
name: ['token', 'amount'],
@@ -71,6 +73,7 @@ export const useWithdrawalRates = ({
{
...STRATEGY_LAZY,
isPaused: () =>
+ isPaused ||
!debouncedAmount ||
!debouncedAmount._isBigNumber ||
enabledDexes.length === 0,
diff --git a/features/withdrawals/withdrawals-constants/index.ts b/features/withdrawals/withdrawals-constants/index.ts
index 72fd896a5..1a8112fb2 100644
--- a/features/withdrawals/withdrawals-constants/index.ts
+++ b/features/withdrawals/withdrawals-constants/index.ts
@@ -1,5 +1,6 @@
// max requests count for one tx
export const MAX_REQUESTS_COUNT = 256;
+// Leger Clear Sign only allows 2 requests per claim
export const MAX_REQUESTS_COUNT_LEDGER_LIMIT = 2;
export const DEFAULT_CLAIM_REQUEST_SELECTED = 80;
diff --git a/features/wsteth/shared/wallet/wallet.tsx b/features/wsteth/shared/wallet/wallet.tsx
index 3f9276051..175e670da 100644
--- a/features/wsteth/shared/wallet/wallet.tsx
+++ b/features/wsteth/shared/wallet/wallet.tsx
@@ -2,15 +2,8 @@ import { memo } from 'react';
import { Divider, Text } from '@lidofinance/lido-ui';
import { TOKENS } from '@lido-sdk/constants';
-import {
- useSDK,
- useEthereumBalance,
- useSTETHBalance,
- useWSTETHBalance,
- useTokenAddress,
-} from '@lido-sdk/react';
+import { useSDK, useTokenAddress } from '@lido-sdk/react';
-import { STRATEGY_LAZY } from 'consts/swr-strategies';
import { FormatToken } from 'shared/formatters';
import { TokenToWallet } from 'shared/components';
import { useWstethBySteth, useStethByWsteth } from 'shared/hooks';
@@ -26,12 +19,17 @@ import {
} from 'shared/wallet';
import { StyledCard } from './styles';
+import {
+ useEthereumBalance,
+ useStethBalance,
+ useWstethBalance,
+} from 'shared/hooks/use-balance';
const WalletComponent: WalletComponentType = (props) => {
const { account } = useSDK();
- const ethBalance = useEthereumBalance(undefined, STRATEGY_LAZY);
- const stethBalance = useSTETHBalance(STRATEGY_LAZY);
- const wstethBalance = useWSTETHBalance(STRATEGY_LAZY);
+ const ethBalance = useEthereumBalance();
+ const stethBalance = useStethBalance();
+ const wstethBalance = useWstethBalance();
const stethAddress = useTokenAddress(TOKENS.STETH);
const wstethAddress = useTokenAddress(TOKENS.WSTETH);
@@ -44,7 +42,7 @@ const WalletComponent: WalletComponentType = (props) => {
{
{
{
- const { active } = useWeb3();
+ const { isDappActive } = useDappStatus();
const { maxAmount } = networkData;
const validationContextAwaited = useMemo(() => {
- if (active && !maxAmount) {
+ if (isDappActive && !maxAmount) {
return undefined;
}
return {
- isWalletActive: active,
+ isWalletActive: isDappActive,
maxAmount,
};
- }, [active, maxAmount]);
+ }, [isDappActive, maxAmount]);
return useAwaiter(validationContextAwaited).awaiter;
};
diff --git a/features/wsteth/unwrap/hooks/use-unwrap-form-network-data.ts b/features/wsteth/unwrap/hooks/use-unwrap-form-network-data.ts
index 284d80061..6bbe9e9a4 100644
--- a/features/wsteth/unwrap/hooks/use-unwrap-form-network-data.ts
+++ b/features/wsteth/unwrap/hooks/use-unwrap-form-network-data.ts
@@ -1,14 +1,12 @@
import { useCallback, useMemo } from 'react';
import { useIsMultisig } from 'shared/hooks/useIsMultisig';
-import { useSTETHBalance, useWSTETHBalance } from '@lido-sdk/react';
-import { STRATEGY_LAZY } from 'consts/swr-strategies';
+import { useStethBalance, useWstethBalance } from 'shared/hooks/use-balance';
export const useUnwrapFormNetworkData = () => {
const { isMultisig } = useIsMultisig();
- const { data: stethBalance, update: stethBalanceUpdate } =
- useSTETHBalance(STRATEGY_LAZY);
- const { data: wstethBalance, update: wstethBalanceUpdate } =
- useWSTETHBalance(STRATEGY_LAZY);
+ const { data: stethBalance, refetch: stethBalanceUpdate } = useStethBalance();
+ const { data: wstethBalance, refetch: wstethBalanceUpdate } =
+ useWstethBalance();
const revalidateUnwrapFormData = useCallback(async () => {
await Promise.allSettled([stethBalanceUpdate(), wstethBalanceUpdate()]);
diff --git a/features/wsteth/unwrap/hooks/use-unwrap-form-processing.ts b/features/wsteth/unwrap/hooks/use-unwrap-form-processing.ts
index 21450e3f5..9c99fc485 100644
--- a/features/wsteth/unwrap/hooks/use-unwrap-form-processing.ts
+++ b/features/wsteth/unwrap/hooks/use-unwrap-form-processing.ts
@@ -1,18 +1,25 @@
+import { useCallback } from 'react';
import invariant from 'tiny-invariant';
+import { useAccount } from 'wagmi';
-import { useCallback } from 'react';
-import { useSTETHContractRPC, useWSTETHContractRPC } from '@lido-sdk/react';
-import { useWeb3 } from 'reef-knot/web3-react';
-import { useUnwrapTxProcessing } from './use-unwrap-tx-processing';
-import { useTxModalStagesUnwrap } from './use-tx-modal-stages-unwrap';
+import {
+ useSDK,
+ useSTETHContractRPC,
+ useWSTETHContractRPC,
+ useWSTETHContractWeb3,
+} from '@lido-sdk/react';
+import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider';
import { isContract } from 'utils/isContract';
import { runWithTransactionLogger } from 'utils';
+
import type { UnwrapFormInputType } from '../unwrap-form-context';
-import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider';
+import { useTxModalStagesUnwrap } from './use-tx-modal-stages-unwrap';
+import { sendTx } from 'utils/send-tx';
+import { useTxConfirmation } from 'shared/hooks/use-tx-conformation';
type UseUnwrapFormProcessorArgs = {
- onConfirm?: () => Promise;
+ onConfirm: () => Promise;
onRetry?: () => void;
};
@@ -20,25 +27,43 @@ export const useUnwrapFormProcessor = ({
onConfirm,
onRetry,
}: UseUnwrapFormProcessorArgs) => {
- const { account } = useWeb3();
+ const { address } = useAccount();
+ const { providerWeb3 } = useSDK();
const { staticRpcProvider } = useCurrentStaticRpcProvider();
- const processWrapTx = useUnwrapTxProcessing();
+ const { txModalStages } = useTxModalStagesUnwrap();
const stETHContractRPC = useSTETHContractRPC();
const wstETHContractRPC = useWSTETHContractRPC();
- const { txModalStages } = useTxModalStagesUnwrap();
+ const wstethContractWeb3 = useWSTETHContractWeb3();
+ const waitForTx = useTxConfirmation();
return useCallback(
async ({ amount }: UnwrapFormInputType) => {
try {
invariant(amount, 'amount should be presented');
- invariant(account, 'address should be presented');
- const isMultisig = await isContract(account, staticRpcProvider);
- const willReceive = await wstETHContractRPC.getStETHByWstETH(amount);
+ invariant(address, 'address should be presented');
+ invariant(providerWeb3, 'providerWeb3 must be presented');
+ invariant(wstethContractWeb3, 'must have wstethContractWeb3');
+
+ const [isMultisig, willReceive] = await Promise.all([
+ isContract(address, staticRpcProvider),
+ wstETHContractRPC.getStETHByWstETH(amount),
+ ]);
txModalStages.sign(amount, willReceive);
- const txHash = await runWithTransactionLogger('Unwrap signing', () =>
- processWrapTx({ amount, isMultisig }),
+ const txHash = await runWithTransactionLogger(
+ 'Unwrap signing',
+ async () => {
+ const tx =
+ await wstethContractWeb3.populateTransaction.unwrap(amount);
+
+ return sendTx({
+ tx,
+ isMultisig,
+ staticProvider: staticRpcProvider,
+ walletProvider: providerWeb3,
+ });
+ },
);
if (isMultisig) {
@@ -48,13 +73,15 @@ export const useUnwrapFormProcessor = ({
txModalStages.pending(amount, willReceive, txHash);
- await runWithTransactionLogger('Unwrap block confirmation', async () =>
- staticRpcProvider.waitForTransaction(txHash),
+ await runWithTransactionLogger('Unwrap block confirmation', () =>
+ waitForTx(txHash),
);
- const stethBalance = await stETHContractRPC.balanceOf(account);
+ const [stethBalance] = await Promise.all([
+ stETHContractRPC.balanceOf(address),
+ onConfirm(),
+ ]);
- await onConfirm?.();
txModalStages.success(stethBalance, txHash);
return true;
} catch (error: any) {
@@ -64,13 +91,15 @@ export const useUnwrapFormProcessor = ({
}
},
[
- account,
+ address,
+ providerWeb3,
+ wstethContractWeb3,
+ staticRpcProvider,
wstETHContractRPC,
txModalStages,
stETHContractRPC,
onConfirm,
- processWrapTx,
- staticRpcProvider,
+ waitForTx,
onRetry,
],
);
diff --git a/features/wsteth/unwrap/hooks/use-unwrap-tx-processing.ts b/features/wsteth/unwrap/hooks/use-unwrap-tx-processing.ts
deleted file mode 100644
index eb0742eed..000000000
--- a/features/wsteth/unwrap/hooks/use-unwrap-tx-processing.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { useCallback } from 'react';
-import invariant from 'tiny-invariant';
-
-import { useSDK, useWSTETHContractWeb3 } from '@lido-sdk/react';
-
-import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider';
-
-import type { UnwrapFormInputType } from '../unwrap-form-context';
-import { sendTx } from 'utils/send-tx';
-
-type UnwrapTxProcessorArgs = Omit & {
- isMultisig: boolean;
-};
-
-export const useUnwrapTxProcessing = () => {
- const { chainId, providerWeb3 } = useSDK();
- const { staticRpcProvider } = useCurrentStaticRpcProvider();
- const wstethContractWeb3 = useWSTETHContractWeb3();
-
- return useCallback(
- async ({ isMultisig, amount }: UnwrapTxProcessorArgs) => {
- invariant(amount, 'amount id must be presented');
- invariant(chainId, 'chain id must be presented');
- invariant(providerWeb3, 'providerWeb3 must be presented');
- invariant(wstethContractWeb3, 'must have wstethContractWeb3');
-
- const tx = await wstethContractWeb3.populateTransaction.unwrap(amount);
-
- return sendTx({
- tx,
- isMultisig,
- staticProvider: staticRpcProvider,
- walletProvider: providerWeb3,
- });
- },
- [chainId, providerWeb3, staticRpcProvider, wstethContractWeb3],
- );
-};
diff --git a/features/wsteth/wrap/hooks/use-approve-gas-limit.tsx b/features/wsteth/wrap/hooks/use-approve-gas-limit.tsx
index 3a5dbec3f..68f8cc380 100644
--- a/features/wsteth/wrap/hooks/use-approve-gas-limit.tsx
+++ b/features/wsteth/wrap/hooks/use-approve-gas-limit.tsx
@@ -1,5 +1,5 @@
import { BigNumber } from 'ethers';
-import { useWeb3 } from 'reef-knot/web3-react';
+import { useAccount } from 'wagmi';
import {
useLidoSWR,
useSTETHContractRPC,
@@ -13,7 +13,7 @@ import { STRATEGY_IMMUTABLE } from 'consts/swr-strategies';
export const useApproveGasLimit = () => {
const steth = useSTETHContractRPC();
const wsteth = useWSTETHContractRPC();
- const { chainId } = useWeb3();
+ const { chainId } = useAccount();
const { data } = useLidoSWR(
['swr:approve-wrap-gas-limit', chainId],
diff --git a/features/wsteth/wrap/hooks/use-wrap-form-network-data.ts b/features/wsteth/wrap/hooks/use-wrap-form-network-data.ts
index b437f6b75..b0da4caf7 100644
--- a/features/wsteth/wrap/hooks/use-wrap-form-network-data.ts
+++ b/features/wsteth/wrap/hooks/use-wrap-form-network-data.ts
@@ -1,29 +1,24 @@
import { useCallback, useMemo } from 'react';
-import {
- useWSTETHBalance,
- useSTETHBalance,
- useEthereumBalance,
-} from '@lido-sdk/react';
import { config } from 'config';
-import { STRATEGY_LAZY } from 'consts/swr-strategies';
import { useIsMultisig } from 'shared/hooks/useIsMultisig';
import { useTokenMaxAmount } from 'shared/hooks/use-token-max-amount';
import { useMaxGasPrice, useStakingLimitInfo } from 'shared/hooks';
import { useWrapGasLimit } from './use-wrap-gas-limit';
+import {
+ useEthereumBalance,
+ useStethBalance,
+ useWstethBalance,
+} from 'shared/hooks/use-balance';
// Provides all data fetching for form to function
export const useWrapFormNetworkData = () => {
const { isMultisig, isLoading: isMultisigLoading } = useIsMultisig();
- const { data: ethBalance, update: ethBalanceUpdate } = useEthereumBalance(
- undefined,
- STRATEGY_LAZY,
- );
- const { data: stethBalance, update: stethBalanceUpdate } =
- useSTETHBalance(STRATEGY_LAZY);
- const { data: wstethBalance, update: wstethBalanceUpdate } =
- useWSTETHBalance(STRATEGY_LAZY);
+ const { data: ethBalance, refetch: ethBalanceUpdate } = useEthereumBalance();
+ const { data: stethBalance, refetch: stethBalanceUpdate } = useStethBalance();
+ const { data: wstethBalance, refetch: wstethBalanceUpdate } =
+ useWstethBalance();
const { data: stakeLimitInfo, mutate: stakeLimitInfoUpdate } =
useStakingLimitInfo();
diff --git a/features/wsteth/wrap/hooks/use-wrap-form-processing.ts b/features/wsteth/wrap/hooks/use-wrap-form-processing.ts
index 3c5daa786..ca9c4e423 100644
--- a/features/wsteth/wrap/hooks/use-wrap-form-processing.ts
+++ b/features/wsteth/wrap/hooks/use-wrap-form-processing.ts
@@ -1,22 +1,24 @@
+import { useCallback } from 'react';
import invariant from 'tiny-invariant';
+import { useAccount } from 'wagmi';
-import { useCallback } from 'react';
-import { useWeb3 } from 'reef-knot/web3-react';
-import { useWrapTxProcessing } from './use-wrap-tx-processing';
-import { useTxModalWrap } from './use-tx-modal-stages-wrap';
-import { useWSTETHContractRPC } from '@lido-sdk/react';
+import { useSDK, useWSTETHContractRPC } from '@lido-sdk/react';
+import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider';
import { runWithTransactionLogger } from 'utils';
import { isContract } from 'utils/isContract';
+import { useTxConfirmation } from 'shared/hooks/use-tx-conformation';
+
import type {
WrapFormApprovalData,
WrapFormInputType,
} from '../wrap-form-context';
-import { useCurrentStaticRpcProvider } from 'shared/hooks/use-current-static-rpc-provider';
+import { useWrapTxProcessing } from './use-wrap-tx-processing';
+import { useTxModalWrap } from './use-tx-modal-stages-wrap';
type UseWrapFormProcessorArgs = {
approvalData: WrapFormApprovalData;
- onConfirm?: () => Promise;
+ onConfirm: () => Promise;
onRetry?: () => void;
};
@@ -25,20 +27,27 @@ export const useWrapFormProcessor = ({
onConfirm,
onRetry,
}: UseWrapFormProcessorArgs) => {
- const { account } = useWeb3();
+ const { address } = useAccount();
+ const { providerWeb3 } = useSDK();
+ const { staticRpcProvider } = useCurrentStaticRpcProvider();
+ const wstETHContractRPC = useWSTETHContractRPC();
+
+ const { txModalStages } = useTxModalWrap();
const processWrapTx = useWrapTxProcessing();
+ const waitForTx = useTxConfirmation();
const { isApprovalNeededBeforeWrap, processApproveTx } = approvalData;
- const { txModalStages } = useTxModalWrap();
- const wstETHContractRPC = useWSTETHContractRPC();
- const { staticRpcProvider } = useCurrentStaticRpcProvider();
return useCallback(
async ({ amount, token }: WrapFormInputType) => {
try {
invariant(amount, 'amount should be presented');
- invariant(account, 'address should be presented');
- const isMultisig = await isContract(account, staticRpcProvider);
- const willReceive = await wstETHContractRPC.getWstETHByStETH(amount);
+ invariant(address, 'address should be presented');
+ invariant(providerWeb3, 'providerWeb3 should be presented');
+
+ const [isMultisig, willReceive] = await Promise.all([
+ isContract(address, staticRpcProvider),
+ wstETHContractRPC.getWstETHByStETH(amount),
+ ]);
if (isApprovalNeededBeforeWrap) {
txModalStages.signApproval(amount, token);
@@ -70,12 +79,14 @@ export const useWrapFormProcessor = ({
txModalStages.pending(amount, token, willReceive, txHash);
await runWithTransactionLogger('Wrap block confirmation', () =>
- staticRpcProvider.waitForTransaction(txHash),
+ waitForTx(txHash),
);
- const wstethBalance = await wstETHContractRPC.balanceOf(account);
+ const [wstethBalance] = await Promise.all([
+ wstETHContractRPC.balanceOf(address),
+ onConfirm(),
+ ]);
- await onConfirm?.();
txModalStages.success(wstethBalance, txHash);
return true;
} catch (error) {
@@ -85,14 +96,16 @@ export const useWrapFormProcessor = ({
}
},
[
- account,
+ address,
+ providerWeb3,
+ staticRpcProvider,
wstETHContractRPC,
isApprovalNeededBeforeWrap,
txModalStages,
onConfirm,
processApproveTx,
processWrapTx,
- staticRpcProvider,
+ waitForTx,
onRetry,
],
);
diff --git a/features/wsteth/wrap/hooks/use-wrap-form-validation-context.ts b/features/wsteth/wrap/hooks/use-wrap-form-validation-context.ts
index 6ad2763f3..e044da344 100644
--- a/features/wsteth/wrap/hooks/use-wrap-form-validation-context.ts
+++ b/features/wsteth/wrap/hooks/use-wrap-form-validation-context.ts
@@ -1,5 +1,5 @@
import { useMemo } from 'react';
-import { useWeb3 } from 'reef-knot/web3-react';
+import { useDappStatus } from 'shared/hooks/use-dapp-status';
import { useAwaiter } from 'shared/hooks/use-awaiter';
import type {
@@ -15,7 +15,7 @@ type UseWrapFormValidationContextArgs = {
export const useWrapFormValidationContext = ({
networkData,
}: UseWrapFormValidationContextArgs): WrapFormValidationContext => {
- const { active } = useWeb3();
+ const { isDappActive } = useDappStatus();
const {
stakeLimitInfo,
ethBalance,
@@ -24,7 +24,7 @@ export const useWrapFormValidationContext = ({
wrapEthGasCost,
} = networkData;
- const waitForAccountData = active
+ const waitForAccountData = isDappActive
? stethBalance && ethBalance && isMultisig !== undefined
: true;
@@ -38,7 +38,7 @@ export const useWrapFormValidationContext = ({
useMemo(() => {
return isDataReady
? ({
- isWalletActive: active,
+ isWalletActive: isDappActive,
stethBalance,
etherBalance: ethBalance,
isMultisig,
@@ -49,7 +49,7 @@ export const useWrapFormValidationContext = ({
: undefined;
}, [
isDataReady,
- active,
+ isDappActive,
stethBalance,
ethBalance,
isMultisig,
diff --git a/features/wsteth/wrap/hooks/use-wrap-gas-limit.ts b/features/wsteth/wrap/hooks/use-wrap-gas-limit.ts
index 60d44f792..4433fc87e 100644
--- a/features/wsteth/wrap/hooks/use-wrap-gas-limit.ts
+++ b/features/wsteth/wrap/hooks/use-wrap-gas-limit.ts
@@ -1,4 +1,4 @@
-import { useWeb3 } from 'reef-knot/web3-react';
+import { useAccount } from 'wagmi';
import { useLidoSWR, useWSTETHContractRPC } from '@lido-sdk/react';
import { config } from 'config';
@@ -8,7 +8,7 @@ import { applyGasLimitRatio } from 'utils/apply-gas-limit-ratio';
export const useWrapGasLimit = () => {
const wsteth = useWSTETHContractRPC();
- const { chainId } = useWeb3();
+ const { chainId } = useAccount();
const { staticRpcProvider } = useCurrentStaticRpcProvider();
const { data } = useLidoSWR(
diff --git a/features/wsteth/wrap/hooks/use-wrap-tx-approve.ts b/features/wsteth/wrap/hooks/use-wrap-tx-approve.ts
index ada13cc5e..f8fd6396f 100644
--- a/features/wsteth/wrap/hooks/use-wrap-tx-approve.ts
+++ b/features/wsteth/wrap/hooks/use-wrap-tx-approve.ts
@@ -1,11 +1,13 @@
import { useMemo } from 'react';
-import { useWeb3 } from 'reef-knot/web3-react';
-import { useSDK } from '@lido-sdk/react';
-import { useApprove } from 'shared/hooks/useApprove';
-
+import { useAccount } from 'wagmi';
import type { BigNumber } from 'ethers';
+
import { getTokenAddress, TOKENS } from '@lido-sdk/constants';
+import { useSDK } from '@lido-sdk/react';
+
import { TokensWrappable, TOKENS_TO_WRAP } from 'features/wsteth/shared/types';
+import { useApprove } from 'shared/hooks/useApprove';
+import { useDappStatus } from 'shared/hooks/use-dapp-status';
type UseWrapTxApproveArgs = {
amount: BigNumber;
@@ -13,7 +15,8 @@ type UseWrapTxApproveArgs = {
};
export const useWrapTxApprove = ({ amount, token }: UseWrapTxApproveArgs) => {
- const { active, account } = useWeb3();
+ const { isDappActive } = useDappStatus();
+ const { address } = useAccount();
const { chainId } = useSDK();
const [stethTokenAddress, wstethTokenAddress] = useMemo(
@@ -28,16 +31,17 @@ export const useWrapTxApprove = ({ amount, token }: UseWrapTxApproveArgs) => {
approve: processApproveTx,
needsApprove,
allowance,
- loading: isApprovalLoading,
+ isLoading: isApprovalLoading,
+ refetch: refetchAllowance,
} = useApprove(
amount,
stethTokenAddress,
wstethTokenAddress,
- account ? account : undefined,
+ address ? address : undefined,
);
const isApprovalNeededBeforeWrap =
- active && needsApprove && token === TOKENS_TO_WRAP.STETH;
+ isDappActive && needsApprove && token === TOKENS_TO_WRAP.STETH;
return useMemo(
() => ({
@@ -46,6 +50,7 @@ export const useWrapTxApprove = ({ amount, token }: UseWrapTxApproveArgs) => {
allowance,
isApprovalLoading,
isApprovalNeededBeforeWrap,
+ refetchAllowance,
}),
[
allowance,
@@ -53,6 +58,7 @@ export const useWrapTxApprove = ({ amount, token }: UseWrapTxApproveArgs) => {
needsApprove,
isApprovalLoading,
processApproveTx,
+ refetchAllowance,
],
);
};
diff --git a/features/wsteth/wrap/wrap-form-context/wrap-form-context.tsx b/features/wsteth/wrap/wrap-form-context/wrap-form-context.tsx
index 245582359..b2bf010d4 100644
--- a/features/wsteth/wrap/wrap-form-context/wrap-form-context.tsx
+++ b/features/wsteth/wrap/wrap-form-context/wrap-form-context.tsx
@@ -5,6 +5,7 @@ import {
useMemo,
createContext,
useContext,
+ useCallback,
} from 'react';
import { useForm, FormProvider } from 'react-hook-form';
import { useWrapTxApprove } from '../hooks/use-wrap-tx-approve';
@@ -72,9 +73,16 @@ export const WrapFormProvider: FC = ({ children }) => {
const approvalData = useWrapTxApprove({ amount: amount ?? Zero, token });
const isSteth = token === TOKENS_TO_WRAP.STETH;
+ const onConfirm = useCallback(async () => {
+ await Promise.allSettled([
+ networkData.revalidateWrapFormData(),
+ approvalData.refetchAllowance(),
+ ]);
+ }, [networkData, approvalData]);
+
const processWrapFormFlow = useWrapFormProcessor({
approvalData,
- onConfirm: networkData.revalidateWrapFormData,
+ onConfirm,
onRetry: retryFire,
});
diff --git a/features/wsteth/wrap/wrap-form/wrap-stats.tsx b/features/wsteth/wrap/wrap-form/wrap-stats.tsx
index 4767eb814..1d26d5e2c 100644
--- a/features/wsteth/wrap/wrap-form/wrap-stats.tsx
+++ b/features/wsteth/wrap/wrap-form/wrap-stats.tsx
@@ -1,5 +1,4 @@
import { useFormContext } from 'react-hook-form';
-import { useWeb3 } from 'reef-knot/web3-react';
import { parseEther } from '@ethersproject/units';
import { DataTable, DataTableRow } from '@lidofinance/lido-ui';
@@ -11,6 +10,7 @@ import { TOKENS_TO_WRAP } from 'features/wsteth/shared/types';
import { AllowanceDataTableRow } from 'shared/components/allowance-data-table-row';
import { FormatPrice, FormatToken } from 'shared/formatters';
import { useTxCostInUsd, useWstethBySteth } from 'shared/hooks';
+import { useDappStatus } from 'shared/hooks/use-dapp-status';
import { useApproveGasLimit } from '../hooks/use-approve-gas-limit';
import { useWrapFormData, WrapFormInputType } from '../wrap-form-context';
@@ -18,7 +18,7 @@ import { useWrapFormData, WrapFormInputType } from '../wrap-form-context';
const oneSteth = parseEther('1');
export const WrapFormStats = () => {
- const { active } = useWeb3();
+ const { isDappActive } = useDappStatus();
const { allowance, wrapGasLimit, isApprovalLoading } = useWrapFormData();
const { watch } = useFormContext();
@@ -82,7 +82,7 @@ export const WrapFormStats = () => {
diff --git a/package.json b/package.json
index 5ca71f1a9..79c3ddb37 100644
--- a/package.json
+++ b/package.json
@@ -33,18 +33,19 @@
"@lido-sdk/helpers": "^1.6.0",
"@lido-sdk/providers": "^1.4.15",
"@lido-sdk/react": "^2.0.6",
- "@lidofinance/analytics-matomo": "^0.41.0",
- "@lidofinance/api-metrics": "^0.41.0",
- "@lidofinance/api-rpc": "^0.41.0",
- "@lidofinance/eth-api-providers": "^0.41.0",
- "@lidofinance/eth-providers": "^0.41.0",
+ "@lidofinance/analytics-matomo": "^0.45.1",
+ "@lidofinance/api-metrics": "^0.45.1",
+ "@lidofinance/api-rpc": "^0.45.1",
+ "@lidofinance/eth-api-providers": "^0.45.1",
+ "@lidofinance/eth-providers": "^0.45.1",
+ "@lidofinance/lido-ethereum-sdk": "^3.4.0",
"@lidofinance/lido-ui": "^3.26.0",
- "@lidofinance/next-api-wrapper": "^0.41.0",
- "@lidofinance/next-ip-rate-limit": "^0.41.0",
- "@lidofinance/next-pages": "^0.41.0",
- "@lidofinance/rpc": "^0.41.0",
- "@lidofinance/satanizer": "^0.41.0",
- "@tanstack/react-query": "^5.48.0",
+ "@lidofinance/next-api-wrapper": "^0.45.1",
+ "@lidofinance/next-ip-rate-limit": "^0.45.1",
+ "@lidofinance/next-pages": "^0.45.1",
+ "@lidofinance/rpc": "^0.45.1",
+ "@lidofinance/satanizer": "^0.45.1",
+ "@tanstack/react-query": "^5.51.21",
"bignumber.js": "9.1.0",
"copy-to-clipboard": "^3.3.1",
"cors": "^2.8.5",
@@ -78,7 +79,7 @@
"tiny-async-pool": "^1.2.0",
"tiny-invariant": "^1.1.0",
"uuid": "^8.3.2",
- "viem": "2.13.3",
+ "viem": "2.18.8",
"wagmi": "2.12.2"
},
"devDependencies": {
diff --git a/pages/withdrawals/[mode].tsx b/pages/withdrawals/[mode].tsx
index 3dacb7c42..b4bf20e70 100644
--- a/pages/withdrawals/[mode].tsx
+++ b/pages/withdrawals/[mode].tsx
@@ -2,15 +2,14 @@ import type { FC } from 'react';
import type { GetStaticPaths } from 'next';
import Head from 'next/head';
-import { Layout } from 'shared/components';
-
import { WithdrawalsTabs } from 'features/withdrawals';
import { WithdrawalsProvider } from 'features/withdrawals/contexts/withdrawals-context';
-import { useWeb3Key } from 'shared/hooks/useWeb3Key';
+import { Layout } from 'shared/components';
+import { useWagmiKey } from 'shared/hooks/use-wagmi-key';
import { getDefaultStaticProps } from 'utilsApi/get-default-static-props';
const Withdrawals: FC = ({ mode }) => {
- const key = useWeb3Key();
+ const key = useWagmiKey();
return (
= ({ mode }) => {
- const key = useWeb3Key();
+ const key = useWagmiKey();
+
return (
> = ({
-
-
- {children}
-
-
+
+
+
+ {children}
+
+
+
diff --git a/providers/ipfs-info-box-statuses.tsx b/providers/ipfs-info-box-statuses.tsx
index 76823e0d0..c79cc6959 100644
--- a/providers/ipfs-info-box-statuses.tsx
+++ b/providers/ipfs-info-box-statuses.tsx
@@ -9,6 +9,7 @@ import {
import { useLidoSWR, useLocalStorage, useSDK } from '@lido-sdk/react';
import invariant from 'tiny-invariant';
+import { config } from 'config';
import { useRpcUrl } from 'config/rpc';
import { SETTINGS_PATH } from 'consts/urls';
import { STRATEGY_LAZY } from 'consts/swr-strategies';
@@ -56,7 +57,7 @@ export const IPFSInfoBoxStatusesProvider: FC = ({
const { data: isRPCAvailableRaw, initialLoading: isLoading } = useLidoSWR(
`rpc-url-check-${rpcUrl}-${chainId}`,
async () => await checkRpcUrl(rpcUrl, chainId),
- STRATEGY_LAZY,
+ { ...STRATEGY_LAZY, isPaused: () => !config.ipfsMode },
);
const isRPCAvailable = isRPCAvailableRaw === true;
diff --git a/providers/lido-sdk.tsx b/providers/lido-sdk.tsx
new file mode 100644
index 000000000..09ebaca09
--- /dev/null
+++ b/providers/lido-sdk.tsx
@@ -0,0 +1,54 @@
+import { createContext, useContext, useMemo } from 'react';
+import { LidoSDKCore } from '@lidofinance/lido-ethereum-sdk/core';
+import {
+ LidoSDKstETH,
+ LidoSDKwstETH,
+} from '@lidofinance/lido-ethereum-sdk/erc20';
+import invariant from 'tiny-invariant';
+import { useChainId, useClient, useConnectorClient } from 'wagmi';
+import { useTokenTransferSubscription } from 'shared/hooks/use-balance';
+import { useGetRpcUrlByChainId } from 'config/rpc';
+
+type LidoSDKContextValue = {
+ core: LidoSDKCore;
+ steth: LidoSDKstETH;
+ wsteth: LidoSDKwstETH;
+ subscribeToTokenUpdates: ReturnType;
+};
+
+const LidoSDKContext = createContext(null);
+LidoSDKContext.displayName = 'LidoSDKContext';
+
+export const useLidoSDK = () => {
+ const value = useContext(LidoSDKContext);
+ invariant(value, 'useLidoSDK was used outside of LidoSDKProvider');
+ return value;
+};
+
+export const LidoSDKProvider = ({ children }: React.PropsWithChildren) => {
+ const subscribe = useTokenTransferSubscription();
+ const publicClient = useClient();
+ const chainId = useChainId();
+ const getRpcUrl = useGetRpcUrlByChainId();
+ const fallbackRpcUrl = !publicClient ? getRpcUrl(chainId) : undefined;
+ const { data: walletClient } = useConnectorClient();
+
+ const sdk = useMemo(() => {
+ const core = new LidoSDKCore({
+ chainId,
+ logMode: 'none',
+ rpcProvider: publicClient as any,
+ web3Provider: walletClient as any,
+ // viem client can be unavailable on ipfs+dev first renders
+ rpcUrls: !publicClient && fallbackRpcUrl ? [fallbackRpcUrl] : undefined,
+ });
+
+ const steth = new LidoSDKstETH({ core });
+ const wsteth = new LidoSDKwstETH({ core });
+
+ return { core, steth, wsteth, subscribeToTokenUpdates: subscribe };
+ }, [chainId, fallbackRpcUrl, publicClient, subscribe, walletClient]);
+ return (
+ {children}
+ );
+};
diff --git a/providers/sdk-legacy.tsx b/providers/sdk-legacy.tsx
index f01e86d86..a42f693dd 100644
--- a/providers/sdk-legacy.tsx
+++ b/providers/sdk-legacy.tsx
@@ -1,13 +1,15 @@
import React, { PropsWithChildren, useEffect, useMemo, useState } from 'react';
-import { useSupportedChains, useWeb3 } from 'reef-knot/web3-react';
-import { useClient, useConfig } from 'wagmi';
+import { useReefKnotContext } from 'reef-knot/core-react';
+// TODO: to remove the 'reef-knot/web3-react' after it will be deprecated
+import { useSupportedChains } from 'reef-knot/web3-react';
+import { useAccount, useClient, useConfig } from 'wagmi';
+import { mainnet } from 'wagmi/chains';
import { Web3Provider } from '@ethersproject/providers';
import { ProviderSDK } from '@lido-sdk/react';
-
-import { mainnet } from 'wagmi/chains';
import { getStaticRpcBatchProvider } from '@lido-sdk/providers';
-import { useReefKnotContext } from 'reef-knot/core-react';
+
+import { useDappStatus } from 'shared/hooks/use-dapp-status';
type SDKLegacyProviderProps = PropsWithChildren<{
defaultChainId: number;
@@ -19,8 +21,9 @@ export const SDKLegacyProvider = ({
defaultChainId,
pollingInterval,
}: SDKLegacyProviderProps) => {
- const { chainId: web3ChainId = defaultChainId, account, active } = useWeb3();
+ const { chainId: wagmiChainId = defaultChainId, address } = useAccount();
const { supportedChains } = useSupportedChains();
+ const { isDappActive } = useDappStatus();
const config = useConfig();
const client = useClient();
const { rpc } = useReefKnotContext();
@@ -40,7 +43,7 @@ export const SDKLegacyProvider = ({
};
const getProviderValue = async () => {
- if (!client || !account || !active) return undefined;
+ if (!client || !address || !isDappActive) return undefined;
const { chain } = client;
const providerTransport = await getProviderTransport();
@@ -65,7 +68,7 @@ export const SDKLegacyProvider = ({
return () => {
isHookMounted = false;
};
- }, [config, config.state, client, account, active, pollingInterval]);
+ }, [config, config.state, client, address, isDappActive, pollingInterval]);
const supportedChainIds = useMemo(
() => supportedChains.map((chain) => chain.chainId),
@@ -73,10 +76,10 @@ export const SDKLegacyProvider = ({
);
const chainId = useMemo(() => {
- return supportedChainIds.indexOf(web3ChainId) > -1
- ? web3ChainId
+ return supportedChainIds.indexOf(wagmiChainId) > -1
+ ? wagmiChainId
: defaultChainId;
- }, [defaultChainId, supportedChainIds, web3ChainId]);
+ }, [defaultChainId, supportedChainIds, wagmiChainId]);
const providerRpc = useMemo(
() => getStaticRpcBatchProvider(chainId, rpc[chainId], 0, pollingInterval),
@@ -102,7 +105,7 @@ export const SDKLegacyProvider = ({
providerWeb3={providerWeb3}
providerRpc={providerRpc}
providerMainnetRpc={providerMainnetRpc}
- account={account ?? undefined}
+ account={address ?? undefined}
>
{children}
diff --git a/providers/web3.tsx b/providers/web3.tsx
index c13000bae..a7abd995f 100644
--- a/providers/web3.tsx
+++ b/providers/web3.tsx
@@ -1,6 +1,6 @@
-import { FC, PropsWithChildren, useMemo } from 'react';
+import { FC, PropsWithChildren, useEffect, useMemo } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
-import { http, WagmiProvider, createConfig } from 'wagmi';
+import { WagmiProvider, createConfig, useConnections } from 'wagmi';
import * as wagmiChains from 'wagmi/chains';
import {
AutoConnect,
@@ -16,12 +16,19 @@ import { CHAINS } from 'consts/chains';
import { ConnectWalletModal } from 'shared/wallet/connect-wallet-modal';
import { SDKLegacyProvider } from './sdk-legacy';
+import { useWeb3Transport } from 'utils/use-web3-transport';
type ChainsList = [wagmiChains.Chain, ...wagmiChains.Chain[]];
const wagmiChainsArray = Object.values(wagmiChains) as any as ChainsList;
-const queryClient = new QueryClient();
+const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ refetchOnWindowFocus: false,
+ },
+ },
+});
const Web3Provider: FC = ({ children }) => {
const {
@@ -63,32 +70,39 @@ const Web3Provider: FC = ({ children }) => {
return getWalletsDataList({
walletsList: WalletsListEthereum,
rpc: backendRPC,
- walletconnectProjectId: walletconnectProjectId,
- defaultChain: defaultChain,
+ walletconnectProjectId,
+ defaultChain,
});
}, [backendRPC, defaultChain, walletconnectProjectId]);
+ const { transportMap, onActiveConnection } = useWeb3Transport(
+ supportedChains,
+ backendRPC,
+ );
+
const wagmiConfig = useMemo(() => {
return createConfig({
chains: supportedChains,
ssr: true,
+ connectors: [],
+
batch: {
- // eth_call's will be batched via multicall contract every 100ms
+ // eth_call's can be batched via multicall contract
multicall: {
- wait: 100,
+ wait: config.PROVIDER_BATCH_TIME,
},
},
multiInjectedProviderDiscovery: false,
pollingInterval: config.PROVIDER_POLLING_INTERVAL,
- transports: supportedChains.reduce(
- (res, curr) => ({
- ...res,
- [curr.id]: http(backendRPC[curr.id], { batch: true }),
- }),
- {},
- ),
+ transports: transportMap,
});
- }, [supportedChains, backendRPC]);
+ }, [supportedChains, transportMap]);
+
+ const [activeConnection] = useConnections({ config: wagmiConfig });
+
+ useEffect(() => {
+ void onActiveConnection(activeConnection ?? null);
+ }, [activeConnection, onActiveConnection]);
return (
// default wagmi autoConnect, MUST be false in our case, because we use custom autoConnect from Reef Knot
diff --git a/shared/hook-form/form-controller/form-controller.tsx b/shared/hook-form/form-controller/form-controller.tsx
index e06b24f60..b1a799249 100644
--- a/shared/hook-form/form-controller/form-controller.tsx
+++ b/shared/hook-form/form-controller/form-controller.tsx
@@ -1,6 +1,8 @@
import { FC, PropsWithChildren, useEffect, useMemo } from 'react';
-import { useWeb3 } from 'reef-knot/web3-react';
import { useFormContext } from 'react-hook-form';
+
+import { useDappStatus } from 'shared/hooks/use-dapp-status';
+
import { useFormControllerContext } from './form-controller-context';
type FormControllerProps = React.ComponentProps<'form'>;
@@ -9,7 +11,7 @@ export const FormController: FC> = ({
children,
...props
}) => {
- const { active } = useWeb3();
+ const { isDappActive } = useDappStatus();
const { handleSubmit, reset: resetDefault } = useFormContext();
const {
onSubmit,
@@ -34,11 +36,11 @@ export const FormController: FC> = ({
// Reset form amount after disconnect wallet
useEffect(() => {
- if (!active) resetDefault();
+ if (!isDappActive) resetDefault();
// reset will be captured when active changes
// so we don't need it in deps
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [active]);
+ }, [isDappActive]);
return (