From 798fa3fb21bb47518415f602673e1f70c8b5254e Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 26 Oct 2023 14:11:33 +0700 Subject: [PATCH] feat: blackjack (#2302) --- .env.dev | 1 + .env.production | 1 + .env.stg | 1 + src/components/ProAmm/ProAmmFee.tsx | 59 ++-- .../WalletPopup/SendToken/useSendToken.tsx | 4 +- .../YieldPools/ElasticFarmGroup/Row.tsx | 4 +- .../YieldPools/ElasticFarmGroup/index.tsx | 6 +- .../ElasticFarmModals/StakeModal.tsx | 2 +- .../ListOrder/useRequestCancelOrder.tsx | 12 +- src/constants/env.ts | 1 + src/data/Allowances.ts | 4 +- src/data/TotalSupply.ts | 4 +- src/hooks/Tokens.ts | 8 +- src/hooks/index.ts | 37 ++- src/hooks/kyberdao/index.tsx | 40 ++- src/hooks/useApproveCallback.ts | 129 ++++---- src/hooks/useClaimReward.ts | 49 ++- src/hooks/useContract.ts | 116 ++++--- src/hooks/useENSAddress.ts | 3 +- src/hooks/useENSContentHash.ts | 3 +- src/hooks/useENSName.ts | 3 +- src/hooks/useFairLaunch.ts | 18 +- src/hooks/usePermit.ts | 21 +- src/hooks/useProAmmPositions.ts | 6 +- src/hooks/useProAmmPreviousTicks.ts | 7 +- src/hooks/useStakedBalance.ts | 4 +- src/hooks/useTokenBalance.ts | 4 +- src/hooks/useWrapCallback.ts | 27 +- src/hooks/useZap.ts | 1 - src/pages/AddLiquidity/TokenPair.tsx | 44 ++- src/pages/AddLiquidity/ZapIn.tsx | 43 ++- src/pages/AddLiquidityV2/index.tsx | 4 +- .../Campaign/CampaignButtonWithOptions.tsx | 18 +- src/pages/CreatePool/index.tsx | 14 +- src/pages/ElasticLegacy/FarmLegacy.tsx | 4 +- src/pages/ElasticSwap/hooks/index.ts | 8 +- src/pages/Farm/ElasticFarmv2/index.tsx | 10 +- src/pages/IncreaseLiquidity/index.tsx | 121 ++++--- .../KyberDAO/Vote/ProposalItem/index.tsx | 10 +- src/pages/KyberDAO/Vote/index.tsx | 9 +- .../SinglePosition/CollectFeesPanel.tsx | 4 +- src/pages/ProAmmPool/PositionListItem.tsx | 4 +- src/pages/RemoveLiquidity/TokenPair.tsx | 81 +++-- src/pages/RemoveLiquidity/ZapOut.tsx | 77 +++-- src/pages/RemoveLiquidityProAmm/index.tsx | 14 +- src/services/blackjack.ts | 39 +++ src/state/farms/classic/knUpdater.tsx | 4 +- src/state/farms/elastic/hooks.ts | 309 ++++++++++++------ src/state/farms/elasticv2/hooks.ts | 77 +++-- src/state/farms/elasticv2/updater.tsx | 4 +- src/state/index.ts | 3 + src/utils/getContract.ts | 24 +- src/utils/sendTransaction.ts | 2 +- 53 files changed, 952 insertions(+), 550 deletions(-) create mode 100644 src/services/blackjack.ts diff --git a/.env.dev b/.env.dev index e455cb9425..354a474d17 100644 --- a/.env.dev +++ b/.env.dev @@ -19,6 +19,7 @@ VITE_TRANSAK_URL=https://staging-global.transak.com VITE_TRANSAK_API_KEY=327b8b63-626b-4376-baf2-70a304c48488 VITE_KS_SETTING_API=https://ks-setting.dev.kyberengineering.io/api +VITE_BLACKJACK_API=https://blackjack.dev.kyberengineering.io/api VITE_GTM_ID= diff --git a/.env.production b/.env.production index db6168b726..dad530c4b1 100644 --- a/.env.production +++ b/.env.production @@ -19,6 +19,7 @@ VITE_TRANSAK_URL=https://global.transak.com VITE_TRANSAK_API_KEY=48949c0b-2d20-4e3a-a311-51ca91ae8c0d VITE_KS_SETTING_API=https://ks-setting.kyberswap.com/api +VITE_BLACKJACK_API=https://blackjack.kyberswap.com/api VITE_GTM_ID=GTM-TRQCJ8F diff --git a/.env.stg b/.env.stg index 984c5d45eb..085738be95 100644 --- a/.env.stg +++ b/.env.stg @@ -18,6 +18,7 @@ VITE_TRANSAK_URL=https://staging-global.transak.com VITE_TRANSAK_API_KEY=327b8b63-626b-4376-baf2-70a304c48488 VITE_KS_SETTING_API=https://ks-setting.stg.kyberengineering.io/api +VITE_BLACKJACK_API=https://blackjack.stg.kyberengineering.io/api VITE_GTM_ID= diff --git a/src/components/ProAmm/ProAmmFee.tsx b/src/components/ProAmm/ProAmmFee.tsx index 8aaeec763e..6ef4f463b8 100644 --- a/src/components/ProAmm/ProAmmFee.tsx +++ b/src/components/ProAmm/ProAmmFee.tsx @@ -19,7 +19,11 @@ import FarmV21ABI from 'constants/abis/v2/farmv2.1.json' import FarmV2ABI from 'constants/abis/v2/farmv2.json' import { EVMNetworkInfo } from 'constants/networks/type' import { useActiveWeb3React, useWeb3React } from 'hooks' -import { useContract, useProAmmNFTPositionManagerContract, useProMMFarmContract } from 'hooks/useContract' +import { + useProAmmNFTPositionManagerReadingContract, + useProMMFarmSigningContract, + useSigningContract, +} from 'hooks/useContract' import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel' import useProAmmPoolInfo from 'hooks/useProAmmPoolInfo' import useTheme from 'hooks/useTheme' @@ -58,7 +62,7 @@ export default function ProAmmFee({ const token0Shown = feeValue0?.currency || position.pool.token0 const token1Shown = feeValue1?.currency || position.pool.token1 const addTransactionWithType = useTransactionAdder() - const positionManager = useProAmmNFTPositionManagerContract() + const positionManager = useProAmmNFTPositionManagerReadingContract() const deadline = useTransactionDeadline() // custom from users settings const { mixpanelHandler } = useMixpanel() @@ -105,7 +109,7 @@ export default function ProAmmFee({ setTxnHash(response.hash) } - const farmContract = useProMMFarmContract(farmAddress || '') + const farmContract = useProMMFarmSigningContract(farmAddress || '') const poolAddress = useProAmmPoolInfo(position.pool.token0, position.pool.token1, position.pool.fee as FeeAmount) const { userInfo } = useElasticFarmsV2() const info = userInfo?.find(item => item.nftId.toString() === tokenId.toString()) @@ -115,8 +119,8 @@ export default function ProAmmFee({ ?.map(item => item.toLowerCase()) .includes(address?.toLowerCase()) - const farmV2Contract = useContract(address, FarmV2ABI) - const farmV21Contract = useContract(address, FarmV21ABI) + const farmV2Contract = useSigningContract(address, FarmV2ABI) + const farmV21Contract = useSigningContract(address, FarmV21ABI) const collectFeeFromFarmContract = async () => { const isInFarmV2 = !!info @@ -178,7 +182,7 @@ export default function ProAmmFee({ } } - const collect = () => { + const collect = async () => { setShowPendingModal(true) setAttemptingTxn(true) @@ -214,27 +218,28 @@ export default function ProAmmFee({ value, } - library - .getSigner() - .estimateGas(txn) - .then((estimate: BigNumber) => { - const newTxn = { - ...txn, - gasLimit: calculateGasMargin(estimate), - } - return library - .getSigner() - .sendTransaction(newTxn) - .then((response: TransactionResponse) => { - handleBroadcastClaimSuccess(response) - }) - }) - .catch((error: any) => { - setShowPendingModal(true) - setAttemptingTxn(false) - setCollectFeeError(error?.message || JSON.stringify(error)) - console.error(error) - }) + try { + await library + .getSigner() + .estimateGas(txn) + .then((estimate: BigNumber) => { + const newTxn = { + ...txn, + gasLimit: calculateGasMargin(estimate), + } + return library + .getSigner() + .sendTransaction(newTxn) + .then((response: TransactionResponse) => { + handleBroadcastClaimSuccess(response) + }) + }) + } catch (error: any) { + setShowPendingModal(true) + setAttemptingTxn(false) + setCollectFeeError(error?.message || JSON.stringify(error)) + console.error(error) + } } const hasNoFeeToCollect = !(feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0)) diff --git a/src/components/WalletPopup/SendToken/useSendToken.tsx b/src/components/WalletPopup/SendToken/useSendToken.tsx index 02d46ca706..3f39e57ea3 100644 --- a/src/components/WalletPopup/SendToken/useSendToken.tsx +++ b/src/components/WalletPopup/SendToken/useSendToken.tsx @@ -7,7 +7,7 @@ import { ethers } from 'ethers' import { useCallback, useEffect, useState } from 'react' import { useActiveWeb3React, useWeb3React, useWeb3Solana } from 'hooks' -import { useTokenContract } from 'hooks/useContract' +import { useTokenSigningContract } from 'hooks/useContract' import { tryParseAmount } from 'state/swap/hooks' import { useTransactionAdder } from 'state/transactions/hooks' import { TRANSACTION_TYPE } from 'state/transactions/type' @@ -16,7 +16,7 @@ export default function useSendToken(currency: Currency | undefined, recipient: const { account, isEVM, walletSolana, isSolana } = useActiveWeb3React() const { library } = useWeb3React() const [estimateGas, setGasFee] = useState(null) - const tokenContract = useTokenContract(isSolana ? undefined : currency?.wrapped.address) + const tokenContract = useTokenSigningContract(isSolana ? undefined : currency?.wrapped.address) const addTransactionWithType = useTransactionAdder() const [isSending, setIsSending] = useState(false) const { publicKey } = useWallet() diff --git a/src/components/YieldPools/ElasticFarmGroup/Row.tsx b/src/components/YieldPools/ElasticFarmGroup/Row.tsx index ef4c0bb148..585adb9a74 100644 --- a/src/components/YieldPools/ElasticFarmGroup/Row.tsx +++ b/src/components/YieldPools/ElasticFarmGroup/Row.tsx @@ -21,7 +21,7 @@ import { PartnerFarmTag } from 'components/YieldPools/PartnerFarmTag' import { APP_PATHS, ELASTIC_BASE_FEE_UNIT } from 'constants/index' import { TOBE_EXTENDED_FARMING_POOLS } from 'constants/v2' import { useActiveWeb3React } from 'hooks' -import { useProMMFarmContract } from 'hooks/useContract' +import { useProMMFarmReadingContract } from 'hooks/useContract' import { useProAmmPositions } from 'hooks/useProAmmPositions' import useTheme from 'hooks/useTheme' import { useShareFarmAddress } from 'state/farms/classic/hooks' @@ -96,7 +96,7 @@ const Row = ({ 0, ) - const contract = useProMMFarmContract(fairlaunchAddress) + const contract = useProMMFarmReadingContract(fairlaunchAddress) const [targetPercent, setTargetPercent] = useState('') const [targetPercentByNFT, setTargetPercentByNFT] = useState<{ [key: string]: string }>({}) const [rowOpen, setRowOpen] = useState(false) diff --git a/src/components/YieldPools/ElasticFarmGroup/index.tsx b/src/components/YieldPools/ElasticFarmGroup/index.tsx index a073492216..28955578fe 100644 --- a/src/components/YieldPools/ElasticFarmGroup/index.tsx +++ b/src/components/YieldPools/ElasticFarmGroup/index.tsx @@ -18,7 +18,7 @@ import { MouseoverTooltip, MouseoverTooltipDesktopOnly, TextDashed } from 'compo import { FARM_TAB, SORT_DIRECTION, ZERO_ADDRESS } from 'constants/index' import { NETWORKS_INFO, isEVM } from 'constants/networks' import { useActiveWeb3React } from 'hooks' -import { useProAmmNFTPositionManagerContract } from 'hooks/useContract' +import { useProAmmNFTPositionManagerReadingContract } from 'hooks/useContract' import useTheme from 'hooks/useTheme' import { Dots } from 'pages/MyPool/styleds' import { useWalletModalToggle } from 'state/application/hooks' @@ -228,7 +228,7 @@ const ElasticFarmGroup: React.FC = ({ address, onOpenModal, pools, onShow }) const toggleWalletModal = useWalletModalToggle() - const posManager = useProAmmNFTPositionManagerContract() + const posManager = useProAmmNFTPositionManagerReadingContract() const res = useSingleCallResult(posManager, 'isApprovedForAll', [account || ZERO_ADDRESS, address]) const isApprovedForAll = res?.result?.[0] @@ -241,7 +241,7 @@ const ElasticFarmGroup: React.FC = ({ address, onOpenModal, pools, onShow const handleApprove = async () => { if (!isApprovedForAll) { const tx = await approve() - setApprovalTx(tx) + tx && setApprovalTx(tx) } } diff --git a/src/components/YieldPools/ElasticFarmModals/StakeModal.tsx b/src/components/YieldPools/ElasticFarmModals/StakeModal.tsx index 195bf0239d..2032effd5d 100644 --- a/src/components/YieldPools/ElasticFarmModals/StakeModal.tsx +++ b/src/components/YieldPools/ElasticFarmModals/StakeModal.tsx @@ -369,7 +369,7 @@ function StakeModal({ stakedLiquidity: e.staked.liquidity.toString(), })) if (type === 'stake') { - let txhash = '' + let txhash: string | undefined = undefined if (tab === 'deposit') txhash = await depositAndJoin(BigNumber.from(poolId), params) else txhash = await stake(BigNumber.from(poolId), params) diff --git a/src/components/swapv2/LimitOrder/ListOrder/useRequestCancelOrder.tsx b/src/components/swapv2/LimitOrder/ListOrder/useRequestCancelOrder.tsx index adba2da856..9997d89b3f 100644 --- a/src/components/swapv2/LimitOrder/ListOrder/useRequestCancelOrder.tsx +++ b/src/components/swapv2/LimitOrder/ListOrder/useRequestCancelOrder.tsx @@ -14,11 +14,12 @@ import useSignOrder from 'components/swapv2/LimitOrder/useSignOrder' import LIMIT_ORDER_ABI from 'constants/abis/limit_order.json' import { TRANSACTION_STATE_DEFAULT } from 'constants/index' import { useActiveWeb3React, useWeb3React } from 'hooks' +import { useKyberSwapConfig } from 'state/application/hooks' import { useLimitActionHandlers, useLimitState } from 'state/limit/hooks' import { useTransactionAdder } from 'state/transactions/hooks' import { TRANSACTION_TYPE } from 'state/transactions/type' import { TransactionFlowState } from 'types/TransactionFlowState' -import { getContract } from 'utils/getContract' +import { getReadingContract } from 'utils/getContract' import { sendEVMTransaction } from 'utils/sendTransaction' import { ErrorName } from 'utils/sentry' import { formatSignature } from 'utils/transaction' @@ -30,15 +31,16 @@ import { CancelOrderFunction, CancelOrderResponse, CancelOrderType, LimitOrder } const useGetEncodeLimitOrder = () => { const { account } = useActiveWeb3React() const [getEncodeData] = useGetEncodeDataMutation() - const { library } = useWeb3React() + const { readProvider } = useKyberSwapConfig() + return useCallback( async ({ orders, isCancelAll }: { orders: LimitOrder[]; isCancelAll: boolean | undefined }) => { - if (!library) throw new Error() + if (!readProvider) throw new Error() if (isCancelAll) { const contracts = [...new Set(orders.map(e => e.contractAddress))] const result = [] for (const address of contracts) { - const limitOrderContract = getContract(address, LIMIT_ORDER_ABI, library, account) + const limitOrderContract = getReadingContract(address, LIMIT_ORDER_ABI, readProvider) const [{ encodedData }, nonce] = await Promise.all([ getEncodeData({ orderIds: [], isCancelAll }).unwrap(), limitOrderContract?.nonce?.(account), @@ -53,7 +55,7 @@ const useGetEncodeLimitOrder = () => { }).unwrap() return [{ encodedData, contractAddress: orders[0]?.contractAddress, nonce: '' }] }, - [account, getEncodeData, library], + [account, getEncodeData, readProvider], ) } diff --git a/src/constants/env.ts b/src/constants/env.ts index bb4b90ebd0..63d42ec001 100644 --- a/src/constants/env.ts +++ b/src/constants/env.ts @@ -17,6 +17,7 @@ export const AGGREGATOR_API = required('AGGREGATOR_API') export const SENTRY_DNS = required('SENTRY_DNS') export const REWARD_SERVICE_API = required('REWARD_SERVICE_API') export const KS_SETTING_API = required('KS_SETTING_API') +export const BLACKJACK_API = required('BLACKJACK_API') export const BLOCK_SERVICE_API = required('BLOCK_SERVICE_API') export const PRICE_CHART_API = required('PRICE_CHART_API') export const AGGREGATOR_STATS_API = required('AGGREGATOR_STATS_API') diff --git a/src/data/Allowances.ts b/src/data/Allowances.ts index 17a3cd3445..c489cddeb4 100644 --- a/src/data/Allowances.ts +++ b/src/data/Allowances.ts @@ -2,12 +2,12 @@ import { Token, TokenAmount } from '@kyberswap/ks-sdk-core' import { useMemo } from 'react' import { useActiveWeb3React } from 'hooks' -import { useTokenContractForReading } from 'hooks/useContract' +import { useTokenReadingContract } from 'hooks/useContract' import { useSingleCallResult } from 'state/multicall/hooks' export function useTokenAllowance(token?: Token, owner?: string, spender?: string): TokenAmount | undefined { const { isEVM } = useActiveWeb3React() - const contractForReading = useTokenContractForReading(isEVM ? token?.address : undefined) + const contractForReading = useTokenReadingContract(isEVM ? token?.address : undefined) const inputs = useMemo(() => [owner, spender], [owner, spender]) const allowance = useSingleCallResult(contractForReading, 'allowance', inputs).result diff --git a/src/data/TotalSupply.ts b/src/data/TotalSupply.ts index 4dd04592d9..2b274cee3b 100644 --- a/src/data/TotalSupply.ts +++ b/src/data/TotalSupply.ts @@ -1,13 +1,13 @@ import { BigNumber } from '@ethersproject/bignumber' import { Token, TokenAmount } from '@kyberswap/ks-sdk-core' -import { useTokenContract } from 'hooks/useContract' +import { useTokenReadingContract } from 'hooks/useContract' import { useSingleCallResult } from 'state/multicall/hooks' // returns undefined if input token is undefined, or fails to get token contract, // or contract total supply cannot be fetched export function useTotalSupply(token?: Token): TokenAmount | undefined { - const contract = useTokenContract(token?.address, false) + const contract = useTokenReadingContract(token?.address) const totalSupply: BigNumber = useSingleCallResult(contract, 'totalSupply')?.result?.[0] return token && totalSupply ? TokenAmount.fromRawAmount(token, totalSupply.toString()) : undefined diff --git a/src/hooks/Tokens.ts b/src/hooks/Tokens.ts index 9cc625a414..eb0b016ecd 100644 --- a/src/hooks/Tokens.ts +++ b/src/hooks/Tokens.ts @@ -12,7 +12,7 @@ import { KS_SETTING_API } from 'constants/env' import { ETHER_ADDRESS, ZERO_ADDRESS } from 'constants/index' import { NativeCurrencies } from 'constants/tokens' import { useActiveWeb3React } from 'hooks/index' -import { useBytes32TokenContract, useMulticallContract, useTokenContract } from 'hooks/useContract' +import { useBytes32TokenContract, useMulticallContract, useTokenReadingContract } from 'hooks/useContract' import { AppState } from 'state' import { TokenAddressMap } from 'state/lists/reducer' import { TokenInfo, WrappedTokenInfo } from 'state/lists/wrappedTokenInfo' @@ -180,10 +180,10 @@ export function useToken(tokenAddress?: string): Token | NativeCurrency | undefi const address = isAddress(chainId, tokenAddress) - const tokenContract = useTokenContract(address && tokenAddress !== ZERO_ADDRESS ? address : undefined, false) - const tokenContractBytes32 = useBytes32TokenContract(address ? address : undefined, false) + const tokenContract = useTokenReadingContract(address && tokenAddress !== ZERO_ADDRESS ? address : undefined) + const tokenContractBytes32 = useBytes32TokenContract(address ? address : undefined) const token = - tokenAddress === ZERO_ADDRESS || tokenAddress?.toLowerCase() === ETHER_ADDRESS.toLowerCase() + tokenAddress?.toLowerCase() === ZERO_ADDRESS || tokenAddress?.toLowerCase() === ETHER_ADDRESS.toLowerCase() ? NativeCurrencies[chainId] : address ? tokens[address] diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 878acbc1c0..03cc51e8a8 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -6,6 +6,7 @@ import { Connector } from '@web3-react/types' import { useMemo } from 'react' import { useSelector } from 'react-redux' import { useSearchParams } from 'react-router-dom' +import { useCheckBlackjackQuery } from 'services/blackjack' import { blocto, gnosisSafe, krystalWalletConnectV2, walletConnectV2 } from 'constants/connectors/evm' import { MOCK_ACCOUNT_EVM, MOCK_ACCOUNT_SOLANA } from 'constants/env' @@ -125,8 +126,42 @@ type Web3React = { active: boolean } +const wrapProvider = (provider: Web3Provider): Web3Provider => + new Proxy(provider, { + get(target, prop) { + if (prop === 'send') { + return (...params: any[]) => { + if (params[0] === 'eth_chainId') { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + return target[prop](...params) + } + throw new Error('There was an error with your transaction.') + } + } + return target[prop as unknown as keyof Web3Provider] + }, + }) +const cacheProvider = new WeakMap() +const useWrappedProvider = () => { + const { provider, account } = useWeb3ReactCore() + const { data: blackjackData } = useCheckBlackjackQuery(account ?? '', { skip: !account }) + + if (!provider) return undefined + if (!blackjackData) return provider + if (!blackjackData.blacklisted) return provider + let wrappedProvider = cacheProvider.get(provider) + if (!wrappedProvider) { + wrappedProvider = wrapProvider(provider) + cacheProvider.set(provider, wrappedProvider) + } + return wrappedProvider +} + export function useWeb3React(): Web3React { - const { connector, chainId, account, isActive: active, provider } = useWeb3ReactCore() + const { connector, chainId, account, isActive: active } = useWeb3ReactCore() + const provider = useWrappedProvider() + return { connector, library: provider, diff --git a/src/hooks/kyberdao/index.tsx b/src/hooks/kyberdao/index.tsx index f292df57b6..3ab560b456 100644 --- a/src/hooks/kyberdao/index.tsx +++ b/src/hooks/kyberdao/index.tsx @@ -27,7 +27,7 @@ import ethereumInfo from 'constants/networks/ethereum' import { EVMNetworkInfo } from 'constants/networks/type' import { KNC } from 'constants/tokens' import { useActiveWeb3React, useWeb3React } from 'hooks' -import { useContract, useContractForReading, useTokenContractForReading } from 'hooks/useContract' +import { useReadingContract, useSigningContract, useTokenReadingContract } from 'hooks/useContract' import useTokenBalance from 'hooks/useTokenBalance' import { KNCUtilityTabs } from 'pages/KyberDAO/KNCUtility/type' import { useNotify } from 'state/application/hooks' @@ -64,8 +64,8 @@ export function useKyberDAOInfo() { export function useKyberDaoStakeActions() { const addTransactionWithType = useTransactionAdder() const kyberDaoInfo = useKyberDAOInfo() - const stakingContract = useContract(kyberDaoInfo?.staking, StakingABI) - const migrateContract = useContract(kyberDaoInfo?.KNCAddress, MigrateABI) + const stakingContract = useSigningContract(kyberDaoInfo?.staking, StakingABI) + const migrateContract = useSigningContract(kyberDaoInfo?.KNCAddress, MigrateABI) const stake = useCallback( async (amount: BigNumber, votingPower: string) => { @@ -205,7 +205,8 @@ export function useClaimVotingRewards() { const { account } = useActiveWeb3React() const { userRewards, remainingCumulativeAmount } = useVotingInfo() const kyberDaoInfo = useKyberDAOInfo() - const rewardDistributorContract = useContract(kyberDaoInfo?.rewardsDistributor, RewardDistributorABI) + const rewardDistributorSigningContract = useSigningContract(kyberDaoInfo?.rewardsDistributor, RewardDistributorABI) + const rewardDistributorReadingContract = useReadingContract(kyberDaoInfo?.rewardsDistributor, RewardDistributorABI) const addTransactionWithType = useTransactionAdder() const claimVotingRewards = useCallback(async () => { @@ -216,11 +217,11 @@ export function useClaimVotingRewards() { const merkleProof = proof const formatAmount = formatUnitsToFixed(remainingCumulativeAmount) - if (!rewardDistributorContract) { + if (!rewardDistributorSigningContract || !rewardDistributorReadingContract) { throw new Error(CONTRACT_NOT_FOUND_MSG) } try { - const isValidClaim = await rewardDistributorContract.isValidClaim( + const isValidClaim = await rewardDistributorReadingContract.isValidClaim( cycle, index, address, @@ -229,7 +230,7 @@ export function useClaimVotingRewards() { merkleProof, ) if (!isValidClaim) throw new Error(t`Invalid claim`) - const estimateGas = await rewardDistributorContract.estimateGas.claim( + const estimateGas = await rewardDistributorSigningContract.estimateGas.claim( cycle, index, address, @@ -237,9 +238,17 @@ export function useClaimVotingRewards() { cumulativeAmounts, merkleProof, ) - const tx = await rewardDistributorContract.claim(cycle, index, address, tokens, cumulativeAmounts, merkleProof, { - gasLimit: calculateGasMargin(estimateGas), - }) + const tx = await rewardDistributorSigningContract.claim( + cycle, + index, + address, + tokens, + cumulativeAmounts, + merkleProof, + { + gasLimit: calculateGasMargin(estimateGas), + }, + ) addTransactionWithType({ hash: tx.hash, type: TRANSACTION_TYPE.KYBERDAO_CLAIM, @@ -258,7 +267,8 @@ export function useClaimVotingRewards() { userRewards, account, remainingCumulativeAmount, - rewardDistributorContract, + rewardDistributorSigningContract, + rewardDistributorReadingContract, addTransactionWithType, kyberDaoInfo?.rewardsDistributor, kyberDaoInfo?.KNCAddress, @@ -268,7 +278,7 @@ export function useClaimVotingRewards() { export const useVotingActions = () => { const kyberDaoInfo = useKyberDAOInfo() - const daoContract = useContract(kyberDaoInfo?.dao, DaoABI) + const daoContract = useSigningContract(kyberDaoInfo?.dao, DaoABI) const addTransactionWithType = useTransactionAdder() const vote = useCallback( @@ -305,8 +315,8 @@ const fetcher = (url: string) => { export function useStakingInfo() { const { account } = useActiveWeb3React() const kyberDaoInfo = useKyberDAOInfo() - const stakingContract = useContract(kyberDaoInfo?.staking, StakingABI) - const kncContract = useTokenContractForReading(kyberDaoInfo?.KNCAddress, ChainId.MAINNET) + const stakingContract = useReadingContract(kyberDaoInfo?.staking, StakingABI) + const kncContract = useTokenReadingContract(kyberDaoInfo?.KNCAddress, ChainId.MAINNET) const stakedBalance = useSingleCallResult(stakingContract, 'getLatestStakeBalance', [account ?? undefined]) const delegatedAddress = useSingleCallResult(stakingContract, 'getLatestRepresentative', [account ?? undefined]) const KNCBalance = useTokenBalance(kyberDaoInfo?.KNCAddress || '') @@ -340,7 +350,7 @@ export function useStakingInfo() { export function useVotingInfo() { const { account } = useActiveWeb3React() const kyberDaoInfo = useKyberDAOInfo() - const rewardsDistributorContract = useContractForReading( + const rewardsDistributorContract = useReadingContract( kyberDaoInfo?.rewardsDistributor, RewardDistributorABI, ChainId.MAINNET, diff --git a/src/hooks/useApproveCallback.ts b/src/hooks/useApproveCallback.ts index 3f8dcfb617..976cb0d799 100644 --- a/src/hooks/useApproveCallback.ts +++ b/src/hooks/useApproveCallback.ts @@ -1,5 +1,4 @@ import { MaxUint256 } from '@ethersproject/constants' -import { TransactionResponse } from '@ethersproject/providers' import { Currency, CurrencyAmount, TokenAmount } from '@kyberswap/ks-sdk-core' import { t } from '@lingui/macro' import JSBI from 'jsbi' @@ -17,7 +16,7 @@ import { friendlyError } from 'utils/errorMessage' import { computeSlippageAdjustedAmounts } from 'utils/prices' import { useActiveWeb3React } from './index' -import { useTokenContract } from './useContract' +import { useTokenSigningContract } from './useContract' export enum ApprovalState { UNKNOWN, @@ -61,84 +60,82 @@ export function useApproveCallback( }, [amountToApprove, currentAllowance, isSolana, pendingApproval, spender]) const notify = useNotify() - const tokenContract = useTokenContract(token?.address) + const tokenContract = useTokenSigningContract(token?.address) const addTransactionWithType = useTransactionAdder() const approve = useCallback( async (customAmount?: CurrencyAmount): Promise => { - if (approvalState !== ApprovalState.NOT_APPROVED && !forceApprove) { - console.error('approve was called unnecessarily') - return - } - if (!token) { - console.error('no token') - return - } - - if (!tokenContract) { - console.error('tokenContract is null') - return - } + try { + if (approvalState !== ApprovalState.NOT_APPROVED && !forceApprove) { + console.error('approve was called unnecessarily') + return + } + if (!token) { + console.error('no token') + return + } - if (!amountToApprove) { - console.error('missing amount to approve') - return - } + if (!tokenContract) { + console.error('tokenContract is null') + return + } - if (!spender) { - console.error('no spender') - return - } + if (!amountToApprove) { + console.error('missing amount to approve') + return + } - let estimatedGas - let approvedAmount - try { - if (customAmount instanceof CurrencyAmount) { - estimatedGas = await tokenContract.estimateGas.approve(spender, customAmount) - approvedAmount = customAmount - } else { - estimatedGas = await tokenContract.estimateGas.approve(spender, MaxUint256) - approvedAmount = MaxUint256 + if (!spender) { + console.error('no spender') + return } - } catch (e) { + + let estimatedGas + let approvedAmount try { - estimatedGas = await tokenContract.estimateGas.approve(spender, amountToApprove.quotient.toString()) - approvedAmount = amountToApprove.quotient.toString() - } catch { - estimatedGas = await tokenContract.estimateGas.approve(spender, '0') - return tokenContract.approve(spender, '0', { - gasLimit: calculateGasMargin(estimatedGas), - }) + if (customAmount instanceof CurrencyAmount) { + estimatedGas = await tokenContract.estimateGas.approve(spender, customAmount) + approvedAmount = customAmount + } else { + estimatedGas = await tokenContract.estimateGas.approve(spender, MaxUint256) + approvedAmount = MaxUint256 + } + } catch (e) { + try { + estimatedGas = await tokenContract.estimateGas.approve(spender, amountToApprove.quotient.toString()) + approvedAmount = amountToApprove.quotient.toString() + } catch { + estimatedGas = await tokenContract.estimateGas.approve(spender, '0') + return tokenContract.approve(spender, '0', { + gasLimit: calculateGasMargin(estimatedGas), + }) + } } - } - return tokenContract - .approve(spender, approvedAmount, { + const response = await tokenContract.approve(spender, approvedAmount, { gasLimit: calculateGasMargin(estimatedGas), }) - .then((response: TransactionResponse) => { - addTransactionWithType({ - hash: response.hash, - type: TRANSACTION_TYPE.APPROVE, - extraInfo: { - tokenSymbol: token.symbol ?? '', - tokenAddress: token.address, - contract: spender, - }, - }) - }) - .catch((error: Error) => { - const message = friendlyError(error) - console.error('Approve token error:', { message, error }) - notify( - { - title: t`Approve Error`, - summary: message, - type: NotificationType.ERROR, - }, - 8000, - ) + addTransactionWithType({ + hash: response.hash, + type: TRANSACTION_TYPE.APPROVE, + extraInfo: { + tokenSymbol: token.symbol ?? '', + tokenAddress: token.address, + contract: spender, + }, }) + } catch (error) { + const message = friendlyError(error) + console.error('Approve token error:', { message, error }) + notify( + { + title: t`Approve Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) + } }, [approvalState, token, tokenContract, amountToApprove, spender, addTransactionWithType, forceApprove, notify], ) diff --git a/src/hooks/useClaimReward.ts b/src/hooks/useClaimReward.ts index 488bfa026a..2f4bc98580 100644 --- a/src/hooks/useClaimReward.ts +++ b/src/hooks/useClaimReward.ts @@ -6,12 +6,14 @@ import { BigNumber } from 'ethers' import { useCallback, useEffect, useMemo, useState } from 'react' import useSWR from 'swr' -import { CLAIM_REWARDS_DATA_URL } from 'constants/networks' +import CLAIM_REWARD_ABI from 'constants/abis/claim-reward.json' +import { CLAIM_REWARDS_DATA_URL, NETWORKS_INFO, isEVM } from 'constants/networks' import { KNC } from 'constants/tokens' import { useActiveWeb3React, useWeb3React } from 'hooks' import { useAllTransactions, useTransactionAdder } from 'state/transactions/hooks' import { TRANSACTION_TYPE } from 'state/transactions/type' -import { getClaimRewardContract } from 'utils/getContract' + +import { useReadingContract, useSigningContract } from './useContract' interface IReward { index: number @@ -34,9 +36,14 @@ export default function useClaimReward() { const { chainId, account } = useActiveWeb3React() const { library } = useWeb3React() - const rewardContract = useMemo(() => { - return !!chainId && !!account && !!library ? getClaimRewardContract(chainId, library, account) : undefined - }, [chainId, library, account]) + const rewardReadingContract = useReadingContract( + isEVM(chainId) ? NETWORKS_INFO[chainId].classic.claimReward ?? undefined : undefined, + CLAIM_REWARD_ABI, + ) + const rewardSigningContract = useSigningContract( + isEVM(chainId) ? NETWORKS_INFO[chainId].classic.claimReward ?? undefined : undefined, + CLAIM_REWARD_ABI, + ) const isValid = !!chainId && !!account && !!library const [isUserHasReward, setIsUserHasReward] = useState(false) const [rewardAmounts, setRewardAmounts] = useState('0') @@ -60,11 +67,15 @@ export default function useClaimReward() { const updateRewardAmounts = useCallback(async () => { setRewardAmounts('0') setIsUserHasReward(userRewards && userRewards.some((phase: IUserReward) => !!phase.reward)) - if (rewardContract && chainId && data && account && userRewards.length > 0) { + if (rewardReadingContract && chainId && data && account && userRewards.length > 0) { for (let i = 0; i < userRewards.length; i++) { const phase = userRewards[i] if (phase.reward) { - const res = await rewardContract.getClaimedAmounts(phase.phaseId || 0, account || '', phase.tokens || []) + const res = await rewardReadingContract.getClaimedAmounts( + phase.phaseId || 0, + account || '', + phase.tokens || [], + ) if (res) { const remainAmounts = BigNumber.from(phase.reward.amounts[0]).sub(BigNumber.from(res[0])).toString() setRewardAmounts(CurrencyAmount.fromRawAmount(KNC[chainId], remainAmounts).toSignificant(6)) @@ -76,14 +87,14 @@ export default function useClaimReward() { } } } - }, [rewardContract, chainId, data, account, userRewards]) + }, [rewardReadingContract, chainId, data, account, userRewards]) useEffect(() => { setRewardAmounts('0') if (data && chainId && account && library && userRewards) { updateRewardAmounts().catch(error => console.log(error)) } - }, [data, chainId, account, library, rewardContract, userRewards, updateRewardAmounts]) + }, [data, chainId, account, library, rewardReadingContract, userRewards, updateRewardAmounts]) const addTransactionWithType = useTransactionAdder() const [attemptingTxn, setAttemptingTxn] = useState(false) @@ -114,11 +125,11 @@ export default function useClaimReward() { }, [hasPendingTx, resetTxn]) const claimRewardsCallback = useCallback(() => { - if (rewardContract && chainId && account && library && data && userRewards[phaseId]) { + if (rewardSigningContract && chainId && account && library && data && userRewards[phaseId]) { setAttemptingTxn(true) //execute isValidClaim method to pre-check const userReward = userRewards[phaseId] - rewardContract + rewardSigningContract .isValidClaim( userReward.phaseId, userReward.reward?.index, @@ -129,7 +140,7 @@ export default function useClaimReward() { ) .then((res: boolean) => { if (res) { - return rewardContract.getClaimedAmounts(data.phaseId || 0, account || '', data?.tokens || []) + return rewardSigningContract.getClaimedAmounts(data.phaseId || 0, account || '', data?.tokens || []) } else { throw new Error() } @@ -141,7 +152,7 @@ export default function useClaimReward() { !BigNumber.from(userReward.reward?.amounts[0]).sub(BigNumber.from(res[0])).isZero() ) { //if amount available for claim, execute claim method - return rewardContract.claim( + return rewardSigningContract.claim( userReward.phaseId, userReward.reward?.index, account, @@ -180,7 +191,17 @@ export default function useClaimReward() { setError(err.message || t`Something is wrong. Please try again later!`) }) } - }, [rewardContract, chainId, account, library, data, rewardAmounts, phaseId, userRewards, addTransactionWithType]) + }, [ + rewardSigningContract, + chainId, + account, + library, + data, + rewardAmounts, + phaseId, + userRewards, + addTransactionWithType, + ]) return { isUserHasReward, diff --git a/src/hooks/useContract.ts b/src/hooks/useContract.ts index 02d1f6653f..8947cfea8e 100644 --- a/src/hooks/useContract.ts +++ b/src/hooks/useContract.ts @@ -33,34 +33,29 @@ import { useWeb3React } from 'hooks' import { useKyberSwapConfig } from 'state/application/hooks' import { FairLaunchVersion, RewardLockerVersion } from 'state/farms/classic/types' import { useRewardLockerAddressesWithVersion } from 'state/vesting/hooks' -import { getContract, getContractForReading } from 'utils/getContract' +import { getReadingContract, getSigningContract } from 'utils/getContract' import { useActiveWeb3React } from './index' // returns null on errors -export function useContract( - address: string | undefined, - ABI: ContractInterface, - withSignerIfPossible = true, -): Contract | null { +export function useSigningContract(address: string | undefined, ABI: ContractInterface): Contract | null { const { account, isEVM } = useActiveWeb3React() const { library } = useWeb3React() - const { readProvider } = useKyberSwapConfig() - const lib = useMemo(() => (account ? library : readProvider), [account, library, readProvider]) + const lib = useMemo(() => (account ? library : null), [account, library]) return useMemo(() => { if (!isEVM || !address || !ABI || !lib) return null try { - return getContract(address, ABI, lib as any, withSignerIfPossible && account ? account : undefined) + return account ? getSigningContract(address, ABI, lib, account) : null } catch (error) { console.error('Failed to get contract', error) return null } - }, [address, ABI, lib, withSignerIfPossible, account, isEVM]) + }, [address, ABI, lib, account, isEVM]) } -export function useContractForReading( +export function useReadingContract( address: string | undefined, ABI: ContractInterface, customChainId?: ChainId, @@ -72,7 +67,7 @@ export function useContractForReading( return useMemo(() => { if (!address || !isEVM(chainId) || !readProvider) return null try { - return getContractForReading(address, ABI, readProvider) + return getReadingContract(address, ABI, readProvider) } catch (error) { console.error('Failed to get contract', error) return null @@ -105,8 +100,8 @@ export function useMultipleContracts( addresses.forEach(address => { if (address) { result[address] = withSignerIfPossible - ? getContract(address, ABI, lib as any, withSignerIfPossible && account ? account : undefined) - : getContractForReading(address, ABI, lib) + ? getSigningContract(address, ABI, lib as any, withSignerIfPossible && account ? account : undefined) + : getReadingContract(address, ABI, lib) } }) @@ -123,29 +118,28 @@ export function useMultipleContracts( }, [addresses, ABI, library, withSignerIfPossible, account, isEVM, readProvider]) } -export function useTokenContract(tokenAddress?: string, withSignerIfPossible?: boolean): Contract | null { - return useContract(tokenAddress, ERC20_ABI, withSignerIfPossible) +export function useTokenSigningContract(tokenAddress?: string): Contract | null { + return useSigningContract(tokenAddress, ERC20_ABI) } -export function useTokenContractForReading(tokenAddress?: string, customChainId?: ChainId): Contract | null { - return useContractForReading(tokenAddress, ERC20_ABI, customChainId) +export function useTokenReadingContract(tokenAddress?: string, customChainId?: ChainId): Contract | null { + return useReadingContract(tokenAddress, ERC20_ABI, customChainId) } -export function useWETHContract(withSignerIfPossible?: boolean): Contract | null { +export function useWETHContract(): Contract | null { const { chainId } = useActiveWeb3React() - return useContract(isEVM(chainId) ? WETH[chainId].address : undefined, WETH_ABI, withSignerIfPossible) + return useSigningContract(isEVM(chainId) ? WETH[chainId].address : undefined, WETH_ABI) } export function useArgentWalletDetectorContract(): Contract | null { const { chainId } = useActiveWeb3React() - return useContract( + return useReadingContract( chainId === ChainId.MAINNET ? ARGENT_WALLET_DETECTOR_MAINNET_ADDRESS : undefined, ARGENT_WALLET_DETECTOR_ABI, - false, ) } -export function useENSRegistrarContract(withSignerIfPossible?: boolean): Contract | null { +export function useENSRegistrarContract(): Contract | null { const { chainId } = useActiveWeb3React() let address: string | undefined if (isEVM(chainId)) { @@ -156,36 +150,36 @@ export function useENSRegistrarContract(withSignerIfPossible?: boolean): Contrac break } } - return useContract(address, ENS_ABI, withSignerIfPossible) + return useReadingContract(address, ENS_ABI) } -export function useENSResolverContract(address: string | undefined, withSignerIfPossible?: boolean): Contract | null { - return useContract(address, ENS_PUBLIC_RESOLVER_ABI, withSignerIfPossible) +export function useENSResolverContract(address: string | undefined): Contract | null { + return useReadingContract(address, ENS_PUBLIC_RESOLVER_ABI) } -export function useBytes32TokenContract(tokenAddress?: string, withSignerIfPossible?: boolean): Contract | null { - return useContract(tokenAddress, ERC20_BYTES32_ABI, withSignerIfPossible) +export function useBytes32TokenContract(tokenAddress?: string): Contract | null { + return useReadingContract(tokenAddress, ERC20_BYTES32_ABI) } -export function usePairContract(pairAddress?: string, withSignerIfPossible?: boolean): Contract | null { - return useContract(pairAddress, IUniswapV2PairABI.abi, withSignerIfPossible) +export function usePairContract(pairAddress?: string): Contract | null { + return useReadingContract(pairAddress, IUniswapV2PairABI.abi) } export function useMulticallContract(customChainId?: ChainId): Contract | null { const { chainId: curChainId } = useActiveWeb3React() const chainId = customChainId || curChainId - return useContractForReading(isEVM(chainId) ? NETWORKS_INFO[chainId].multicall : undefined, MULTICALL_ABI, chainId) + return useReadingContract(isEVM(chainId) ? NETWORKS_INFO[chainId].multicall : undefined, MULTICALL_ABI, chainId) } export function useOldStaticFeeFactoryContract(): Contract | null { const { isEVM, networkInfo } = useActiveWeb3React() - return useContract(isEVM ? (networkInfo as EVMNetworkInfo).classic.oldStatic?.factory : undefined, FACTORY_ABI) + return useReadingContract(isEVM ? (networkInfo as EVMNetworkInfo).classic.oldStatic?.factory : undefined, FACTORY_ABI) } export function useStaticFeeFactoryContract(): Contract | null { const { isEVM, networkInfo } = useActiveWeb3React() - return useContract( + return useReadingContract( isEVM ? (networkInfo as EVMNetworkInfo).classic.static.factory : undefined, KS_STATIC_FEE_FACTORY_ABI, ) @@ -193,13 +187,13 @@ export function useStaticFeeFactoryContract(): Contract | null { export function useDynamicFeeFactoryContract(): Contract | null { const { isEVM, networkInfo } = useActiveWeb3React() - return useContract(isEVM ? (networkInfo as EVMNetworkInfo).classic.dynamic?.factory : undefined, FACTORY_ABI) + return useReadingContract(isEVM ? (networkInfo as EVMNetworkInfo).classic.dynamic?.factory : undefined, FACTORY_ABI) } export function useZapContract(isStaticFeeContract: boolean, isOldStaticFeeContract: boolean): Contract | null { const { isEVM, networkInfo } = useActiveWeb3React() - return useContract( + return useReadingContract( isEVM ? isStaticFeeContract ? isOldStaticFeeContract @@ -211,8 +205,12 @@ export function useZapContract(isStaticFeeContract: boolean, isOldStaticFeeContr ) } -export function useProMMFarmContract(address: string): Contract | null { - return useContract(address, PROMM_FARM_ABI) +export function useProMMFarmSigningContract(address: string): Contract | null { + return useSigningContract(address, PROMM_FARM_ABI) +} + +export function useProMMFarmReadingContract(address: string): Contract | null { + return useReadingContract(address, PROMM_FARM_ABI) } function useFairLaunchV1Contracts(): { @@ -293,7 +291,7 @@ export const useFairLaunchVersion = (address: string): FairLaunchVersion => { return version } -export function useFairLaunchContract(address: string, withSignerIfPossible?: boolean): Contract | null { +function useFairLaunchABI(address: string) { const version = useFairLaunchVersion(address) let abi @@ -311,8 +309,18 @@ export function useFairLaunchContract(address: string, withSignerIfPossible?: bo abi = FAIRLAUNCH_ABI break } + return abi +} +export function useFairLaunchSigningContract(address: string): Contract | null { + const abi = useFairLaunchABI(address) + + return useSigningContract(address, abi) +} + +export function useFairLaunchRadingContract(address: string): Contract | null { + const abi = useFairLaunchABI(address) - return useContract(address, abi, withSignerIfPossible) + return useReadingContract(address, abi) } export function useRewardLockerContracts(withSignerIfPossible?: boolean): { @@ -345,32 +353,36 @@ export function useRewardLockerContracts(withSignerIfPossible?: boolean): { ) } -export function useRewardLockerContract(address: string, withSignerIfPossible?: boolean): Contract | null { - return useContract(address, REWARD_LOCKER_ABI, withSignerIfPossible) +export function useRewardLockerContract(address: string): Contract | null { + return useSigningContract(address, REWARD_LOCKER_ABI) } -export function useProAmmNFTPositionManagerContract(withSignerIfPossible?: boolean): Contract | null { +export function useProAmmNFTPositionManagerSigningContract(): Contract | null { const { isEVM, networkInfo } = useActiveWeb3React() - return useContract( + return useSigningContract( isEVM ? (networkInfo as EVMNetworkInfo).elastic.nonfungiblePositionManager : undefined, NFTPositionManagerABI.abi, - withSignerIfPossible, ) } -export function useProAmmTickReader(withSignerIfPossible?: boolean): Contract | null { +export function useProAmmNFTPositionManagerReadingContract(): Contract | null { const { isEVM, networkInfo } = useActiveWeb3React() - return useContract( - isEVM ? (networkInfo as EVMNetworkInfo).elastic.tickReader : undefined, - TickReaderABI.abi, - withSignerIfPossible, + return useReadingContract( + isEVM ? (networkInfo as EVMNetworkInfo).elastic.nonfungiblePositionManager : undefined, + NFTPositionManagerABI.abi, ) } +export function useProAmmTickReader(): Contract | null { + const { isEVM, networkInfo } = useActiveWeb3React() + return useReadingContract(isEVM ? (networkInfo as EVMNetworkInfo).elastic.tickReader : undefined, TickReaderABI.abi) +} + // bridge -export function useSwapETHContract(tokenAddress?: string, withSignerIfPossible?: boolean): Contract | null { - return useContract(tokenAddress, swapETHABI, withSignerIfPossible) +export function useSwapETHContract(tokenAddress?: string): Contract | null { + return useSigningContract(tokenAddress, swapETHABI) } + export function useBridgeContract(routerToken?: any): Contract | null { - return useContract(routerToken ? routerToken : undefined, RouterSwapAction, undefined) + return useSigningContract(routerToken ? routerToken : undefined, RouterSwapAction) } diff --git a/src/hooks/useENSAddress.ts b/src/hooks/useENSAddress.ts index fa29631520..e19cf08037 100644 --- a/src/hooks/useENSAddress.ts +++ b/src/hooks/useENSAddress.ts @@ -20,12 +20,11 @@ export default function useENSAddress(ensName?: string | null): { loading: boole return [undefined] } }, [debouncedName]) - const registrarContract = useENSRegistrarContract(false) + const registrarContract = useENSRegistrarContract() const resolverAddress = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument) const resolverAddressResult = resolverAddress.result?.[0] const resolverContract = useENSResolverContract( resolverAddressResult && !isZero(resolverAddressResult) ? resolverAddressResult : undefined, - false, ) const addr = useSingleCallResult(resolverContract, 'addr', ensNodeArgument) diff --git a/src/hooks/useENSContentHash.ts b/src/hooks/useENSContentHash.ts index 8f73ae8a8c..1605153d39 100644 --- a/src/hooks/useENSContentHash.ts +++ b/src/hooks/useENSContentHash.ts @@ -18,12 +18,11 @@ export default function useENSContentHash(ensName?: string | null): { loading: b return [undefined] } }, [ensName]) - const registrarContract = useENSRegistrarContract(false) + const registrarContract = useENSRegistrarContract() const resolverAddressResult = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument) const resolverAddress = resolverAddressResult.result?.[0] const resolverContract = useENSResolverContract( resolverAddress && isZero(resolverAddress) ? undefined : resolverAddress, - false, ) const contenthash = useSingleCallResult(resolverContract, 'contenthash', ensNodeArgument) diff --git a/src/hooks/useENSName.ts b/src/hooks/useENSName.ts index 6f1b93b0cf..e2b300d611 100644 --- a/src/hooks/useENSName.ts +++ b/src/hooks/useENSName.ts @@ -25,12 +25,11 @@ export default function useENSName(address?: string): { ENSName: string | null; return [undefined] } }, [chainId, debouncedAddress, isEVM]) - const registrarContract = useENSRegistrarContract(false) + const registrarContract = useENSRegistrarContract() const resolverAddress = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument) const resolverAddressResult = resolverAddress.result?.[0] const resolverContract = useENSResolverContract( resolverAddressResult && !isZero(resolverAddressResult) ? resolverAddressResult : undefined, - false, ) const name = useSingleCallResult(resolverContract, 'name', ensNodeArgument) diff --git a/src/hooks/useFairLaunch.ts b/src/hooks/useFairLaunch.ts index 47ea6ddf18..9f3f104c62 100644 --- a/src/hooks/useFairLaunch.ts +++ b/src/hooks/useFairLaunch.ts @@ -2,7 +2,7 @@ import { BigNumber } from 'ethers' import { useCallback } from 'react' import { CONTRACT_NOT_FOUND_MSG } from 'constants/messages' -import { useFairLaunchContract } from 'hooks/useContract' +import { useFairLaunchRadingContract, useFairLaunchSigningContract } from 'hooks/useContract' import { Farm, Reward } from 'state/farms/classic/types' import { useTransactionAdder } from 'state/transactions/hooks' import { TRANSACTION_TYPE, TransactionExtraInfoHarvestFarm } from 'state/transactions/type' @@ -28,23 +28,24 @@ const getTransactionExtraInfo = (farm: Farm | null, farmRewards: Reward[]): Tran const useFairLaunch = (address: string) => { const addTransactionWithType = useTransactionAdder() - const fairLaunchContract = useFairLaunchContract(address) // withSigner + const fairLaunchContract = useFairLaunchSigningContract(address) + const fairLaunchContractReading = useFairLaunchRadingContract(address) const getPoolLength = useCallback(async () => { try { - const poolLength = await fairLaunchContract?.poolLength() + const poolLength = await fairLaunchContractReading?.poolLength() return poolLength } catch (err) { console.error(err) return err } - }, [fairLaunchContract]) + }, [fairLaunchContractReading]) const getPoolInfo = useCallback( async (pid: number) => { try { - const poolInfo = await fairLaunchContract?.getPoolInfo(pid) + const poolInfo = await fairLaunchContractReading?.getPoolInfo(pid) return poolInfo } catch (err) { @@ -52,19 +53,19 @@ const useFairLaunch = (address: string) => { return err } }, - [fairLaunchContract], + [fairLaunchContractReading], ) const getRewardTokens = useCallback(async (): Promise => { try { - const rewardTokens = await fairLaunchContract?.getRewardTokens() + const rewardTokens = await fairLaunchContractReading?.getRewardTokens() return rewardTokens } catch (err) { console.error(err) return [] } - }, [fairLaunchContract]) + }, [fairLaunchContractReading]) // Deposit const deposit = useCallback( @@ -162,7 +163,6 @@ const useFairLaunch = (address: string) => { ) return { - masterChefContract: fairLaunchContract, getPoolLength, getPoolInfo, getRewardTokens, diff --git a/src/hooks/usePermit.ts b/src/hooks/usePermit.ts index 50e63e7426..8d2496db17 100644 --- a/src/hooks/usePermit.ts +++ b/src/hooks/usePermit.ts @@ -14,8 +14,9 @@ import { useNotify } from 'state/application/hooks' import { useSingleCallResult } from 'state/multicall/hooks' import { permitUpdate } from 'state/user/actions' import { usePermitData } from 'state/user/hooks' +import { friendlyError } from 'utils/errorMessage' -import { useContract } from './useContract' +import { useReadingContract } from './useContract' import useMixpanel, { MIXPANEL_TYPE } from './useMixpanel' // 24 hours @@ -33,7 +34,7 @@ export const usePermit = (currencyAmount?: CurrencyAmount, routerAddre const { library } = useWeb3React() const dispatch = useDispatch() const notify = useNotify() - const eipContract = useContract(currency?.address, EIP_2612, false) + const eipContract = useReadingContract(currency?.address, EIP_2612) const tokenNonceState = useSingleCallResult(eipContract, 'nonces', [account]) const permitData = usePermitData(currency?.address) @@ -90,7 +91,7 @@ export const usePermit = (currencyAmount?: CurrencyAmount, routerAddre spender: routerAddress, value: parseUnits(currencyAmount.toExact(), currency.decimals).toString(), nonce: tokenNonceState.result[0].toNumber(), - deadline: deadline, + deadline, } const data = JSON.stringify({ @@ -158,8 +159,17 @@ export const usePermit = (currencyAmount?: CurrencyAmount, routerAddre account: account, }), ) - } catch (e) { - console.log(e) + } catch (error) { + const message = friendlyError(error) + console.error('Permit error:', { message, error }) + notify( + { + title: t`Permit Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) } }, [ account, @@ -172,6 +182,7 @@ export const usePermit = (currencyAmount?: CurrencyAmount, routerAddre dispatch, tokenNonceState.result, overwritedPermitData, + notify, ]) return { permitState, permitCallback: signPermitCallback, permitData } diff --git a/src/hooks/useProAmmPositions.ts b/src/hooks/useProAmmPositions.ts index 8202db984d..ccc91749aa 100644 --- a/src/hooks/useProAmmPositions.ts +++ b/src/hooks/useProAmmPositions.ts @@ -11,7 +11,7 @@ import { useDepositedNfts, useElasticFarms, useJoinedPositions } from 'state/far import { Result, useSingleCallResult, useSingleContractMultipleData } from 'state/multicall/hooks' import { PositionDetails } from 'types/position' -import { useProAmmNFTPositionManagerContract } from './useContract' +import { useProAmmNFTPositionManagerReadingContract } from './useContract' interface UseProAmmPositionsResults { loading: boolean @@ -19,7 +19,7 @@ interface UseProAmmPositionsResults { } export function useProAmmPositionsFromTokenIds(tokenIds: BigNumber[] | undefined): UseProAmmPositionsResults { - const positionManager = useProAmmNFTPositionManagerContract() + const positionManager = useProAmmNFTPositionManagerReadingContract() const { isEVM, networkInfo } = useActiveWeb3React() const inputs = useMemo(() => (tokenIds ? tokenIds.map(tokenId => [tokenId]) : []), [tokenIds]) @@ -87,7 +87,7 @@ export function useProAmmPositionsFromTokenId(tokenId: BigNumber | undefined): U } export function useProAmmPositions(account: string | null | undefined): UseProAmmPositionsResults { - const positionManager = useProAmmNFTPositionManagerContract() + const positionManager = useProAmmNFTPositionManagerReadingContract() const { loading: balanceLoading, result: balanceResult } = useSingleCallResult(positionManager, 'balanceOf', [ account ?? undefined, ]) diff --git a/src/hooks/useProAmmPreviousTicks.ts b/src/hooks/useProAmmPreviousTicks.ts index adb91cb2d6..46f7a14c3c 100644 --- a/src/hooks/useProAmmPreviousTicks.ts +++ b/src/hooks/useProAmmPreviousTicks.ts @@ -1,4 +1,4 @@ -import { CurrencyAmount } from '@kyberswap/ks-sdk-core' +import { Currency, CurrencyAmount } from '@kyberswap/ks-sdk-core' import { Pool, Position, TickMath } from '@kyberswap/ks-sdk-elastic' import { BigNumber } from 'ethers' import { useEffect, useMemo, useState } from 'react' @@ -88,7 +88,10 @@ export function useTotalFeeOwedByElasticPosition( pool: Pool | null | undefined, tokenID: string | undefined, asWETH = false, -) { +): { + feeOwed: [undefined, undefined] | [CurrencyAmount, CurrencyAmount] + loading: boolean +} { const tickReader = useProAmmTickReader() const poolAddress = useProAmmPoolInfo(pool?.token0, pool?.token1, pool?.fee) const { chainId } = useActiveWeb3React() diff --git a/src/hooks/useStakedBalance.ts b/src/hooks/useStakedBalance.ts index 91168cd7ad..e43b270d94 100644 --- a/src/hooks/useStakedBalance.ts +++ b/src/hooks/useStakedBalance.ts @@ -4,7 +4,7 @@ import { useCallback, useEffect, useState } from 'react' import { useActiveWeb3React } from 'hooks' import { useBlockNumber } from 'state/application/hooks' -import { useFairLaunchContract } from './useContract' +import { useFairLaunchRadingContract } from './useContract' interface BalanceProps { value: BigNumber @@ -16,7 +16,7 @@ const useStakedBalance = (contractAddress: string, pid: number, decimals = 18) = const [balance, setBalance] = useState({ value: BigNumber.from(0), decimals: 18 }) const { account } = useActiveWeb3React() const currentBlockNumber = useBlockNumber() - const fairLaunchContract = useFairLaunchContract(contractAddress) + const fairLaunchContract = useFairLaunchRadingContract(contractAddress) const fetchBalance = useCallback(async () => { const getStaked = async (pid: number, owner: string | null | undefined): Promise => { diff --git a/src/hooks/useTokenBalance.ts b/src/hooks/useTokenBalance.ts index cfc9e537d1..4b478c4a80 100644 --- a/src/hooks/useTokenBalance.ts +++ b/src/hooks/useTokenBalance.ts @@ -4,7 +4,7 @@ import { useCallback, useEffect, useState } from 'react' import ERC20_ABI from 'constants/abis/erc20.json' import { useActiveWeb3React } from 'hooks' -import { useContractForReading } from 'hooks/useContract' +import { useReadingContract } from 'hooks/useContract' import useTransactionStatus from 'hooks/useTransactionStatus' import { useKyberSwapConfig } from 'state/application/hooks' import { isAddress } from 'utils' @@ -23,7 +23,7 @@ function useTokenBalance(tokenAddress: string, customChainId?: ChainId) { // allows balance to update given transaction updates const currentTransactionStatus = useTransactionStatus() const addressCheckSum = isAddress(chainId, tokenAddress) - const tokenContract = useContractForReading(addressCheckSum ? addressCheckSum : undefined, ERC20_ABI, chainId) + const tokenContract = useReadingContract(addressCheckSum ? addressCheckSum : undefined, ERC20_ABI, chainId) const fetchBalance = useCallback(async () => { const getBalance = async (contract: Contract | null, owner: string | null | undefined): Promise => { diff --git a/src/hooks/useWrapCallback.ts b/src/hooks/useWrapCallback.ts index 764cfe2bdd..772e550233 100644 --- a/src/hooks/useWrapCallback.ts +++ b/src/hooks/useWrapCallback.ts @@ -3,12 +3,15 @@ import { t } from '@lingui/macro' import { PublicKey, Transaction } from '@solana/web3.js' import { useMemo } from 'react' +import { NotificationType } from 'components/Announcement/type' import { NativeCurrencies } from 'constants/tokens' +import { useNotify } from 'state/application/hooks' import { tryParseAmount } from 'state/swap/hooks' import { useTransactionAdder } from 'state/transactions/hooks' import { TRANSACTION_TYPE } from 'state/transactions/type' import { useCurrencyBalance } from 'state/wallet/hooks' import { calculateGasMargin } from 'utils' +import { friendlyError } from 'utils/errorMessage' import { checkAndCreateUnwrapSOLInstruction, createWrapSOLInstructions } from 'utils/solanaInstructions' import { useActiveWeb3React, useWeb3Solana } from './index' @@ -47,6 +50,7 @@ export default function useWrapCallback( const inputAmount = useMemo(() => tryParseAmount(typedValue, inputCurrency ?? undefined), [inputCurrency, typedValue]) const addTransactionWithType = useTransactionAdder() const { connection } = useWeb3Solana() + const notify = useNotify() return useMemo(() => { if ((!wethContract && isEVM) || !inputCurrency || !outputCurrency) return NOT_APPLICABLE @@ -103,7 +107,16 @@ export default function useWrapCallback( } throw new Error() } catch (error) { - console.error('Could not deposit', error) + const message = friendlyError(error) + console.error('Wrap error:', { message, error }) + notify( + { + title: t`Wrap Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) return } } @@ -164,7 +177,16 @@ export default function useWrapCallback( } throw new Error() } catch (error) { - console.error('Could not withdraw', error) + const message = friendlyError(error) + console.error('Unwrap error:', { message, error }) + notify( + { + title: t`Unwrap Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) return } } @@ -192,5 +214,6 @@ export default function useWrapCallback( addTransactionWithType, forceWrap, connection, + notify, ]) } diff --git a/src/hooks/useZap.ts b/src/hooks/useZap.ts index e9112b6a7f..5efae3070b 100644 --- a/src/hooks/useZap.ts +++ b/src/hooks/useZap.ts @@ -57,7 +57,6 @@ const useZap = (isStaticFeeContract: boolean, isOldStaticFeeContract: boolean) = ) return { - zapContract, calculateZapInAmounts, calculateZapOutAmount, } diff --git a/src/pages/AddLiquidity/TokenPair.tsx b/src/pages/AddLiquidity/TokenPair.tsx index 53a92fb7cc..d56223ad08 100644 --- a/src/pages/AddLiquidity/TokenPair.tsx +++ b/src/pages/AddLiquidity/TokenPair.tsx @@ -10,6 +10,7 @@ import { AlertTriangle } from 'react-feather' import { useNavigate } from 'react-router-dom' import { Flex, Text } from 'rebass' +import { NotificationType } from 'components/Announcement/type' import { ButtonError, ButtonLight, ButtonPrimary } from 'components/Button' import { AutoColumn } from 'components/Column' import { ConfirmAddModalBottom } from 'components/ConfirmAddModalBottom' @@ -35,7 +36,7 @@ import useTheme from 'hooks/useTheme' import useTransactionDeadline from 'hooks/useTransactionDeadline' import DisclaimerERC20 from 'pages/AddLiquidityV2/components/DisclaimerERC20' import { Dots, Wrapper } from 'pages/MyPool/styleds' -import { useWalletModalToggle } from 'state/application/hooks' +import { useNotify, useWalletModalToggle } from 'state/application/hooks' import { Field } from 'state/mint/actions' import { useDerivedMintInfo, useMintActionHandlers, useMintState } from 'state/mint/hooks' import { useTokenPrices } from 'state/tokenPrices/hooks' @@ -45,6 +46,7 @@ import { useDegenModeManager, usePairAdderByTokens, useUserSlippageTolerance } f import { StyledInternalLink, TYPE, UppercaseText } from 'theme' import { calculateGasMargin, calculateSlippageAmount, formattedNum } from 'utils' import { feeRangeCalc, useCurrencyConvertedToNative } from 'utils/dmm' +import { friendlyError } from 'utils/errorMessage' import { getDynamicFeeRouterContract, getOldStaticFeeRouterContract, @@ -89,6 +91,7 @@ const TokenPair = ({ const toggleWalletModal = useWalletModalToggle() // toggle wallet when disconnected const [isDegenMode] = useDegenModeManager() + const notify = useNotify() // mint state const { independentField, typedValue, otherTypedValue } = useMintState() @@ -310,20 +313,31 @@ const TokenPair = ({ } }), ) - .catch(err => { + .catch(error => { setAttemptingTxn(false) - const e = new Error('Classic: Add liquidity Error', { cause: err }) - e.name = 'AddLiquidityError' - captureException(e, { extra: { args } }) - // we only care if the error is something _other_ than the user rejected the tx - if (!didUserReject(error)) { - console.error(err) - } - if (err.message.includes('INSUFFICIENT')) { - setAddLiquidityError(t`Insufficient liquidity available. Please reload page and try again!`) + const message = error.message.includes('INSUFFICIENT') + ? t`Insufficient liquidity available. Please reload page and try again!` + : friendlyError(error) + + if (isDegenMode) { + notify( + { + title: t`Add Liquidity Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) } else { - setAddLiquidityError(err?.message) + setAddLiquidityError(message) + } + + if (!didUserReject(error)) { + console.error('Add Liquidity error:', { message, error }) + const e = new Error(message, { cause: error }) + e.name = 'AddLiquidityError' + captureException(e, { extra: { args } }) } }) } @@ -395,7 +409,11 @@ const TokenPair = ({ - {'DMM ' + nativeA?.symbol + '/' + nativeB?.symbol + ' LP Tokens'} + + + DMM {nativeA?.symbol}/{nativeB?.symbol} LP Tokens + + {t`Output is estimated. If the price changes by more than ${ diff --git a/src/pages/AddLiquidity/ZapIn.tsx b/src/pages/AddLiquidity/ZapIn.tsx index a0da12406a..967951c15a 100644 --- a/src/pages/AddLiquidity/ZapIn.tsx +++ b/src/pages/AddLiquidity/ZapIn.tsx @@ -9,6 +9,7 @@ import { useCallback, useMemo, useState } from 'react' import { AlertTriangle } from 'react-feather' import { Flex, Text } from 'rebass' +import { NotificationType } from 'components/Announcement/type' import { ButtonError, ButtonLight, ButtonPrimary } from 'components/Button' import { AutoColumn } from 'components/Column' import { ConfirmAddModalBottom } from 'components/ConfirmAddModalBottom' @@ -36,7 +37,7 @@ import { ApprovalState, useApproveCallback } from 'hooks/useApproveCallback' import useTheme from 'hooks/useTheme' import useTransactionDeadline from 'hooks/useTransactionDeadline' import { Dots, Wrapper } from 'pages/MyPool/styleds' -import { useWalletModalToggle } from 'state/application/hooks' +import { useNotify, useWalletModalToggle } from 'state/application/hooks' import { Field } from 'state/mint/actions' import { useDerivedZapInInfo, useMintState, useZapInActionHandlers } from 'state/mint/hooks' import { tryParseAmount } from 'state/swap/hooks' @@ -48,6 +49,7 @@ import { StyledInternalLink, TYPE, UppercaseText } from 'theme' import { calculateGasMargin, formattedNum } from 'utils' import { currencyId } from 'utils/currencyId' import { feeRangeCalc, useCurrencyConvertedToNative } from 'utils/dmm' +import { friendlyError } from 'utils/errorMessage' import { getZapContract } from 'utils/getContract' import isZero from 'utils/isZero' import { maxAmountSpend } from 'utils/maxAmountSpend' @@ -87,6 +89,7 @@ const ZapIn = ({ const [zapInError, setZapInError] = useState('') const [isDegenMode] = useDegenModeManager() + const notify = useNotify() // mint state const { independentField, typedValue, otherTypedValue } = useMintState() @@ -277,21 +280,31 @@ const ZapIn = ({ } }), ) - .catch(err => { + .catch(error => { setAttemptingTxn(false) - const e = new Error('Classic: ZapIn liquidity Error', { cause: err }) - e.name = 'ZapError' - captureException(e, { extra: { args } }) - // we only care if the error is something _other_ than the user rejected the tx - if (!didUserReject(err)) { - console.error(err) + const message = error.message.includes('INSUFFICIENT_MINT_QTY') + ? t`Insufficient liquidity available. Please reload page and try again!` + : friendlyError(error) + + if (isDegenMode) { + notify( + { + title: t`Add Liquidity Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) + } else { + setZapInError(message) } - if (err.message.includes('INSUFFICIENT_MINT_QTY')) { - setZapInError(t`Insufficient liquidity available. Please reload page and try again!`) - } else { - setZapInError(err?.message) + if (!didUserReject(error)) { + console.error('Zap in error:', { message, error }) + const e = new Error(message, { cause: error }) + e.name = 'ZapError' + captureException(e, { extra: { args } }) } }) } @@ -394,7 +407,11 @@ const ZapIn = ({ - {'DMM ' + nativeA?.symbol + '/' + nativeB?.symbol + ' LP Tokens'} + + + DMM {nativeA?.symbol}/{nativeB?.symbol} LP Tokens + + {t`Output is estimated. If the price changes by more than ${ diff --git a/src/pages/AddLiquidityV2/index.tsx b/src/pages/AddLiquidityV2/index.tsx index d3aeb052ca..a2e8bbc8e1 100644 --- a/src/pages/AddLiquidityV2/index.tsx +++ b/src/pages/AddLiquidityV2/index.tsx @@ -53,7 +53,7 @@ import { NativeCurrencies } from 'constants/tokens' import { useActiveWeb3React, useWeb3React } from 'hooks' import { useCurrency } from 'hooks/Tokens' import { ApprovalState, useApproveCallback } from 'hooks/useApproveCallback' -import { useProAmmNFTPositionManagerContract } from 'hooks/useContract' +import { useProAmmNFTPositionManagerReadingContract } from 'hooks/useContract' import useInterval from 'hooks/useInterval' import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel' import useProAmmPoolInfo from 'hooks/useProAmmPoolInfo' @@ -136,7 +136,7 @@ export default function AddLiquidity() { const toggleWalletModal = useWalletModalToggle() // toggle wallet when disconnected const [isDegenMode] = useDegenModeManager() const addTransactionWithType = useTransactionAdder() - const positionManager = useProAmmNFTPositionManagerContract() + const positionManager = useProAmmNFTPositionManagerReadingContract() const [showChart, setShowChart] = useState(false) const [positionIndex, setPositionIndex] = useState(0) const { mixpanelHandler } = useMixpanel() diff --git a/src/pages/Campaign/CampaignButtonWithOptions.tsx b/src/pages/Campaign/CampaignButtonWithOptions.tsx index 84a6acc782..2a25c33124 100644 --- a/src/pages/Campaign/CampaignButtonWithOptions.tsx +++ b/src/pages/Campaign/CampaignButtonWithOptions.tsx @@ -11,6 +11,7 @@ import styled, { css } from 'styled-components' import { ReactComponent as ChevronDown } from 'assets/svg/down.svg' import { OptionsContainer } from 'components' +import { NotificationType } from 'components/Announcement/type' import { ButtonPrimary } from 'components/Button' import { REWARD_SERVICE_API } from 'constants/env' import { BIG_INT_ZERO, DEFAULT_SIGNIFICANT } from 'constants/index' @@ -22,6 +23,7 @@ import useTheme from 'hooks/useTheme' import { useChangeNetwork } from 'hooks/web3/useChangeNetwork' import { Dots } from 'pages/MyPool/styleds' import { AppState } from 'state' +import { useNotify } from 'state/application/hooks' import { CampaignData, CampaignLeaderboardReward, @@ -32,6 +34,7 @@ import { useSetClaimingCampaignRewardId, useSwapNowHandler } from 'state/campaig import { useTransactionAdder } from 'state/transactions/hooks' import { TRANSACTION_TYPE } from 'state/transactions/type' import { findTx } from 'utils' +import { friendlyError } from 'utils/errorMessage' import { sendEVMTransaction } from 'utils/sendTransaction' import { ErrorName } from 'utils/sentry' @@ -55,6 +58,7 @@ export default function CampaignButtonWithOptions({ const containerRef = useRef(null) useOnClickOutside(containerRef, () => setIsShowNetworks(false)) const { mixpanelHandler } = useMixpanel() + const notify = useNotify() const chainIds: ChainId[] = campaign ? campaign[type === 'swap_now' ? 'chainIds' : 'rewardChainIds'].split(',').map(Number) @@ -208,9 +212,19 @@ export default function CampaignButtonWithOptions({ addTemporaryClaimedRefs && addTemporaryClaimedRefs(refs) updateCampaignStore() } - } catch (err) { - console.error(err) + } catch (error) { setClaimingCampaignRewardId(null) + const message = friendlyError(error) + console.error('Claim error:', { message, error }) + notify( + { + title: t`Claim Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) + return } } } diff --git a/src/pages/CreatePool/index.tsx b/src/pages/CreatePool/index.tsx index c5696b7ddc..95e2eafc47 100644 --- a/src/pages/CreatePool/index.tsx +++ b/src/pages/CreatePool/index.tsx @@ -9,6 +9,7 @@ import { AlertTriangle, Plus } from 'react-feather' import { Link, Navigate, useNavigate, useParams } from 'react-router-dom' import { Flex, Text } from 'rebass' +import { NotificationType } from 'components/Announcement/type' import { ButtonError, ButtonLight, ButtonPrimary } from 'components/Button' import { BlueCard, LightCard } from 'components/Card' import { AutoColumn, ColumnCenter } from 'components/Column' @@ -35,7 +36,7 @@ import useTheme from 'hooks/useTheme' import useTransactionDeadline from 'hooks/useTransactionDeadline' import DisclaimerERC20 from 'pages/AddLiquidityV2/components/DisclaimerERC20' import { Dots, Wrapper } from 'pages/MyPool/styleds' -import { useWalletModalToggle } from 'state/application/hooks' +import { useNotify, useWalletModalToggle } from 'state/application/hooks' import { Field } from 'state/mint/actions' import { useDerivedMintInfo, useMintActionHandlers, useMintState } from 'state/mint/hooks' import { useDerivedPairInfo } from 'state/pair/hooks' @@ -47,6 +48,7 @@ import { StyledInternalLink, TYPE } from 'theme' import { calculateGasMargin, calculateSlippageAmount, formattedNum } from 'utils' import { currencyId } from 'utils/currencyId' import { feeRangeCalc, useCurrencyConvertedToNative } from 'utils/dmm' +import { friendlyError } from 'utils/errorMessage' import { getDynamicFeeRouterContract, getStaticFeeRouterContract } from 'utils/getContract' import isZero from 'utils/isZero' import { maxAmountSpend } from 'utils/maxAmountSpend' @@ -184,6 +186,7 @@ export default function CreatePool() { const addTransactionWithType = useTransactionAdder() const addPair = usePairAdderByTokens() + const notify = useNotify() async function onAdd() { // if (!pair) return @@ -300,6 +303,15 @@ export default function CreatePool() { if (!didUserReject(error)) { console.error(error) } + const message = friendlyError(error) + notify( + { + title: t`Create Classic Pool Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) }) } diff --git a/src/pages/ElasticLegacy/FarmLegacy.tsx b/src/pages/ElasticLegacy/FarmLegacy.tsx index 5717e1d3d5..09de5f6426 100644 --- a/src/pages/ElasticLegacy/FarmLegacy.tsx +++ b/src/pages/ElasticLegacy/FarmLegacy.tsx @@ -14,7 +14,7 @@ import { ELASTIC_BASE_FEE_UNIT, ZERO_ADDRESS } from 'constants/index' import { NativeCurrencies } from 'constants/tokens' import { useActiveWeb3React, useWeb3React } from 'hooks' import { useAllTokens } from 'hooks/Tokens' -import { useProMMFarmContract } from 'hooks/useContract' +import { useProMMFarmSigningContract } from 'hooks/useContract' import { Position as SubgraphPosition, config, parsePosition } from 'hooks/useElasticLegacy' import useTheme from 'hooks/useTheme' import { useTokenPrices } from 'state/tokenPrices/hooks' @@ -155,7 +155,7 @@ export default function FarmLegacy({ } } - const farmContract = useProMMFarmContract(config[chainId]?.farmContract || '') + const farmContract = useProMMFarmSigningContract(config[chainId]?.farmContract || '') const handleWithdraw = async () => { setShowConfirmModal('withdraw') diff --git a/src/pages/ElasticSwap/hooks/index.ts b/src/pages/ElasticSwap/hooks/index.ts index 5d555c6eb2..b83d26e4fb 100644 --- a/src/pages/ElasticSwap/hooks/index.ts +++ b/src/pages/ElasticSwap/hooks/index.ts @@ -12,7 +12,7 @@ import { INITIAL_ALLOWED_SLIPPAGE } from 'constants/index' import { EVMNetworkInfo } from 'constants/networks/type' import { useActiveWeb3React, useWeb3React } from 'hooks' import { useAllCurrencyCombinations } from 'hooks/useAllCurrencyCombinations' -import { useContractForReading } from 'hooks/useContract' +import { useReadingContract } from 'hooks/useContract' import { PoolState, usePools } from 'hooks/usePools' import useTransactionDeadline from 'hooks/useTransactionDeadline' import { useNotify } from 'state/application/hooks' @@ -22,7 +22,7 @@ import { TRANSACTION_TYPE } from 'state/transactions/type' import { basisPointsToPercent, calculateGasMargin } from 'utils' import { friendlyError } from 'utils/errorMessage' import { formatCurrencyAmount } from 'utils/formatCurrencyAmount' -import { getContract } from 'utils/getContract' +import { getSigningContract } from 'utils/getContract' import isZero from 'utils/isZero' const ROUTER_PRO_AMM = [ @@ -228,7 +228,7 @@ export function useElasticBestTrade( ) const { routes, loading: routesLoading } = useElasticAllRoutes(currencyIn, currencyOut) - const quoter = useContractForReading((networkInfo as EVMNetworkInfo).elastic.quoter, QuoterABI) + const quoter = useReadingContract((networkInfo as EVMNetworkInfo).elastic.quoter, QuoterABI) const quotesResults = useSingleContractWithCallData( quoter, @@ -606,7 +606,7 @@ function useSwapCallArguments( return useMemo(() => { if (!trade || !account || !library || !account || !chainId || !deadline) return [] - const routerProAmmContract: Contract | null = getContract( + const routerProAmmContract: Contract | null = getSigningContract( (networkInfo as EVMNetworkInfo).elastic.routers, ROUTER_PRO_AMM, library, diff --git a/src/pages/Farm/ElasticFarmv2/index.tsx b/src/pages/Farm/ElasticFarmv2/index.tsx index e828270281..f951f7eb54 100644 --- a/src/pages/Farm/ElasticFarmv2/index.tsx +++ b/src/pages/Farm/ElasticFarmv2/index.tsx @@ -21,7 +21,7 @@ import { FarmList } from 'components/YieldPools/ElasticFarmGroup/styleds' import { ClickableText, ElasticFarmV2TableHeader } from 'components/YieldPools/styleds' import { SORT_DIRECTION } from 'constants/index' import { useActiveWeb3React } from 'hooks' -import { useProAmmNFTPositionManagerContract } from 'hooks/useContract' +import { useProAmmNFTPositionManagerReadingContract } from 'hooks/useContract' import useTheme from 'hooks/useTheme' import { Dots } from 'pages/MyPool/styleds' import { useWalletModalToggle } from 'state/application/hooks' @@ -105,7 +105,7 @@ export default function ElasticFarmv2({ }) const { approve } = useFarmV2Action(farmAddress) - const posManager = useProAmmNFTPositionManagerContract() + const posManager = useProAmmNFTPositionManagerReadingContract() const [approvalTx, setApprovalTx] = useState('') const isApprovalTxPending = useIsTransactionPending(approvalTx) const res = useSingleCallResult(posManager, 'isApprovedForAll', [account, farmAddress]) @@ -114,8 +114,10 @@ export default function ElasticFarmv2({ const handleApprove = async () => { if (!isApprovedForAll) { const tx = await approve() - setApprovalTx(tx) - mixpanel.track('ElasticFarmv2 - Approve Farming contract V2', { tx_hash: tx }) + if (tx) { + setApprovalTx(tx) + mixpanel.track('ElasticFarmv2 - Approve Farming contract V2', { tx_hash: tx }) + } } } diff --git a/src/pages/IncreaseLiquidity/index.tsx b/src/pages/IncreaseLiquidity/index.tsx index b54ee8d6e2..6156838b95 100644 --- a/src/pages/IncreaseLiquidity/index.tsx +++ b/src/pages/IncreaseLiquidity/index.tsx @@ -28,7 +28,10 @@ import ProAmmPriceRangeConfirm from 'components/ProAmm/ProAmmPriceRangeConfirm' import Rating from 'components/Rating' import { RowBetween } from 'components/Row' import { SLIPPAGE_EXPLANATION_URL } from 'components/SlippageWarningNote' -import TransactionConfirmationModal, { ConfirmationModalContent } from 'components/TransactionConfirmationModal' +import TransactionConfirmationModal, { + ConfirmationModalContent, + TransactionErrorContent, +} from 'components/TransactionConfirmationModal' import { TutorialType } from 'components/Tutorial' import { didUserReject } from 'constants/connectors/utils' import { APP_PATHS } from 'constants/index' @@ -37,7 +40,7 @@ import { NativeCurrencies } from 'constants/tokens' import { useActiveWeb3React, useWeb3React } from 'hooks' import { useCurrency } from 'hooks/Tokens' import { ApprovalState, useApproveCallback } from 'hooks/useApproveCallback' -import { useProAmmNFTPositionManagerContract } from 'hooks/useContract' +import { useProAmmNFTPositionManagerReadingContract } from 'hooks/useContract' import { useProAmmDerivedPositionInfo } from 'hooks/useProAmmDerivedPositionInfo' import { useProAmmPositionsFromTokenId } from 'hooks/useProAmmPositions' import useProAmmPreviousTicks from 'hooks/useProAmmPreviousTicks' @@ -102,7 +105,7 @@ export default function IncreaseLiquidity() { } }, [chainId, prevChainId, navigate]) - const positionManager = useProAmmNFTPositionManagerContract() + const positionManager = useProAmmNFTPositionManagerReadingContract() // check for existing position if tokenId in url const { position: existingPositionDetails } = useProAmmPositionsFromTokenId( @@ -239,6 +242,11 @@ export default function IncreaseLiquidity() { const [allowedSlippage] = useUserSlippageTolerance() + const [transactionError, setTransactionError] = useState(undefined) + useEffect(() => { + if (!showConfirm) setTransactionError(undefined) + }, [showConfirm]) + async function onAdd() { if (!isEVM || !library || !account || !tokenId) { return @@ -314,6 +322,7 @@ export default function IncreaseLiquidity() { if (!didUserReject(error)) { console.error(error) } + setTransactionError(error.message) }) } else { return @@ -426,57 +435,61 @@ export default function IncreaseLiquidity() { onDismiss={handleDismissConfirmation} attemptingTxn={attemptingTxn} hash={txHash} - content={() => ( - - existingPosition && ( -
- - - -
- ) - } - bottomContent={() => ( - <> - {slippageStatus === SLIPPAGE_STATUS.HIGH && ( - - - - - - - Slippage - - - is high. Your transaction may be front-run - - - - - - )} - - - Supply - - - - )} - /> - )} + content={() => + transactionError ? ( + + ) : ( + + existingPosition && ( +
+ + + +
+ ) + } + bottomContent={() => ( + <> + {slippageStatus === SLIPPAGE_STATUS.HIGH && ( + + + + + + + Slippage + + + is high. Your transaction may be front-run + + + + + + )} + + + Supply + + + + )} + /> + ) + } pendingText={pendingText} /> diff --git a/src/pages/KyberDAO/Vote/ProposalItem/index.tsx b/src/pages/KyberDAO/Vote/ProposalItem/index.tsx index 52066e78d7..bcb205c4b7 100644 --- a/src/pages/KyberDAO/Vote/ProposalItem/index.tsx +++ b/src/pages/KyberDAO/Vote/ProposalItem/index.tsx @@ -257,9 +257,13 @@ function ProposalItem({ voteCallback?.( proposal.proposal_id, selectedOptions.map(i => i + 1).reduce((acc, item) => (acc += 1 << (item - 1)), 0), - ).then(() => { - setSelectedOptions([]) - }) + ) + .then(() => { + setSelectedOptions([]) + }) + .catch(error => { + setErrorMessage(error.message) + }) }, [selectedOptions, proposal.proposal_id, voteCallback]) const votedOfCurrentProposal = useMemo( diff --git a/src/pages/KyberDAO/Vote/index.tsx b/src/pages/KyberDAO/Vote/index.tsx index b088444b4e..ada634d8c9 100644 --- a/src/pages/KyberDAO/Vote/index.tsx +++ b/src/pages/KyberDAO/Vote/index.tsx @@ -137,7 +137,7 @@ export default function Vote() { const [pendingText, setPendingText] = useState('') const [txHash, setTxHash] = useState(undefined) - const [transactionError, setTransactionError] = useState() + const [transactionError, setTransactionError] = useState(undefined) const totalStakedAmount = stakerInfo ? stakerInfo?.stake_amount + stakerInfo?.pending_stake_amount : 0 const votePowerAmount: number = useMemo( () => @@ -187,7 +187,7 @@ export default function Vote() { }, [claimVotingRewards, remainingCumulativeAmount, toggleClaimConfirmModal]) const handleVote = useCallback( - async (proposal_id: number, option: number) => { + async (proposal_id: number, option: number): Promise => { // only can vote when user has staked amount setPendingText(t`Vote submitting`) setShowConfirm(true) @@ -196,12 +196,13 @@ export default function Vote() { const tx = await vote(proposal_id, option) setAttemptingTxn(false) setTxHash(tx) - return Promise.resolve(true) + return true } catch (error) { setShowConfirm(false) + setAttemptingTxn(false) setTransactionError(error?.message) setTxHash(undefined) - return Promise.reject(error) + throw error } }, [vote], diff --git a/src/pages/MyEarnings/ElasticPools/SinglePosition/CollectFeesPanel.tsx b/src/pages/MyEarnings/ElasticPools/SinglePosition/CollectFeesPanel.tsx index 6db7a31921..6d79995016 100644 --- a/src/pages/MyEarnings/ElasticPools/SinglePosition/CollectFeesPanel.tsx +++ b/src/pages/MyEarnings/ElasticPools/SinglePosition/CollectFeesPanel.tsx @@ -18,7 +18,7 @@ import FarmV2ABI from 'constants/abis/v2/farmv2.json' import { NETWORKS_INFO } from 'constants/networks' import { EVMNetworkInfo } from 'constants/networks/type' import { useActiveWeb3React, useWeb3React } from 'hooks' -import { useProAmmNFTPositionManagerContract } from 'hooks/useContract' +import { useProAmmNFTPositionManagerReadingContract } from 'hooks/useContract' import { config } from 'hooks/useElasticLegacy' import useTheme from 'hooks/useTheme' import useTransactionDeadline from 'hooks/useTransactionDeadline' @@ -70,7 +70,7 @@ const CollectFeesPanel: React.FC = ({ const dispatch = useDispatch() const hasNoFeeToCollect = !(feeValue0?.greaterThan(0) || feeValue1?.greaterThan(0)) const { changeNetwork } = useChangeNetwork() - const positionManager = useProAmmNFTPositionManagerContract() + const positionManager = useProAmmNFTPositionManagerReadingContract() const deadline = useTransactionDeadline() // custom from users settings const [allowedSlippage] = useUserSlippageTolerance() const token0Shown = feeValue0?.currency || position.pool.token0 diff --git a/src/pages/ProAmmPool/PositionListItem.tsx b/src/pages/ProAmmPool/PositionListItem.tsx index 9117ff60b0..f57f8b8ae5 100644 --- a/src/pages/ProAmmPool/PositionListItem.tsx +++ b/src/pages/ProAmmPool/PositionListItem.tsx @@ -20,7 +20,7 @@ import { MouseoverTooltip } from 'components/Tooltip' import { APP_PATHS, PROMM_ANALYTICS_URL } from 'constants/index' import { useActiveWeb3React } from 'hooks' import { useToken } from 'hooks/Tokens' -import { useProMMFarmContract } from 'hooks/useContract' +import { useProMMFarmReadingContract } from 'hooks/useContract' import useIsTickAtLimit from 'hooks/useIsTickAtLimit' import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel' import { usePool } from 'hooks/usePools' @@ -187,7 +187,7 @@ function PositionListItem({ f.ranges.some(r => positionDetails.tickLower <= r.tickLower && positionDetails.tickUpper >= r.tickUpper), ).length - const farmContract = useProMMFarmContract(farmAddress) + const farmContract = useProMMFarmReadingContract(farmAddress) const tokenId = positionDetails.tokenId.toString() diff --git a/src/pages/RemoveLiquidity/TokenPair.tsx b/src/pages/RemoveLiquidity/TokenPair.tsx index 2334b85e70..3cd5ee716e 100644 --- a/src/pages/RemoveLiquidity/TokenPair.tsx +++ b/src/pages/RemoveLiquidity/TokenPair.tsx @@ -9,6 +9,7 @@ import JSBI from 'jsbi' import { useCallback, useEffect, useMemo, useState } from 'react' import { Flex, Text } from 'rebass' +import { NotificationType } from 'components/Announcement/type' import { ButtonConfirmed, ButtonError, ButtonLight, ButtonPrimary } from 'components/Button' import { BlackCard } from 'components/Card' import { AutoColumn } from 'components/Column' @@ -36,7 +37,7 @@ import useIsArgentWallet from 'hooks/useIsArgentWallet' import useTheme from 'hooks/useTheme' import useTransactionDeadline from 'hooks/useTransactionDeadline' import { Wrapper } from 'pages/MyPool/styleds' -import { useWalletModalToggle } from 'state/application/hooks' +import { useNotify, useWalletModalToggle } from 'state/application/hooks' import { Field } from 'state/burn/actions' import { useBurnActionHandlers, useBurnState, useDerivedBurnInfo } from 'state/burn/hooks' import { useTokenPrices } from 'state/tokenPrices/hooks' @@ -46,12 +47,14 @@ import { useUserSlippageTolerance } from 'state/user/hooks' import { StyledInternalLink, TYPE, UppercaseText } from 'theme' import { calculateGasMargin, calculateSlippageAmount, formattedNum } from 'utils' import { currencyId } from 'utils/currencyId' +import { friendlyError } from 'utils/errorMessage' import { formatJSBIValue } from 'utils/formatBalance' import { getDynamicFeeRouterContract, getOldStaticFeeRouterContract, getStaticFeeRouterContract, } from 'utils/getContract' +import { formatDisplayNumber } from 'utils/numbers' import { ErrorName } from 'utils/sentry' import useDebouncedChangeHandler from 'utils/useDebouncedChangeHandler' @@ -90,6 +93,7 @@ export default function TokenPair({ const currencyBIsWETH = !!currencyB?.equals(WETH[chainId]) const theme = useTheme() + const notify = useNotify() // toggle wallet when disconnected const toggleWalletModal = useWalletModalToggle() @@ -164,7 +168,7 @@ export default function TokenPair({ const domain = { name: isStaticFeePair ? 'KyberSwap LP' : 'KyberDMM LP', version: '1', - chainId: chainId, + chainId, verifyingContract: pair.liquidityToken.address, } const Permit = [ @@ -176,7 +180,6 @@ export default function TokenPair({ ] const message = { owner: account, - TransactionErrorContent, spender: contractAddress, value: liquidityAmount.quotient.toString(), nonce: nonce.toHexString(), @@ -192,23 +195,32 @@ export default function TokenPair({ message, }) - library - .send('eth_signTypedData_v4', [account, data]) - .then(splitSignature) - .then(signature => { - setSignatureData({ - v: signature.v, - r: signature.r, - s: signature.s, - deadline: deadline.toNumber(), + try { + await library + .send('eth_signTypedData_v4', [account, data]) + .then(splitSignature) + .then(signature => { + setSignatureData({ + v: signature.v, + r: signature.r, + s: signature.s, + deadline: deadline.toNumber(), + }) }) - }) - .catch((error: any) => { - // for all errors other than 4001 (EIP-1193 user rejected request), fall back to manual approve - if (!didUserReject(error)) { - approveCallback() - } - }) + } catch (error) { + if (didUserReject(error)) { + notify( + { + title: t`Approve failed`, + summary: friendlyError(error), + type: NotificationType.ERROR, + }, + 8000, + ) + } else { + approveCallback() + } + } } // wrapped onUserInput to clear signatures @@ -395,22 +407,21 @@ export default function TokenPair({ setTxHash(response.hash) } }) - .catch((err: Error) => { + .catch((error: Error) => { setAttemptingTxn(false) - // we only care if the error is something _other_ than the user rejected the tx - if (!didUserReject(err)) { - const e = new Error('Remove Classic Liquidity Error', { cause: err }) + + const message = error.message.includes('INSUFFICIENT') + ? t`Insufficient liquidity available. Please reload page or increase max slippage and try again!` + : error.message + + setRemoveLiquidityError(message) + + if (!didUserReject(error)) { + console.error('Remove Classic Liquidity Error:', { message, error }) + const e = new Error(friendlyError(error), { cause: error }) e.name = ErrorName.RemoveClassicLiquidityError captureException(e, { extra: { args } }) } - - if (err.message.includes('INSUFFICIENT')) { - setRemoveLiquidityError( - t`Insufficient liquidity available. Please reload page or increase max slippage and try again!`, - ) - } else { - setRemoveLiquidityError(err?.message || JSON.stringify(err)) - } }) } } @@ -602,7 +613,13 @@ export default function TokenPair({ - Balance: {!userLiquidity ? : userLiquidity?.toSignificant(6)} LP Tokens + Balance:{' '} + {!userLiquidity ? ( + + ) : ( + formatDisplayNumber(userLiquidity, { style: 'decimal', significantDigits: 6 }) + )}{' '} + LP Tokens diff --git a/src/pages/RemoveLiquidity/ZapOut.tsx b/src/pages/RemoveLiquidity/ZapOut.tsx index 3185c5a04f..3028332d4f 100644 --- a/src/pages/RemoveLiquidity/ZapOut.tsx +++ b/src/pages/RemoveLiquidity/ZapOut.tsx @@ -18,6 +18,7 @@ import JSBI from 'jsbi' import { useCallback, useEffect, useMemo, useState } from 'react' import { Flex, Text } from 'rebass' +import { NotificationType } from 'components/Announcement/type' import { ButtonConfirmed, ButtonError, ButtonLight, ButtonPrimary } from 'components/Button' import { BlackCard } from 'components/Card' import { AutoColumn } from 'components/Column' @@ -47,7 +48,7 @@ import useIsArgentWallet from 'hooks/useIsArgentWallet' import useTheme from 'hooks/useTheme' import useTransactionDeadline from 'hooks/useTransactionDeadline' import { Wrapper } from 'pages/MyPool/styleds' -import { useWalletModalToggle } from 'state/application/hooks' +import { useNotify, useWalletModalToggle } from 'state/application/hooks' import { Field } from 'state/burn/actions' import { useBurnState, useDerivedZapOutInfo, useZapOutActionHandlers } from 'state/burn/hooks' import { useTokenPrices } from 'state/tokenPrices/hooks' @@ -58,8 +59,10 @@ import { StyledInternalLink, TYPE, UppercaseText } from 'theme' import { calculateGasMargin, formattedNum } from 'utils' import { currencyId } from 'utils/currencyId' import { useCurrencyConvertedToNative } from 'utils/dmm' +import { friendlyError } from 'utils/errorMessage' import { formatJSBIValue } from 'utils/formatBalance' import { getZapContract } from 'utils/getContract' +import { formatDisplayNumber } from 'utils/numbers' import { computePriceImpactWithoutFee, warningSeverity } from 'utils/prices' import { ErrorName } from 'utils/sentry' import useDebouncedChangeHandler from 'utils/useDebouncedChangeHandler' @@ -96,6 +99,7 @@ export default function ZapOut({ const theme = useTheme() const [isDegenMode] = useDegenModeManager() + const notify = useNotify() // toggle wallet when disconnected const toggleWalletModal = useWalletModalToggle() @@ -234,23 +238,32 @@ export default function ZapOut({ message, }) - library - .send('eth_signTypedData_v4', [account, data]) - .then(splitSignature) - .then(signature => { - setSignatureData({ - v: signature.v, - r: signature.r, - s: signature.s, - deadline: deadline.toNumber(), + try { + await library + .send('eth_signTypedData_v4', [account, data]) + .then(splitSignature) + .then(signature => { + setSignatureData({ + v: signature.v, + r: signature.r, + s: signature.s, + deadline: deadline.toNumber(), + }) }) - }) - .catch((error: any) => { - // for all errors other than 4001 (EIP-1193 user rejected request), fall back to manual approve - if (!didUserReject(error)) { - approveCallback() - } - }) + } catch (error) { + if (didUserReject(error)) { + notify( + { + title: t`Approve failed`, + summary: friendlyError(error), + type: NotificationType.ERROR, + }, + 8000, + ) + } else { + approveCallback() + } + } } // wrapped onUserInput to clear signatures @@ -266,6 +279,7 @@ export default function ZapOut({ (typedValue: string): void => onUserInput(Field.LIQUIDITY, typedValue), [onUserInput], ) + const onCurrencyInput = useCallback( (typedValue: string): void => onUserInput(independentTokenField, typedValue), [independentTokenField, onUserInput], @@ -439,20 +453,21 @@ export default function ZapOut({ setTxHash(response.hash) } }) - .catch((err: Error) => { + .catch((error: Error) => { setAttemptingTxn(false) - // we only care if the error is something _other_ than the user rejected the tx - if (!didUserReject(err)) { - const e = new Error('zap out failed', { cause: err }) + + const message = error.message.includes('INSUFFICIENT') + ? t`Insufficient liquidity available. Please reload page or increase max slippage and try again!` + : error.message + + setZapOutError(message) + + if (!didUserReject(error)) { + console.error('Remove Classic Liquidity Error:', { message, error }) + const e = new Error(friendlyError(message), { cause: error }) e.name = ErrorName.RemoveClassicLiquidityError captureException(e, { extra: { args } }) } - - if (err.message.includes('INSUFFICIENT_OUTPUT_AMOUNT')) { - setZapOutError(t`Insufficient Liquidity in the Liquidity Pool to Swap`) - } else { - setZapOutError(err?.message) - } }) } } @@ -662,7 +677,13 @@ export default function ZapOut({ - Balance: {!userLiquidity ? : userLiquidity?.toSignificant(6)} LP Tokens + Balance:{' '} + {!userLiquidity ? ( + + ) : ( + formatDisplayNumber(userLiquidity, { style: 'decimal', significantDigits: 6 }) + )}{' '} + LP Tokens diff --git a/src/pages/RemoveLiquidityProAmm/index.tsx b/src/pages/RemoveLiquidityProAmm/index.tsx index 7b257fd902..c8a419d101 100644 --- a/src/pages/RemoveLiquidityProAmm/index.tsx +++ b/src/pages/RemoveLiquidityProAmm/index.tsx @@ -40,7 +40,11 @@ import FarmV2ABI from 'constants/abis/v2/farmv2.json' import { didUserReject } from 'constants/connectors/utils' import { EVMNetworkInfo } from 'constants/networks/type' import { useActiveWeb3React, useWeb3React } from 'hooks' -import { useContract, useProAmmNFTPositionManagerContract, useProMMFarmContract } from 'hooks/useContract' +import { + useProAmmNFTPositionManagerReadingContract, + useProMMFarmSigningContract, + useSigningContract, +} from 'hooks/useContract' import useProAmmPoolInfo from 'hooks/useProAmmPoolInfo' import { useProAmmPositionsFromTokenId } from 'hooks/useProAmmPositions' import useTheme from 'hooks/useTheme' @@ -148,7 +152,7 @@ export default function RemoveLiquidityProAmm() { function Remove({ tokenId }: { tokenId: BigNumber }) { const { position } = useProAmmPositionsFromTokenId(tokenId) - const positionManager = useProAmmNFTPositionManagerContract() + const positionManager = useProAmmNFTPositionManagerReadingContract() const theme = useTheme() const { networkInfo, account, chainId, isEVM } = useActiveWeb3React() const { library } = useWeb3React() @@ -265,11 +269,11 @@ function Remove({ tokenId }: { tokenId: BigNumber }) { const [txnHash, setTxnHash] = useState() const addTransactionWithType = useTransactionAdder() - const farmV1Contract = useProMMFarmContract(owner) + const farmV1Contract = useProMMFarmSigningContract(owner) const farmV2Address = isFarmV2 ? owner : undefined - const farmV2Contract = useContract(farmV2Address, FarmV2ABI) - const farmV21Contract = useContract(isFarmV21 ? owner : undefined, FarmV21ABI) + const farmV2Contract = useSigningContract(farmV2Address, FarmV2ABI) + const farmV21Contract = useSigningContract(isFarmV21 ? owner : undefined, FarmV21ABI) const handleBroadcastRemoveSuccess = (response: TransactionResponse) => { setAttemptingTxn(false) diff --git a/src/services/blackjack.ts b/src/services/blackjack.ts new file mode 100644 index 0000000000..df8333139e --- /dev/null +++ b/src/services/blackjack.ts @@ -0,0 +1,39 @@ +import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' + +import { BLACKJACK_API } from 'constants/env' + +type BlackjackCheck = { + blacklisted: boolean + expiryMs: string + reason: number +} + +type BlackjackResponse = { + data: { + wallets: BlackjackCheck[] + } +} + +const blackjackApi = createApi({ + reducerPath: 'blackjackApi', + baseQuery: fetchBaseQuery({ + baseUrl: `${BLACKJACK_API}/v1`, + }), + endpoints: builder => ({ + checkBlackjack: builder.query({ + query: (address: string) => ({ + url: '/check', + params: { + wallets: address, + }, + }), + transformResponse: (res: BlackjackResponse): BlackjackCheck => { + return res.data.wallets[0] + }, + }), + }), +}) + +export const { useCheckBlackjackQuery } = blackjackApi + +export default blackjackApi diff --git a/src/state/farms/classic/knUpdater.tsx b/src/state/farms/classic/knUpdater.tsx index 9f2addd25d..11200ca23b 100644 --- a/src/state/farms/classic/knUpdater.tsx +++ b/src/state/farms/classic/knUpdater.tsx @@ -14,7 +14,7 @@ import { useKyberSwapConfig } from 'state/application/hooks' import { setFarmsData, setLoading, setYieldPoolsError } from 'state/farms/classic/actions' import { FairLaunchVersion, Farm, FarmV1, FarmV2 } from 'state/farms/classic/types' import { useAppDispatch } from 'state/hooks' -import { getContractForReading } from 'utils/getContract' +import { getReadingContract } from 'utils/getContract' import { parseFraction, toString } from 'utils/numbers' const KNUpdater = ({ isInterval = true }: { isInterval?: boolean }) => { @@ -88,7 +88,7 @@ const KNUpdater = ({ isInterval = true }: { isInterval?: boolean }) => { if (!account) return {} if (!readProvider) return {} try { - const contract = getContractForReading( + const contract = getReadingContract( fairLaunchAddress, version === FairLaunchVersion.V1 ? FAIRLAUNCH_ABI diff --git a/src/state/farms/elastic/hooks.ts b/src/state/farms/elastic/hooks.ts index 9d2b137203..6ad61e329b 100644 --- a/src/state/farms/elastic/hooks.ts +++ b/src/state/farms/elastic/hooks.ts @@ -7,6 +7,7 @@ import { Interface } from 'ethers/lib/utils' import { useCallback, useMemo, useState } from 'react' import { useSearchParams } from 'react-router-dom' +import { NotificationType } from 'components/Announcement/type' import ELASTIC_FARM_ABI from 'constants/abis/v2/farm.json' import { ELASTIC_FARM_TYPE, FARM_TAB } from 'constants/index' import { CONTRACT_NOT_FOUND_MSG } from 'constants/messages' @@ -14,9 +15,10 @@ import { isEVM as isEVMNetwork } from 'constants/networks' import { EVMNetworkInfo } from 'constants/networks/type' import { useActiveWeb3React } from 'hooks' import { useTokens } from 'hooks/Tokens' -import { useProAmmNFTPositionManagerContract, useProMMFarmContract } from 'hooks/useContract' +import { useProAmmNFTPositionManagerSigningContract, useProMMFarmSigningContract } from 'hooks/useContract' import { usePools } from 'hooks/usePools' import { useProAmmPositionsFromTokenIds } from 'hooks/useProAmmPositions' +import { useNotify } from 'state/application/hooks' import { FarmingPool, NFTPosition, UserFarmInfo, UserInfo } from 'state/farms/elastic/types' import { useAppSelector } from 'state/hooks' import { getPoolAddress } from 'state/mint/proamm/utils' @@ -29,6 +31,7 @@ import { } from 'state/transactions/type' import { PositionDetails } from 'types/position' import { calculateGasMargin, isAddressString } from 'utils' +import { friendlyError } from 'utils/errorMessage' import { defaultChainData } from '.' @@ -206,30 +209,59 @@ const getTransactionExtraInfo = ( return { pairs } } -export const useFarmAction = (address: string) => { +export const useFarmAction = ( + address: string, +): { + approve: () => Promise + deposit: (positionDetails: PositionDetails[], positions: Position[]) => Promise + withdraw: (positionDetails: PositionDetails[], positions: Position[]) => Promise + emergencyWithdraw: (nftIds: BigNumber[]) => Promise + depositAndJoin: (pid: BigNumber, selectedNFTs: StakeParam[]) => Promise + stake: (pid: BigNumber, selectedNFTs: StakeParam[]) => Promise + unstake: (pid: BigNumber, selectedNFTs: StakeParam[]) => Promise + harvest: ( + nftIds: BigNumber[], + poolIds: BigNumber[], + farm: FarmingPool | undefined, + farmRewards: CurrencyAmount[], + ) => Promise +} => { const addTransactionWithType = useTransactionAdder() - const contract = useProMMFarmContract(address) - const posManager = useProAmmNFTPositionManagerContract() + const contract = useProMMFarmSigningContract(address) + const posManager = useProAmmNFTPositionManagerSigningContract() + const notify = useNotify() const approve = useCallback(async () => { if (!posManager) { throw new Error(CONTRACT_NOT_FOUND_MSG) } - const estimateGas = await posManager.estimateGas.setApprovalForAll(address, true) - const tx = await posManager.setApprovalForAll(address, true, { - gasLimit: calculateGasMargin(estimateGas), - }) - addTransactionWithType({ - hash: tx.hash, - type: TRANSACTION_TYPE.APPROVE, - extraInfo: { - summary: `Elastic Farm`, - contract: address, - }, - }) + try { + const estimateGas = await posManager.estimateGas.setApprovalForAll(address, true) + const tx = await posManager.setApprovalForAll(address, true, { + gasLimit: calculateGasMargin(estimateGas), + }) + addTransactionWithType({ + hash: tx.hash, + type: TRANSACTION_TYPE.APPROVE, + extraInfo: { + summary: `Elastic Farm`, + contract: address, + }, + }) - return tx.hash - }, [addTransactionWithType, address, posManager]) + return tx.hash + } catch (error) { + const message = friendlyError(error) + notify( + { + title: t`Approve Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) + } + }, [addTransactionWithType, address, posManager, notify]) // Deposit const deposit = useCallback( @@ -238,24 +270,35 @@ export const useFarmAction = (address: string) => { if (!contract) { throw new Error(CONTRACT_NOT_FOUND_MSG) } + try { + const estimateGas = await contract.estimateGas.deposit(nftIds) + const tx = await contract.deposit(nftIds, { + gasLimit: calculateGasMargin(estimateGas), + }) + addTransactionWithType({ + hash: tx.hash, + type: TRANSACTION_TYPE.ELASTIC_DEPOSIT_LIQUIDITY, + extraInfo: getTransactionExtraInfo( + positions, + positionDetails.map(e => e.poolId), + positionDetails.map(e => e.tokenId.toString()), + ), + }) - const estimateGas = await contract.estimateGas.deposit(nftIds) - const tx = await contract.deposit(nftIds, { - gasLimit: calculateGasMargin(estimateGas), - }) - addTransactionWithType({ - hash: tx.hash, - type: TRANSACTION_TYPE.ELASTIC_DEPOSIT_LIQUIDITY, - extraInfo: getTransactionExtraInfo( - positions, - positionDetails.map(e => e.poolId), - positionDetails.map(e => e.tokenId.toString()), - ), - }) - - return tx.hash + return tx.hash + } catch (error) { + const message = friendlyError(error) + notify( + { + title: t`Deposit Farm Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) + } }, - [addTransactionWithType, contract], + [addTransactionWithType, contract, notify], ) const withdraw = useCallback( @@ -263,24 +306,36 @@ export const useFarmAction = (address: string) => { if (!contract) { throw new Error(CONTRACT_NOT_FOUND_MSG) } - const nftIds = positionDetails.map(e => e.tokenId) - const estimateGas = await contract.estimateGas.withdraw(nftIds) - const tx = await contract.withdraw(nftIds, { - gasLimit: calculateGasMargin(estimateGas), - }) - addTransactionWithType({ - hash: tx.hash, - type: TRANSACTION_TYPE.ELASTIC_WITHDRAW_LIQUIDITY, - extraInfo: getTransactionExtraInfo( - positions, - positionDetails.map(e => e.poolId), - positionDetails.map(e => e.tokenId.toString()), - ), - }) + try { + const nftIds = positionDetails.map(e => e.tokenId) + const estimateGas = await contract.estimateGas.withdraw(nftIds) + const tx = await contract.withdraw(nftIds, { + gasLimit: calculateGasMargin(estimateGas), + }) + addTransactionWithType({ + hash: tx.hash, + type: TRANSACTION_TYPE.ELASTIC_WITHDRAW_LIQUIDITY, + extraInfo: getTransactionExtraInfo( + positions, + positionDetails.map(e => e.poolId), + positionDetails.map(e => e.tokenId.toString()), + ), + }) - return tx.hash + return tx.hash + } catch (error) { + const message = friendlyError(error) + notify( + { + title: t`Withdraw Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) + } }, - [addTransactionWithType, contract], + [addTransactionWithType, contract, notify], ) const emergencyWithdraw = useCallback( @@ -288,19 +343,31 @@ export const useFarmAction = (address: string) => { if (!contract) { throw new Error(CONTRACT_NOT_FOUND_MSG) } - const estimateGas = await contract.estimateGas.emergencyWithdraw(nftIds) - const tx = await contract.emergencyWithdraw(nftIds, { - gasLimit: calculateGasMargin(estimateGas), - }) - addTransactionWithType({ - hash: tx.hash, - type: TRANSACTION_TYPE.ELASTIC_FORCE_WITHDRAW_LIQUIDITY, - extraInfo: { contract: address }, - }) + try { + const estimateGas = await contract.estimateGas.emergencyWithdraw(nftIds) + const tx = await contract.emergencyWithdraw(nftIds, { + gasLimit: calculateGasMargin(estimateGas), + }) + addTransactionWithType({ + hash: tx.hash, + type: TRANSACTION_TYPE.ELASTIC_FORCE_WITHDRAW_LIQUIDITY, + extraInfo: { contract: address }, + }) - return tx.hash + return tx.hash + } catch (error) { + const message = friendlyError(error) + notify( + { + title: t`Withdraw Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) + } }, - [addTransactionWithType, contract, address], + [addTransactionWithType, contract, address, notify], ) const depositAndJoin = useCallback( @@ -308,26 +375,37 @@ export const useFarmAction = (address: string) => { if (!contract) { throw new Error(CONTRACT_NOT_FOUND_MSG) } + try { + const nftIds = selectedNFTs.map(item => item.nftId) - const nftIds = selectedNFTs.map(item => item.nftId) - - const estimateGas = await contract.estimateGas.depositAndJoin(pid, nftIds) - const tx = await contract.depositAndJoin(pid, nftIds, { - gasLimit: calculateGasMargin(estimateGas), - }) - addTransactionWithType({ - hash: tx.hash, - type: TRANSACTION_TYPE.STAKE, - extraInfo: getTransactionExtraInfo( - selectedNFTs.map(e => e.position), - selectedNFTs.map(e => e.poolAddress), - nftIds.map(e => e.toString()), - ), - }) + const estimateGas = await contract.estimateGas.depositAndJoin(pid, nftIds) + const tx = await contract.depositAndJoin(pid, nftIds, { + gasLimit: calculateGasMargin(estimateGas), + }) + addTransactionWithType({ + hash: tx.hash, + type: TRANSACTION_TYPE.STAKE, + extraInfo: getTransactionExtraInfo( + selectedNFTs.map(e => e.position), + selectedNFTs.map(e => e.poolAddress), + nftIds.map(e => e.toString()), + ), + }) - return tx.hash + return tx.hash + } catch (error) { + const message = friendlyError(error) + notify( + { + title: t`Deposit Farm Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) + } }, - [addTransactionWithType, contract], + [addTransactionWithType, contract, notify], ) const stake = useCallback( @@ -335,27 +413,38 @@ export const useFarmAction = (address: string) => { if (!contract) { throw new Error(CONTRACT_NOT_FOUND_MSG) } + try { + const nftIds = selectedNFTs.map(item => item.nftId) + const liqs = selectedNFTs.map(item => BigNumber.from(item.position.liquidity.toString())) - const nftIds = selectedNFTs.map(item => item.nftId) - const liqs = selectedNFTs.map(item => BigNumber.from(item.position.liquidity.toString())) - - const estimateGas = await contract.estimateGas.join(pid, nftIds, liqs) - const tx = await contract.join(pid, nftIds, liqs, { - gasLimit: calculateGasMargin(estimateGas), - }) - addTransactionWithType({ - hash: tx.hash, - type: TRANSACTION_TYPE.STAKE, - extraInfo: getTransactionExtraInfo( - selectedNFTs.map(e => e.position), - selectedNFTs.map(e => e.poolAddress), - nftIds.map(e => e.toString()), - ), - }) + const estimateGas = await contract.estimateGas.join(pid, nftIds, liqs) + const tx = await contract.join(pid, nftIds, liqs, { + gasLimit: calculateGasMargin(estimateGas), + }) + addTransactionWithType({ + hash: tx.hash, + type: TRANSACTION_TYPE.STAKE, + extraInfo: getTransactionExtraInfo( + selectedNFTs.map(e => e.position), + selectedNFTs.map(e => e.poolAddress), + nftIds.map(e => e.toString()), + ), + }) - return tx.hash + return tx.hash + } catch (error) { + const message = friendlyError(error) + notify( + { + title: t`Stake Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) + } }, - [addTransactionWithType, contract], + [addTransactionWithType, contract, notify], ) const unstake = useCallback( @@ -381,11 +470,19 @@ export const useFarmAction = (address: string) => { }) return tx.hash - } catch (e) { - console.log(e) + } catch (error) { + const message = friendlyError(error) + notify( + { + title: t`Unstake Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) } }, - [addTransactionWithType, contract], + [addTransactionWithType, contract, notify], ) const harvest = useCallback( @@ -419,11 +516,19 @@ export const useFarmAction = (address: string) => { } addTransactionWithType({ hash: tx.hash, type: TRANSACTION_TYPE.HARVEST, extraInfo }) return tx - } catch (e) { - console.log(e) + } catch (error) { + const message = friendlyError(error) + notify( + { + title: t`Harvest Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) } }, - [addTransactionWithType, contract], + [addTransactionWithType, contract, notify], ) return { deposit, withdraw, approve, stake, unstake, harvest, emergencyWithdraw, depositAndJoin } diff --git a/src/state/farms/elasticv2/hooks.ts b/src/state/farms/elasticv2/hooks.ts index 80d1d1a915..5f56732450 100644 --- a/src/state/farms/elasticv2/hooks.ts +++ b/src/state/farms/elasticv2/hooks.ts @@ -1,16 +1,20 @@ +import { t } from '@lingui/macro' import { useCallback, useMemo } from 'react' import { useSearchParams } from 'react-router-dom' import { useLocalStorage } from 'react-use' +import { NotificationType } from 'components/Announcement/type' import FarmV2ABI from 'constants/abis/v2/farmv2.json' import { ELASTIC_FARM_TYPE, FARM_TAB, SORT_DIRECTION } from 'constants/index' import { CONTRACT_NOT_FOUND_MSG } from 'constants/messages' import { useActiveWeb3React } from 'hooks' -import { useContract, useProAmmNFTPositionManagerContract } from 'hooks/useContract' +import { useProAmmNFTPositionManagerSigningContract, useSigningContract } from 'hooks/useContract' +import { useNotify } from 'state/application/hooks' import { useAppSelector } from 'state/hooks' import { useTransactionAdder } from 'state/transactions/hooks' import { TRANSACTION_TYPE } from 'state/transactions/type' import { calculateGasMargin, isAddressString } from 'utils' +import { friendlyError } from 'utils/errorMessage' import { defaultChainData } from '.' import { UserFarmV2Info } from './types' @@ -206,30 +210,51 @@ export const useFilteredFarmsV2 = (farmAddress?: string) => { } } -export const useFarmV2Action = (farmAddress: string) => { +export const useFarmV2Action = ( + farmAddress: string, +): { + approve: () => Promise + deposit: (fId: number, rangeId: number, nftIds: number[]) => Promise + updateLiquidity: (fId: number, rangeId: number, nftIds: number[]) => Promise + withdraw: (fId: number, nftIds: number[]) => Promise + harvest: (fId: number, nftIds: number[]) => Promise +} => { const { account } = useActiveWeb3React() const addTransactionWithType = useTransactionAdder() - const farmContract = useContract(farmAddress, FarmV2ABI) - const posManager = useProAmmNFTPositionManagerContract() + const farmContract = useSigningContract(farmAddress, FarmV2ABI) + const posManager = useProAmmNFTPositionManagerSigningContract() + const notify = useNotify() const approve = useCallback(async () => { if (!posManager) { throw new Error(CONTRACT_NOT_FOUND_MSG) } - const estimateGas = await posManager.estimateGas.setApprovalForAll(farmAddress, true) - const tx = await posManager.setApprovalForAll(farmAddress, true, { - gasLimit: calculateGasMargin(estimateGas), - }) - addTransactionWithType({ - hash: tx.hash, - type: TRANSACTION_TYPE.APPROVE, - extraInfo: { - summary: `Elastic Static Farm`, - contract: farmAddress, - }, - }) - return tx.hash - }, [posManager, farmAddress, addTransactionWithType]) + try { + const estimateGas = await posManager.estimateGas.setApprovalForAll(farmAddress, true) + const tx = await posManager.setApprovalForAll(farmAddress, true, { + gasLimit: calculateGasMargin(estimateGas), + }) + addTransactionWithType({ + hash: tx.hash, + type: TRANSACTION_TYPE.APPROVE, + extraInfo: { + summary: `Elastic Static Farm`, + contract: farmAddress, + }, + }) + return tx.hash + } catch (error) { + const message = friendlyError(error) + notify( + { + title: t`Approve Farm Error`, + summary: message, + type: NotificationType.ERROR, + }, + 8000, + ) + } + }, [posManager, farmAddress, addTransactionWithType, notify]) //Deposit const deposit = useCallback( @@ -247,8 +272,8 @@ export const useFarmV2Action = (farmAddress: string) => { type: TRANSACTION_TYPE.ELASTIC_DEPOSIT_LIQUIDITY, }) return tx.hash - } catch (e) { - throw e + } catch (error) { + throw error } }, [farmContract, addTransactionWithType, account], @@ -269,8 +294,8 @@ export const useFarmV2Action = (farmAddress: string) => { type: TRANSACTION_TYPE.ELASTIC_DEPOSIT_LIQUIDITY, }) return tx.hash - } catch (e) { - throw e + } catch (error) { + throw error } }, [addTransactionWithType, farmContract], @@ -292,8 +317,8 @@ export const useFarmV2Action = (farmAddress: string) => { type: TRANSACTION_TYPE.ELASTIC_WITHDRAW_LIQUIDITY, }) return tx.hash - } catch (e) { - throw e + } catch (error) { + throw error } }, [addTransactionWithType, farmContract], @@ -313,8 +338,8 @@ export const useFarmV2Action = (farmAddress: string) => { addTransactionWithType({ hash: tx.hash, type: TRANSACTION_TYPE.HARVEST }) return tx.hash - } catch (e) { - throw e + } catch (error) { + throw error } }, [addTransactionWithType, farmContract], diff --git a/src/state/farms/elasticv2/updater.tsx b/src/state/farms/elasticv2/updater.tsx index ecf7c923f7..61bacf0727 100644 --- a/src/state/farms/elasticv2/updater.tsx +++ b/src/state/farms/elasticv2/updater.tsx @@ -15,7 +15,7 @@ import { ETHER_ADDRESS, RTK_QUERY_TAGS, ZERO_ADDRESS } from 'constants/index' import { EVMNetworkInfo } from 'constants/networks/type' import { NativeCurrencies } from 'constants/tokens' import { useActiveWeb3React } from 'hooks' -import { useContract, useMulticallContract } from 'hooks/useContract' +import { useMulticallContract, useReadingContract } from 'hooks/useContract' import { useKyberSwapConfig } from 'state/application/hooks' import { useAppDispatch } from 'state/hooks' import { useTokenPricesWithLoading } from 'state/tokenPrices/hooks' @@ -109,7 +109,7 @@ export default function ElasticFarmV2Updater({ interval = true }: { interval?: b const { elasticClient, isEnableKNProtocol } = useKyberSwapConfig() const multicallContract = useMulticallContract() - const farmv2QuoterContract = useContract( + const farmv2QuoterContract = useReadingContract( isEVM ? (networkInfo as EVMNetworkInfo).elastic.farmv2Quoter : undefined, FarmV2QuoterABI, ) diff --git a/src/state/index.ts b/src/state/index.ts index 337177cb2d..863550aca7 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -1,6 +1,7 @@ import { configureStore } from '@reduxjs/toolkit' import { load, save } from 'redux-localstorage-simple' import announcementApi, { publicAnnouncementApi } from 'services/announcement' +import blackjackApi from 'services/blackjack' import blockServiceApi from 'services/blockService' import campaignApi from 'services/campaign' import coingeckoApi from 'services/coingecko' @@ -121,6 +122,7 @@ const store = configureStore({ [tokenApi.reducerPath]: tokenApi.reducer, [socialApi.reducerPath]: socialApi.reducer, [blockServiceApi.reducerPath]: blockServiceApi.reducer, + [blackjackApi.reducerPath]: blackjackApi.reducer, [knProtocolApi.reducerPath]: knProtocolApi.reducer, }, middleware: getDefaultMiddleware => @@ -144,6 +146,7 @@ const store = configureStore({ .concat(socialApi.middleware) .concat(tokenApi.middleware) .concat(blockServiceApi.middleware) + .concat(blackjackApi.middleware) .concat(knProtocolApi.middleware), preloadedState, }) diff --git a/src/utils/getContract.ts b/src/utils/getContract.ts index f937284a9d..29d0e92875 100644 --- a/src/utils/getContract.ts +++ b/src/utils/getContract.ts @@ -4,7 +4,6 @@ import { JsonRpcSigner, Web3Provider } from '@ethersproject/providers' import { ChainId } from '@kyberswap/ks-sdk-core' import { ethers } from 'ethers' -import CLAIM_REWARD_ABI from 'constants/abis/claim-reward.json' import ROUTER_DYNAMIC_FEE_ABI from 'constants/abis/dmm-router-dynamic-fee.json' import ROUTER_STATIC_FEE_ABI from 'constants/abis/dmm-router-static-fee.json' import KS_ROUTER_STATIC_FEE_ABI from 'constants/abis/ks-router-static-fee.json' @@ -24,7 +23,7 @@ function getProviderOrSigner(library: Web3Provider, account?: string): Web3Provi } // account is optional -export function getContract( +export function getSigningContract( address: string, ABI: ContractInterface, library: Web3Provider, @@ -37,7 +36,7 @@ export function getContract( return new Contract(address, ABI, getProviderOrSigner(library, account) as any) } -export function getContractForReading( +export function getReadingContract( address: string, ABI: ContractInterface, library: ethers.providers.JsonRpcProvider, @@ -51,7 +50,7 @@ export function getContractForReading( // account is optional export function getOldStaticFeeRouterContract(chainId: ChainId, library: Web3Provider, account?: string): Contract { - return getContract( + return getSigningContract( isEVM(chainId) ? NETWORKS_INFO[chainId].classic.oldStatic?.router ?? '' : '', ROUTER_STATIC_FEE_ABI, library, @@ -60,7 +59,7 @@ export function getOldStaticFeeRouterContract(chainId: ChainId, library: Web3Pro } // account is optional export function getStaticFeeRouterContract(chainId: ChainId, library: Web3Provider, account?: string): Contract { - return getContract( + return getSigningContract( isEVM(chainId) ? NETWORKS_INFO[chainId].classic.static.router : '', KS_ROUTER_STATIC_FEE_ABI, library, @@ -69,7 +68,7 @@ export function getStaticFeeRouterContract(chainId: ChainId, library: Web3Provid } // account is optional export function getDynamicFeeRouterContract(chainId: ChainId, library: Web3Provider, account?: string): Contract { - return getContract( + return getSigningContract( isEVM(chainId) ? NETWORKS_INFO[chainId].classic.dynamic?.router ?? '' : '', ROUTER_DYNAMIC_FEE_ABI, library, @@ -85,7 +84,7 @@ export function getZapContract( isStaticFeeContract?: boolean, isOldStaticFeeContract?: boolean, ): Contract { - return getContract( + return getSigningContract( isEVM(chainId) ? isStaticFeeContract ? isOldStaticFeeContract @@ -98,14 +97,3 @@ export function getZapContract( account, ) } - -export function getClaimRewardContract( - chainId: ChainId, - library: Web3Provider, - account?: string, -): Contract | undefined { - if (!isEVM(chainId)) return - const claimReward = NETWORKS_INFO[chainId].classic.claimReward - if (!claimReward) return - return getContract(claimReward, CLAIM_REWARD_ABI, library, account) -} diff --git a/src/utils/sendTransaction.ts b/src/utils/sendTransaction.ts index 971ab0c7dc..a94d051a73 100644 --- a/src/utils/sendTransaction.ts +++ b/src/utils/sendTransaction.ts @@ -33,7 +33,7 @@ export async function sendEVMTransaction({ } chainId?: ChainId }): Promise { - if (!account || !library) return + if (!account || !library) throw new Error('Invalid transaction') const estimateGasOption = { from: account,