diff --git a/src/components/transactions/FlowCommons/ApprovalMethodToggleButton.tsx b/src/components/transactions/FlowCommons/ApprovalMethodToggleButton.tsx index 0767b1cdfc..5f68b23e1a 100644 --- a/src/components/transactions/FlowCommons/ApprovalMethodToggleButton.tsx +++ b/src/components/transactions/FlowCommons/ApprovalMethodToggleButton.tsx @@ -10,19 +10,21 @@ import { SvgIcon, Typography, } from '@mui/material'; -import * as React from 'react'; +import { useState } from 'react'; import { ApprovalMethod } from 'src/store/walletSlice'; interface ApprovalMethodToggleButtonProps { currentMethod: ApprovalMethod; - setMethod: (newMethod: ApprovalMethod) => void; + setMethod: (method: ApprovalMethod) => void; + showBatchOption?: boolean; } export const ApprovalMethodToggleButton = ({ currentMethod, setMethod, + showBatchOption = false, }: ApprovalMethodToggleButtonProps) => { - const [anchorEl, setAnchorEl] = React.useState(null); + const [anchorEl, setAnchorEl] = useState(null); const open = Boolean(anchorEl); const handleClick = (event: React.MouseEvent) => { setAnchorEl(event.currentTarget); @@ -36,16 +38,16 @@ export const ApprovalMethodToggleButton = ({ - {currentMethod} + {currentMethod === ApprovalMethod.BATCH && Batch Transaction} + {currentMethod === ApprovalMethod.PERMIT && Signature} + {currentMethod === ApprovalMethod.APPROVE && Transaction} - + {showBatchOption && ( + { + setMethod(ApprovalMethod.BATCH); + handleClose(); + }} + selected={currentMethod === ApprovalMethod.BATCH} + > + + {currentMethod === ApprovalMethod.BATCH && } + + + Batch Transaction + + + )} { - if (currentMethod === ApprovalMethod.APPROVE) { - setMethod(ApprovalMethod.PERMIT); - } + setMethod(ApprovalMethod.PERMIT); handleClose(); }} + selected={currentMethod === ApprovalMethod.PERMIT} > - - {ApprovalMethod.PERMIT} - - {currentMethod === ApprovalMethod.PERMIT && } + {currentMethod === ApprovalMethod.PERMIT && } + + Signed Message + - { - if (currentMethod === ApprovalMethod.PERMIT) { - setMethod(ApprovalMethod.APPROVE); - } + setMethod(ApprovalMethod.APPROVE); handleClose(); }} + selected={currentMethod === ApprovalMethod.APPROVE} > - - {ApprovalMethod.APPROVE} - - {currentMethod === ApprovalMethod.APPROVE && } + {currentMethod === ApprovalMethod.APPROVE && } + + Transaction + diff --git a/src/components/transactions/FlowCommons/RightHelperText.tsx b/src/components/transactions/FlowCommons/RightHelperText.tsx index e401d04e65..64873b448b 100644 --- a/src/components/transactions/FlowCommons/RightHelperText.tsx +++ b/src/components/transactions/FlowCommons/RightHelperText.tsx @@ -12,6 +12,7 @@ import { useShallow } from 'zustand/shallow'; export type RightHelperTextProps = { approvalHash?: string; tryPermit?: boolean; + showBatchOption?: boolean; }; const ExtLinkIcon = () => ( @@ -20,7 +21,11 @@ const ExtLinkIcon = () => ( ); -export const RightHelperText = ({ approvalHash, tryPermit }: RightHelperTextProps) => { +export const RightHelperText = ({ + approvalHash, + tryPermit, + showBatchOption = false, +}: RightHelperTextProps) => { const [ account, walletApprovalMethodPreference, @@ -46,7 +51,7 @@ export const RightHelperText = ({ approvalHash, tryPermit }: RightHelperTextProp if (isContractAddress && walletApprovalMethodPreference === ApprovalMethod.PERMIT) { setWalletApprovalMethodPreference(ApprovalMethod.APPROVE); } - }, [isContractAddress]); + }, [isContractAddress, walletApprovalMethodPreference, setWalletApprovalMethodPreference]); // a signature is not submitted on-chain so there is no link to review if (!approvalHash && !isSigned && tryPermit) @@ -58,6 +63,7 @@ export const RightHelperText = ({ approvalHash, tryPermit }: RightHelperTextProp setWalletApprovalMethodPreference(method)} + showBatchOption={showBatchOption} /> ); diff --git a/src/components/transactions/Supply/BatchSupplyActions.tsx b/src/components/transactions/Supply/BatchSupplyActions.tsx new file mode 100644 index 0000000000..ce47a92ed8 --- /dev/null +++ b/src/components/transactions/Supply/BatchSupplyActions.tsx @@ -0,0 +1,278 @@ +import { gasLimitRecommendations, ProtocolAction } from '@aave/contract-helpers'; +import { TransactionResponse } from '@ethersproject/providers'; +import { Trans } from '@lingui/macro'; +import { BoxProps } from '@mui/material'; +import { useQueryClient } from '@tanstack/react-query'; +import React, { useEffect, useState } from 'react'; +import { SignedParams, useApprovalTx } from 'src/hooks/useApprovalTx'; +import { usePoolApprovedAmount } from 'src/hooks/useApprovedAmount'; +import { useModalContext } from 'src/hooks/useModal'; +import { useWeb3Context } from 'src/libs/hooks/useWeb3Context'; +import { useRootStore } from 'src/store/root'; +import { ApprovalMethod } from 'src/store/walletSlice'; +import { getErrorTextFromError, TxAction } from 'src/ui-config/errorMapping'; +import { queryKeysFactory } from 'src/ui-config/queries'; +import { encodeFunctionData, erc20Abi, parseUnits } from 'viem'; +import { useAccount, useSendCalls } from 'wagmi'; +import { useShallow } from 'zustand/shallow'; + +import { poolAbi } from '../../../libs/abis/pool_abi'; +import { TxActionsWrapper } from '../TxActionsWrapper'; +import { APPROVAL_GAS_LIMIT, checkRequiresApproval } from '../utils'; + +export interface BatchSupplyActionsProps extends BoxProps { + amountToSupply: string; + isWrongNetwork: boolean; + poolAddress: string; + symbol: string; + blocked: boolean; + decimals: number; + isWrappedBaseAsset: boolean; +} + +export function BatchSupplyActions({ + amountToSupply, + isWrongNetwork, + poolAddress, + symbol, + blocked, + decimals, + isWrappedBaseAsset, + ...props +}: BatchSupplyActionsProps) { + const { address } = useAccount(); + const queryClient = useQueryClient(); + const { + approvalTxState, + mainTxState, + loadingTxns, + setLoadingTxns, + setApprovalTxState, + setMainTxState, + setGasLimit, + setTxError, + } = useModalContext(); + const { sendTx } = useWeb3Context(); + const [signatureParams, setSignatureParams] = useState(); + + const [ + tryPermit, + supply, + supplyWithPermit, + walletApprovalMethodPreference, + estimateGasLimit, + addTransaction, + currentMarketData, + ] = useRootStore( + useShallow((state) => [ + state.tryPermit, + state.supply, + state.supplyWithPermit, + state.walletApprovalMethodPreference, + state.estimateGasLimit, + state.addTransaction, + state.currentMarketData, + ]) + ); + + const { + data: approvedAmount, + refetch: fetchApprovedAmount, + isRefetching: fetchingApprovedAmount, + } = usePoolApprovedAmount(currentMarketData, poolAddress); + + setLoadingTxns(fetchingApprovedAmount); + + const requiresApproval = + Number(amountToSupply) !== 0 && + checkRequiresApproval({ + approvedAmount: approvedAmount?.amount || '0', + amount: amountToSupply, + signedAmount: signatureParams ? signatureParams.amount : '0', + }); + + if (requiresApproval && approvalTxState?.success) { + // There was a successful approval tx, but the approval amount is not enough. + // Clear the state to prompt for another approval. + setApprovalTxState({}); + } + + const permitAvailable = tryPermit({ reserveAddress: poolAddress, isWrappedBaseAsset }); + const usePermit = permitAvailable && walletApprovalMethodPreference === ApprovalMethod.PERMIT; + + const { approval } = useApprovalTx({ + usePermit, + approvedAmount, + requiresApproval, + assetAddress: poolAddress, + symbol, + decimals, + signatureAmount: amountToSupply, + onApprovalTxConfirmed: fetchApprovedAmount, + onSignTxCompleted: (signedParams) => setSignatureParams(signedParams), + }); + + const { sendCalls, isPending } = useSendCalls({ + mutation: { + onSuccess: (hash) => { + console.log('BATCH HASH', hash); + addTransaction('batch', { + action: ProtocolAction.supply, + txState: 'success', + asset: poolAddress, + amount: amountToSupply, + assetName: symbol, + }); + queryClient.invalidateQueries({ queryKey: queryKeysFactory.pool }); + setMainTxState({ success: true, loading: false,txHash: hash.id }); + }, + onError: (error) => { + console.log('ERROR', error); + const parsedError = getErrorTextFromError(error, TxAction.GAS_ESTIMATION, false); + setTxError(parsedError); + }, + }, + }); + + // Update gas estimation + useEffect(() => { + let supplyGasLimit = 0; + if (walletApprovalMethodPreference === ApprovalMethod.BATCH) { + supplyGasLimit = Number(gasLimitRecommendations[ProtocolAction.supply].recommended); + if (requiresApproval) { + supplyGasLimit += Number(APPROVAL_GAS_LIMIT); + } + } else if (usePermit) { + supplyGasLimit = Number(gasLimitRecommendations[ProtocolAction.supplyWithPermit].recommended); + } else { + supplyGasLimit = Number(gasLimitRecommendations[ProtocolAction.supply].recommended); + if (requiresApproval && !approvalTxState.success) { + supplyGasLimit += Number(APPROVAL_GAS_LIMIT); + } + } + setGasLimit(supplyGasLimit.toString()); + }, [requiresApproval, approvalTxState, usePermit, walletApprovalMethodPreference, setGasLimit]); + + const handleSupply = async () => { + try { + setMainTxState({ ...mainTxState, loading: true }); + + if (walletApprovalMethodPreference === ApprovalMethod.BATCH) { + const calls = []; + + if (requiresApproval) { + const approveData = encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [currentMarketData.addresses.LENDING_POOL as `0x${string}`, parseUnits(amountToSupply, decimals)], + }); + calls.push({ + to: poolAddress, + data: approveData, + }); + } + + const supplyData = encodeFunctionData({ + abi: poolAbi, + functionName: 'supply', + args: [ + poolAddress as `0x${string}`, + parseUnits(amountToSupply, decimals), + address || '0x0', + 0, + ], + }); + calls.push({ + to: currentMarketData.addresses.LENDING_POOL, + data: supplyData, + }); + + sendCalls({ + calls, + }); + } else { + let response: TransactionResponse; + let action = ProtocolAction.default; + + if (usePermit && signatureParams) { + action = ProtocolAction.supplyWithPermit; + let signedSupplyWithPermitTxData = supplyWithPermit({ + signature: signatureParams.signature, + amount: parseUnits(amountToSupply, decimals).toString(), + reserve: poolAddress, + deadline: signatureParams.deadline, + }); + + signedSupplyWithPermitTxData = await estimateGasLimit(signedSupplyWithPermitTxData); + response = await sendTx(signedSupplyWithPermitTxData); + + await response.wait(1); + + addTransaction(response.hash, { + action: ProtocolAction.supplyWithPermit, + txState: 'success', + asset: poolAddress, + amount: amountToSupply, + assetName: symbol, + }); + + queryClient.invalidateQueries({ queryKey: queryKeysFactory.pool }); + } else { + action = ProtocolAction.supply; + let supplyTxData = supply({ + amount: parseUnits(amountToSupply, decimals).toString(), + reserve: poolAddress, + }); + supplyTxData = await estimateGasLimit(supplyTxData); + response = await sendTx(supplyTxData); + + await response.wait(1); + + addTransaction(response.hash, { + action, + txState: 'success', + asset: poolAddress, + amount: amountToSupply, + assetName: symbol, + }); + + queryClient.invalidateQueries({ queryKey: queryKeysFactory.pool }); + } + + setMainTxState({ + txHash: response.hash, + loading: false, + success: true, + }); + } + } catch (error) { + const parsedError = getErrorTextFromError(error, TxAction.GAS_ESTIMATION, false); + setTxError(parsedError); + setMainTxState({ + txHash: undefined, + loading: false, + }); + } + }; + + return ( + Supply {symbol}} + actionInProgressText={Supplying {symbol}} + handleApproval={approval} + handleAction={handleSupply} + requiresApproval={requiresApproval && walletApprovalMethodPreference !== ApprovalMethod.BATCH} + tryPermit={permitAvailable} + showBatchOption={true} + sx={props.sx} + /> + ); +} diff --git a/src/components/transactions/Supply/SupplyModalContent.tsx b/src/components/transactions/Supply/SupplyModalContent.tsx index 54ac9552f9..0fb9fad9e4 100644 --- a/src/components/transactions/Supply/SupplyModalContent.tsx +++ b/src/components/transactions/Supply/SupplyModalContent.tsx @@ -51,6 +51,7 @@ import { getAssetCollateralType } from '../utils'; import { AAVEWarning } from '../Warnings/AAVEWarning'; import { IsolationModeWarning } from '../Warnings/IsolationModeWarning'; import { SNXWarning } from '../Warnings/SNXWarning'; +import { BatchSupplyActions } from './BatchSupplyActions'; import { SupplyActions } from './SupplyActions'; import { SupplyWrappedTokenActions } from './SupplyWrappedTokenActions'; @@ -146,11 +147,17 @@ export const SupplyModalContent = React.memo( }: SupplyModalContentProps) => { const { marketReferencePriceInUsd } = useAppDataContext(); const { mainTxState: supplyTxState, gasLimit, txError } = useModalContext(); - const [minRemainingBaseTokenBalance, currentMarketData, currentNetworkConfig] = useRootStore( + const [ + minRemainingBaseTokenBalance, + currentMarketData, + currentNetworkConfig, + walletCapabilities, + ] = useRootStore( useShallow((state) => [ state.poolComputed.minRemainingBaseTokenBalance, state.currentMarketData, state.currentNetworkConfig, + state.walletCapabilities, ]) ); @@ -272,7 +279,11 @@ export const SupplyModalContent = React.memo( {txError && } - + {walletCapabilities?.[currentMarketData.chainId] ? ( + + ) : ( + + )} ); } diff --git a/src/components/transactions/TxActionsWrapper.tsx b/src/components/transactions/TxActionsWrapper.tsx index af16ded1bd..e77b50824b 100644 --- a/src/components/transactions/TxActionsWrapper.tsx +++ b/src/components/transactions/TxActionsWrapper.tsx @@ -33,6 +33,7 @@ interface TxActionsWrapperProps extends BoxProps { }; tryPermit?: boolean; event?: TrackEventProps; + showBatchOption?: boolean; } export const TxActionsWrapper = ({ @@ -54,6 +55,7 @@ export const TxActionsWrapper = ({ errorParams, tryPermit, event, + showBatchOption = false, ...rest }: TxActionsWrapperProps) => { const { txError } = useModalContext(); @@ -127,9 +129,13 @@ export const TxActionsWrapper = ({ const approvalParams = getApprovalParams(); return ( - {approvalParams && !readOnlyModeAddress && ( + {(approvalParams || showBatchOption) && !readOnlyModeAddress && ( - + )} diff --git a/src/hooks/useGetWalletCapabilities.ts b/src/hooks/useGetWalletCapabilities.ts new file mode 100644 index 0000000000..2cf43dfe4a --- /dev/null +++ b/src/hooks/useGetWalletCapabilities.ts @@ -0,0 +1,28 @@ +import { useQuery } from '@tanstack/react-query'; +import { useAccount, useWalletClient } from 'wagmi'; + +export type WalletCapabilities = { + [chainId: number]: boolean; +}; + +export const useGetWalletCapabilities = () => { + const { address } = useAccount(); + const { data: walletClient } = useWalletClient(); + + return useQuery({ + queryFn: async () => { + if (!walletClient || !address) return null; + const capabilities = await walletClient.getCapabilities(); + const simplifiedCapabilities: WalletCapabilities = {}; + Object.entries(capabilities).forEach(([chainId, chainCapabilities]) => { + const atomicStatus = (chainCapabilities as { atomic?: { status?: string } })?.atomic + ?.status; + simplifiedCapabilities[Number(chainId)] = + atomicStatus === 'supported' || atomicStatus === 'ready'; + }); + return simplifiedCapabilities; + }, + queryKey: ['walletCapabilities', address], + enabled: !!walletClient && !!address, + }); +}; diff --git a/src/libs/abis/pool_abi.ts b/src/libs/abis/pool_abi.ts new file mode 100644 index 0000000000..c6ddcbf190 --- /dev/null +++ b/src/libs/abis/pool_abi.ts @@ -0,0 +1,893 @@ +export const poolAbi = [ + { + inputs: [ + { internalType: 'contract IPoolAddressesProvider', name: 'provider', type: 'address' }, + ], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'reserve', type: 'address' }, + { indexed: true, internalType: 'address', name: 'backer', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'amount', type: 'uint256' }, + { indexed: false, internalType: 'uint256', name: 'fee', type: 'uint256' }, + ], + name: 'BackUnbacked', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'reserve', type: 'address' }, + { indexed: false, internalType: 'address', name: 'user', type: 'address' }, + { indexed: true, internalType: 'address', name: 'onBehalfOf', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'amount', type: 'uint256' }, + { + indexed: false, + internalType: 'enum DataTypes.InterestRateMode', + name: 'interestRateMode', + type: 'uint8', + }, + { indexed: false, internalType: 'uint256', name: 'borrowRate', type: 'uint256' }, + { indexed: true, internalType: 'uint16', name: 'referralCode', type: 'uint16' }, + ], + name: 'Borrow', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'reserve', type: 'address' }, + { indexed: false, internalType: 'address', name: 'caller', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'amountCovered', type: 'uint256' }, + ], + name: 'DeficitCovered', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'user', type: 'address' }, + { indexed: true, internalType: 'address', name: 'debtAsset', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'amountCreated', type: 'uint256' }, + ], + name: 'DeficitCreated', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'target', type: 'address' }, + { indexed: false, internalType: 'address', name: 'initiator', type: 'address' }, + { indexed: true, internalType: 'address', name: 'asset', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'amount', type: 'uint256' }, + { + indexed: false, + internalType: 'enum DataTypes.InterestRateMode', + name: 'interestRateMode', + type: 'uint8', + }, + { indexed: false, internalType: 'uint256', name: 'premium', type: 'uint256' }, + { indexed: true, internalType: 'uint16', name: 'referralCode', type: 'uint16' }, + ], + name: 'FlashLoan', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'asset', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'totalDebt', type: 'uint256' }, + ], + name: 'IsolationModeTotalDebtUpdated', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'collateralAsset', type: 'address' }, + { indexed: true, internalType: 'address', name: 'debtAsset', type: 'address' }, + { indexed: true, internalType: 'address', name: 'user', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'debtToCover', type: 'uint256' }, + { + indexed: false, + internalType: 'uint256', + name: 'liquidatedCollateralAmount', + type: 'uint256', + }, + { indexed: false, internalType: 'address', name: 'liquidator', type: 'address' }, + { indexed: false, internalType: 'bool', name: 'receiveAToken', type: 'bool' }, + ], + name: 'LiquidationCall', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'reserve', type: 'address' }, + { indexed: false, internalType: 'address', name: 'user', type: 'address' }, + { indexed: true, internalType: 'address', name: 'onBehalfOf', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'amount', type: 'uint256' }, + { indexed: true, internalType: 'uint16', name: 'referralCode', type: 'uint16' }, + ], + name: 'MintUnbacked', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'reserve', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'amountMinted', type: 'uint256' }, + ], + name: 'MintedToTreasury', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'reserve', type: 'address' }, + { indexed: true, internalType: 'address', name: 'user', type: 'address' }, + { indexed: true, internalType: 'address', name: 'repayer', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'amount', type: 'uint256' }, + { indexed: false, internalType: 'bool', name: 'useATokens', type: 'bool' }, + ], + name: 'Repay', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'reserve', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'liquidityRate', type: 'uint256' }, + { indexed: false, internalType: 'uint256', name: 'stableBorrowRate', type: 'uint256' }, + { indexed: false, internalType: 'uint256', name: 'variableBorrowRate', type: 'uint256' }, + { indexed: false, internalType: 'uint256', name: 'liquidityIndex', type: 'uint256' }, + { indexed: false, internalType: 'uint256', name: 'variableBorrowIndex', type: 'uint256' }, + ], + name: 'ReserveDataUpdated', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'reserve', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'liquidityRate', type: 'uint256' }, + { indexed: false, internalType: 'uint256', name: 'stableBorrowRate', type: 'uint256' }, + { indexed: false, internalType: 'uint256', name: 'variableBorrowRate', type: 'uint256' }, + { indexed: false, internalType: 'uint256', name: 'liquidityIndex', type: 'uint256' }, + { indexed: false, internalType: 'uint256', name: 'variableBorrowIndex', type: 'uint256' }, + ], + name: 'ReserveDataUpdated', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'reserve', type: 'address' }, + { indexed: true, internalType: 'address', name: 'user', type: 'address' }, + ], + name: 'ReserveUsedAsCollateralDisabled', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'reserve', type: 'address' }, + { indexed: true, internalType: 'address', name: 'user', type: 'address' }, + ], + name: 'ReserveUsedAsCollateralEnabled', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'reserve', type: 'address' }, + { indexed: false, internalType: 'address', name: 'user', type: 'address' }, + { indexed: true, internalType: 'address', name: 'onBehalfOf', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'amount', type: 'uint256' }, + { indexed: true, internalType: 'uint16', name: 'referralCode', type: 'uint16' }, + ], + name: 'Supply', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'user', type: 'address' }, + { indexed: false, internalType: 'uint8', name: 'categoryId', type: 'uint8' }, + ], + name: 'UserEModeSet', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'reserve', type: 'address' }, + { indexed: true, internalType: 'address', name: 'user', type: 'address' }, + { indexed: true, internalType: 'address', name: 'to', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'amount', type: 'uint256' }, + ], + name: 'Withdraw', + type: 'event', + }, + { + inputs: [], + name: 'ADDRESSES_PROVIDER', + outputs: [{ internalType: 'contract IPoolAddressesProvider', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'BRIDGE_PROTOCOL_FEE', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'FLASHLOAN_PREMIUM_TOTAL', + outputs: [{ internalType: 'uint128', name: '', type: 'uint128' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'FLASHLOAN_PREMIUM_TO_PROTOCOL', + outputs: [{ internalType: 'uint128', name: '', type: 'uint128' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'MAX_NUMBER_RESERVES', + outputs: [{ internalType: 'uint16', name: '', type: 'uint16' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'POOL_REVISION', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'UMBRELLA', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'uint256', name: 'fee', type: 'uint256' }, + ], + name: 'backUnbacked', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'uint256', name: 'interestRateMode', type: 'uint256' }, + { internalType: 'uint16', name: 'referralCode', type: 'uint16' }, + { internalType: 'address', name: 'onBehalfOf', type: 'address' }, + ], + name: 'borrow', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint8', name: 'id', type: 'uint8' }, + { + components: [ + { internalType: 'uint16', name: 'ltv', type: 'uint16' }, + { internalType: 'uint16', name: 'liquidationThreshold', type: 'uint16' }, + { internalType: 'uint16', name: 'liquidationBonus', type: 'uint16' }, + { internalType: 'string', name: 'label', type: 'string' }, + ], + internalType: 'struct DataTypes.EModeCategoryBaseConfiguration', + name: 'category', + type: 'tuple', + }, + ], + name: 'configureEModeCategory', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint8', name: 'id', type: 'uint8' }, + { internalType: 'uint128', name: 'borrowableBitmap', type: 'uint128' }, + ], + name: 'configureEModeCategoryBorrowableBitmap', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint8', name: 'id', type: 'uint8' }, + { internalType: 'uint128', name: 'collateralBitmap', type: 'uint128' }, + ], + name: 'configureEModeCategoryCollateralBitmap', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'address', name: 'onBehalfOf', type: 'address' }, + { internalType: 'uint16', name: 'referralCode', type: 'uint16' }, + ], + name: 'deposit', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'asset', type: 'address' }], + name: 'dropReserve', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + ], + name: 'eliminateReserveDeficit', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'address', name: 'from', type: 'address' }, + { internalType: 'address', name: 'to', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'uint256', name: 'balanceFromBefore', type: 'uint256' }, + { internalType: 'uint256', name: 'balanceToBefore', type: 'uint256' }, + ], + name: 'finalizeTransfer', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'receiverAddress', type: 'address' }, + { internalType: 'address[]', name: 'assets', type: 'address[]' }, + { internalType: 'uint256[]', name: 'amounts', type: 'uint256[]' }, + { internalType: 'uint256[]', name: 'interestRateModes', type: 'uint256[]' }, + { internalType: 'address', name: 'onBehalfOf', type: 'address' }, + { internalType: 'bytes', name: 'params', type: 'bytes' }, + { internalType: 'uint16', name: 'referralCode', type: 'uint16' }, + ], + name: 'flashLoan', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'receiverAddress', type: 'address' }, + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'bytes', name: 'params', type: 'bytes' }, + { internalType: 'uint16', name: 'referralCode', type: 'uint16' }, + ], + name: 'flashLoanSimple', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'getBorrowLogic', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [], + name: 'getBridgeLogic', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'asset', type: 'address' }], + name: 'getConfiguration', + outputs: [ + { + components: [{ internalType: 'uint256', name: 'data', type: 'uint256' }], + internalType: 'struct DataTypes.ReserveConfigurationMap', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint8', name: 'id', type: 'uint8' }], + name: 'getEModeCategoryBorrowableBitmap', + outputs: [{ internalType: 'uint128', name: '', type: 'uint128' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint8', name: 'id', type: 'uint8' }], + name: 'getEModeCategoryCollateralBitmap', + outputs: [{ internalType: 'uint128', name: '', type: 'uint128' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint8', name: 'id', type: 'uint8' }], + name: 'getEModeCategoryCollateralConfig', + outputs: [ + { + components: [ + { internalType: 'uint16', name: 'ltv', type: 'uint16' }, + { internalType: 'uint16', name: 'liquidationThreshold', type: 'uint16' }, + { internalType: 'uint16', name: 'liquidationBonus', type: 'uint16' }, + ], + internalType: 'struct DataTypes.CollateralConfig', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint8', name: 'id', type: 'uint8' }], + name: 'getEModeCategoryData', + outputs: [ + { + components: [ + { internalType: 'uint16', name: 'ltv', type: 'uint16' }, + { internalType: 'uint16', name: 'liquidationThreshold', type: 'uint16' }, + { internalType: 'uint16', name: 'liquidationBonus', type: 'uint16' }, + { internalType: 'address', name: 'priceSource', type: 'address' }, + { internalType: 'string', name: 'label', type: 'string' }, + ], + internalType: 'struct DataTypes.EModeCategoryLegacy', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint8', name: 'id', type: 'uint8' }], + name: 'getEModeCategoryLabel', + outputs: [{ internalType: 'string', name: '', type: 'string' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getEModeLogic', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [], + name: 'getFlashLoanLogic', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'asset', type: 'address' }], + name: 'getLiquidationGracePeriod', + outputs: [{ internalType: 'uint40', name: '', type: 'uint40' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getLiquidationLogic', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [], + name: 'getPoolLogic', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'asset', type: 'address' }], + name: 'getReserveAToken', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'uint16', name: 'id', type: 'uint16' }], + name: 'getReserveAddressById', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'asset', type: 'address' }], + name: 'getReserveData', + outputs: [ + { + components: [ + { + components: [{ internalType: 'uint256', name: 'data', type: 'uint256' }], + internalType: 'struct DataTypes.ReserveConfigurationMap', + name: 'configuration', + type: 'tuple', + }, + { internalType: 'uint128', name: 'liquidityIndex', type: 'uint128' }, + { internalType: 'uint128', name: 'currentLiquidityRate', type: 'uint128' }, + { internalType: 'uint128', name: 'variableBorrowIndex', type: 'uint128' }, + { internalType: 'uint128', name: 'currentVariableBorrowRate', type: 'uint128' }, + { internalType: 'uint128', name: 'currentStableBorrowRate', type: 'uint128' }, + { internalType: 'uint40', name: 'lastUpdateTimestamp', type: 'uint40' }, + { internalType: 'uint16', name: 'id', type: 'uint16' }, + { internalType: 'address', name: 'aTokenAddress', type: 'address' }, + { internalType: 'address', name: 'stableDebtTokenAddress', type: 'address' }, + { internalType: 'address', name: 'variableDebtTokenAddress', type: 'address' }, + { internalType: 'address', name: 'interestRateStrategyAddress', type: 'address' }, + { internalType: 'uint128', name: 'accruedToTreasury', type: 'uint128' }, + { internalType: 'uint128', name: 'unbacked', type: 'uint128' }, + { internalType: 'uint128', name: 'isolationModeTotalDebt', type: 'uint128' }, + ], + internalType: 'struct DataTypes.ReserveDataLegacy', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'asset', type: 'address' }], + name: 'getReserveDeficit', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'asset', type: 'address' }], + name: 'getReserveNormalizedIncome', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'asset', type: 'address' }], + name: 'getReserveNormalizedVariableDebt', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'asset', type: 'address' }], + name: 'getReserveVariableDebtToken', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getReservesCount', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getReservesList', + outputs: [{ internalType: 'address[]', name: '', type: 'address[]' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getSupplyLogic', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'user', type: 'address' }], + name: 'getUserAccountData', + outputs: [ + { internalType: 'uint256', name: 'totalCollateralBase', type: 'uint256' }, + { internalType: 'uint256', name: 'totalDebtBase', type: 'uint256' }, + { internalType: 'uint256', name: 'availableBorrowsBase', type: 'uint256' }, + { internalType: 'uint256', name: 'currentLiquidationThreshold', type: 'uint256' }, + { internalType: 'uint256', name: 'ltv', type: 'uint256' }, + { internalType: 'uint256', name: 'healthFactor', type: 'uint256' }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'user', type: 'address' }], + name: 'getUserConfiguration', + outputs: [ + { + components: [{ internalType: 'uint256', name: 'data', type: 'uint256' }], + internalType: 'struct DataTypes.UserConfigurationMap', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'user', type: 'address' }], + name: 'getUserEMode', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'asset', type: 'address' }], + name: 'getVirtualUnderlyingBalance', + outputs: [{ internalType: 'uint128', name: '', type: 'uint128' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'address', name: 'aTokenAddress', type: 'address' }, + { internalType: 'address', name: 'variableDebtAddress', type: 'address' }, + { internalType: 'address', name: 'interestRateStrategyAddress', type: 'address' }, + ], + name: 'initReserve', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'contract IPoolAddressesProvider', name: 'provider', type: 'address' }, + ], + name: 'initialize', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'collateralAsset', type: 'address' }, + { internalType: 'address', name: 'debtAsset', type: 'address' }, + { internalType: 'address', name: 'user', type: 'address' }, + { internalType: 'uint256', name: 'debtToCover', type: 'uint256' }, + { internalType: 'bool', name: 'receiveAToken', type: 'bool' }, + ], + name: 'liquidationCall', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address[]', name: 'assets', type: 'address[]' }], + name: 'mintToTreasury', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'address', name: 'onBehalfOf', type: 'address' }, + { internalType: 'uint16', name: 'referralCode', type: 'uint16' }, + ], + name: 'mintUnbacked', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'uint256', name: 'interestRateMode', type: 'uint256' }, + { internalType: 'address', name: 'onBehalfOf', type: 'address' }, + ], + name: 'repay', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'uint256', name: 'interestRateMode', type: 'uint256' }, + ], + name: 'repayWithATokens', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'uint256', name: 'interestRateMode', type: 'uint256' }, + { internalType: 'address', name: 'onBehalfOf', type: 'address' }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + { internalType: 'uint8', name: 'permitV', type: 'uint8' }, + { internalType: 'bytes32', name: 'permitR', type: 'bytes32' }, + { internalType: 'bytes32', name: 'permitS', type: 'bytes32' }, + ], + name: 'repayWithPermit', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'token', type: 'address' }, + { internalType: 'address', name: 'to', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + ], + name: 'rescueTokens', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'asset', type: 'address' }], + name: 'resetIsolationModeTotalDebt', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { + components: [{ internalType: 'uint256', name: 'data', type: 'uint256' }], + internalType: 'struct DataTypes.ReserveConfigurationMap', + name: 'configuration', + type: 'tuple', + }, + ], + name: 'setConfiguration', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'uint40', name: 'until', type: 'uint40' }, + ], + name: 'setLiquidationGracePeriod', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'address', name: 'rateStrategyAddress', type: 'address' }, + ], + name: 'setReserveInterestRateStrategyAddress', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'uint8', name: 'categoryId', type: 'uint8' }], + name: 'setUserEMode', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'bool', name: 'useAsCollateral', type: 'bool' }, + ], + name: 'setUserUseReserveAsCollateral', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'address', name: 'onBehalfOf', type: 'address' }, + { internalType: 'uint16', name: 'referralCode', type: 'uint16' }, + ], + name: 'supply', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'address', name: 'onBehalfOf', type: 'address' }, + { internalType: 'uint16', name: 'referralCode', type: 'uint16' }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + { internalType: 'uint8', name: 'permitV', type: 'uint8' }, + { internalType: 'bytes32', name: 'permitR', type: 'bytes32' }, + { internalType: 'bytes32', name: 'permitS', type: 'bytes32' }, + ], + name: 'supplyWithPermit', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'asset', type: 'address' }], + name: 'syncIndexesState', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'asset', type: 'address' }], + name: 'syncRatesState', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: 'protocolFee', type: 'uint256' }], + name: 'updateBridgeProtocolFee', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint128', name: 'flashLoanPremiumTotal', type: 'uint128' }, + { internalType: 'uint128', name: 'flashLoanPremiumToProtocol', type: 'uint128' }, + ], + name: 'updateFlashloanPremiums', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'asset', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'address', name: 'to', type: 'address' }, + ], + name: 'withdraw', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, +] as const; diff --git a/src/libs/web3-data-provider/Web3Provider.tsx b/src/libs/web3-data-provider/Web3Provider.tsx index 26fe83287c..f3c40f7303 100644 --- a/src/libs/web3-data-provider/Web3Provider.tsx +++ b/src/libs/web3-data-provider/Web3Provider.tsx @@ -3,6 +3,7 @@ import { SignatureLike } from '@ethersproject/bytes'; import { JsonRpcProvider, TransactionResponse } from '@ethersproject/providers'; import { BigNumber, PopulatedTransaction, utils } from 'ethers'; import React, { ReactElement, useEffect, useState } from 'react'; +import { useGetWalletCapabilities } from 'src/hooks/useGetWalletCapabilities'; import { useIsContractAddress } from 'src/hooks/useIsContractAddress'; import { useRootStore } from 'src/store/root'; import { wagmiConfig } from 'src/ui-config/wagmiConfig'; @@ -49,8 +50,12 @@ export const Web3ContextProvider: React.FC<{ children: ReactElement }> = ({ chil const [readOnlyModeAddress, setReadOnlyModeAddress] = useState(); const [switchNetworkError, setSwitchNetworkError] = useState(); - const [setAccount, setConnectedAccountIsContract] = useRootStore( - useShallow((store) => [store.setAccount, store.setConnectedAccountIsContract]) + const [setAccount, setConnectedAccountIsContract, setWalletCapabilities] = useRootStore( + useShallow((store) => [ + store.setAccount, + store.setConnectedAccountIsContract, + store.setWalletCapabilities, + ]) ); const account = address; @@ -61,6 +66,29 @@ export const Web3ContextProvider: React.FC<{ children: ReactElement }> = ({ chil } const { data: isContractAddress } = useIsContractAddress(account || '', chainId); + const { data: walletCapabilities } = useGetWalletCapabilities(); + + useEffect(() => { + if (!account) { + setConnectedAccountIsContract(false); + setWalletCapabilities(null); + return; + } + + if (isContractAddress) { + setConnectedAccountIsContract(true); + } + + if (walletCapabilities) { + setWalletCapabilities(walletCapabilities); + } + }, [ + isContractAddress, + setConnectedAccountIsContract, + account, + walletCapabilities, + setWalletCapabilities, + ]); useEffect(() => { if (didInit) { @@ -185,17 +213,6 @@ export const Web3ContextProvider: React.FC<{ children: ReactElement }> = ({ chil } }, [readOnlyModeAddress, setAccount]); - useEffect(() => { - if (!account) { - setConnectedAccountIsContract(false); - return; - } - - if (isContractAddress) { - setConnectedAccountIsContract(true); - } - }, [isContractAddress, setConnectedAccountIsContract, account]); - return ( void; connectedAccountIsContract: boolean; setConnectedAccountIsContract: (isContract: boolean) => void; + walletCapabilities: WalletCapabilities | null; + setWalletCapabilities: (capabilities: WalletCapabilities | null) => void; } const getWalletPreferences = () => { @@ -79,4 +83,8 @@ export const createWalletSlice: StateCreator< setConnectedAccountIsContract(isContract) { set({ connectedAccountIsContract: isContract }); }, + walletCapabilities: null, + setWalletCapabilities(capabilities) { + set({ walletCapabilities: capabilities }); + }, });