diff --git a/src/contexts/TokenContext.tsx b/src/contexts/TokenContext.tsx
index 418826865..a9f91d647 100644
--- a/src/contexts/TokenContext.tsx
+++ b/src/contexts/TokenContext.tsx
@@ -1,5 +1,6 @@
-import React, { createContext, useEffect } from "react"
+import React, { createContext } from "react"
import { Contract } from "@ethersproject/contracts"
+import { AddressZero } from "@ethersproject/constants"
import { useWeb3React } from "@web3-react/core"
import { useKeep } from "../web3/hooks/useKeep"
import { useNu } from "../web3/hooks/useNu"
@@ -49,7 +50,7 @@ export const TokenContextProvider: React.FC = ({ children }) => {
const fetchBalances = useTokensBalanceCall(
[keep.contract!, nu.contract!, t.contract!],
- account!
+ active ? account! : AddressZero
)
//
diff --git a/src/hooks/__tests__/useFetchTvl.test.tsx b/src/hooks/__tests__/useFetchTvl.test.tsx
new file mode 100644
index 000000000..85f2e4b18
--- /dev/null
+++ b/src/hooks/__tests__/useFetchTvl.test.tsx
@@ -0,0 +1,219 @@
+import { renderHook } from "@testing-library/react-hooks"
+import * as ethersUnits from "@ethersproject/units"
+import { Token } from "../../enums"
+import {
+ useKeepAssetPoolContract,
+ useKeepBondingContract,
+ useKeepTokenStakingContract,
+ useMulticall,
+ useMulticallContract,
+ useTStakingContract,
+} from "../../web3/hooks"
+import { useETHData } from "../useETHData"
+import { useFetchTvl } from "../useFetchTvl"
+import * as useTokenModule from "../useToken"
+import { TokenContext } from "../../contexts/TokenContext"
+import * as usdUtils from "../../utils/getUsdBalance"
+
+jest.mock("../../web3/hooks", () => ({
+ ...(jest.requireActual("../../web3/hooks") as {}),
+ useKeepAssetPoolContract: jest.fn(),
+ useKeepBondingContract: jest.fn(),
+ useKeepTokenStakingContract: jest.fn(),
+ useMulticall: jest.fn(),
+ useMulticallContract: jest.fn(),
+ useTStakingContract: jest.fn(),
+}))
+
+jest.mock("../useETHData", () => ({
+ ...(jest.requireActual("../useETHData") as {}),
+ useETHData: jest.fn(),
+}))
+
+describe("Test `useFetchTvl` hook", () => {
+ const keepContext = {
+ contract: {} as any,
+ usdConversion: 1,
+ } as any
+ const tbtcContext = {
+ contract: {} as any,
+ usdConversion: 2,
+ } as any
+
+ const tContext = {
+ contract: {} as any,
+ usdConversion: 3,
+ } as any
+
+ const nuContext = {
+ contract: {} as any,
+ usdConversion: 4,
+ } as any
+
+ const mockedKeepTokenStakingContract = { address: "0x1" }
+ const mockedKeepBondingContract = { address: "0x0" }
+ const mockedTStakingContract = { address: "0x2" }
+ const mockedMultiCallContract = {}
+ const mockedKeepAssetPoolContract = {}
+
+ const wrapper = ({ children }) => (
+
+ {children}
+
+ )
+
+ const multicallRequest = jest.fn()
+ const mockedETHData = { usdPrice: 20 }
+
+ beforeEach(() => {
+ ;(useMulticall as jest.Mock).mockReturnValue(multicallRequest)
+ ;(useETHData as jest.Mock).mockReturnValue(mockedETHData)
+ ;(useKeepBondingContract as jest.Mock).mockReturnValue(
+ mockedKeepBondingContract
+ )
+ ;(useMulticallContract as jest.Mock).mockReturnValue(
+ mockedMultiCallContract
+ )
+ ;(useKeepAssetPoolContract as jest.Mock).mockReturnValue(
+ mockedKeepAssetPoolContract
+ )
+ ;(useTStakingContract as jest.Mock).mockReturnValue(mockedTStakingContract)
+ ;(useKeepTokenStakingContract as jest.Mock).mockReturnValue(
+ mockedKeepTokenStakingContract
+ )
+ })
+
+ test("should fetch tvl data correctly.", async () => {
+ // given
+ const ethInKeepBonding = { raw: "10000000000000000000", format: "10.0" }
+ const tbtcTokenTotalSupply = { raw: "5000000000000000000", format: "5.0" }
+ const coveragePoolTvl = { raw: "300000000000000000000", format: "300.0" }
+ const keepStaking = { raw: "500000000000000000000", format: "500.0" }
+ const tStaking = { raw: "600000000000000000000", format: "600.0" }
+
+ const multicallRequestResult = [
+ ethInKeepBonding.raw,
+ tbtcTokenTotalSupply.raw,
+ coveragePoolTvl.raw,
+ keepStaking.raw,
+ tStaking.raw,
+ ]
+
+ multicallRequest.mockResolvedValue(multicallRequestResult)
+
+ const spyOnFormatUnits = jest.spyOn(ethersUnits, "formatUnits")
+ const spyOnToUsdBalance = jest.spyOn(usdUtils, "toUsdBalance")
+ const spyOnUseToken = jest.spyOn(useTokenModule, "useToken")
+
+ const _expectedResult = {
+ ecdsa: ethInKeepBonding.format * mockedETHData.usdPrice,
+ tbtc: tbtcTokenTotalSupply.format * tbtcContext.usdConversion,
+ keepCoveragePool: coveragePoolTvl.format * keepContext.usdConversion,
+ keepStaking: keepStaking.format * keepContext.usdConversion,
+ tStaking: tStaking.format * tContext.usdConversion,
+ }
+
+ // `FixedNumber` from `@ethersproject/bignumber` adds trailing zero so we
+ // need to do the same here.
+ const expectedResult = {
+ ecdsa: `${_expectedResult.ecdsa.toString()}.0`,
+ tbtc: `${_expectedResult.tbtc.toString()}.0`,
+ keepCoveragePool: `${_expectedResult.keepCoveragePool.toString()}.0`,
+ keepStaking: `${_expectedResult.keepStaking.toString()}.0`,
+ tStaking: `${_expectedResult.tStaking.toString()}.0`,
+ total: `${
+ _expectedResult.ecdsa +
+ _expectedResult.tbtc +
+ _expectedResult.keepCoveragePool +
+ _expectedResult.keepStaking +
+ _expectedResult.tStaking
+ }.0`,
+ }
+
+ // when
+ const { result, waitForNextUpdate } = renderHook(() => useFetchTvl(), {
+ wrapper,
+ })
+
+ // then
+ expect(useETHData).toHaveBeenCalled()
+ expect(spyOnUseToken).toHaveBeenCalledWith(Token.Keep)
+ expect(spyOnUseToken).toHaveBeenCalledWith(Token.TBTC)
+ expect(spyOnUseToken).toHaveBeenCalledWith(Token.T)
+ expect(useKeepBondingContract).toHaveBeenCalled()
+ expect(useMulticallContract).toHaveBeenCalled()
+ expect(useKeepAssetPoolContract).toHaveBeenCalled()
+ expect(useTStakingContract).toHaveBeenCalled()
+ expect(useKeepTokenStakingContract).toHaveBeenCalled()
+ expect(useMulticall).toHaveBeenCalledWith([
+ {
+ contract: mockedMultiCallContract,
+ method: "getEthBalance",
+ args: [mockedKeepBondingContract.address],
+ },
+ {
+ contract: tbtcContext.contract,
+ method: "totalSupply",
+ },
+ { contract: mockedKeepAssetPoolContract, method: "totalValue" },
+ {
+ contract: keepContext.contract,
+ method: "balanceOf",
+ args: [mockedKeepTokenStakingContract.address],
+ },
+ {
+ contract: tContext.contract,
+ method: "balanceOf",
+ args: [mockedTStakingContract.address],
+ },
+ ])
+
+ result.current[1]()
+
+ await waitForNextUpdate()
+
+ expect(multicallRequest).toHaveBeenCalled()
+ expect(spyOnFormatUnits).toHaveBeenCalledTimes(
+ multicallRequestResult.length
+ )
+ // The `toUsdBalance` function was called 2x times because it was called
+ // first on mount for every value and then after fetching on-chain data.
+ expect(spyOnToUsdBalance).toHaveBeenCalledTimes(
+ multicallRequestResult.length * 2
+ )
+ expect(spyOnToUsdBalance).toHaveBeenNthCalledWith(
+ 6,
+ ethInKeepBonding.format,
+ mockedETHData.usdPrice
+ )
+ expect(spyOnToUsdBalance).toHaveBeenNthCalledWith(
+ 7,
+ tbtcTokenTotalSupply.format,
+ tbtcContext.usdConversion
+ )
+ expect(spyOnToUsdBalance).toHaveBeenNthCalledWith(
+ 8,
+ coveragePoolTvl.format,
+ keepContext.usdConversion
+ )
+ expect(spyOnToUsdBalance).toHaveBeenNthCalledWith(
+ 9,
+ keepStaking.format,
+ keepContext.usdConversion
+ )
+ expect(spyOnToUsdBalance).toHaveBeenNthCalledWith(
+ 10,
+ tStaking.format,
+ tContext.usdConversion
+ )
+
+ expect(result.current[0]).toEqual(expectedResult)
+ })
+})
diff --git a/src/hooks/useFetchTvl.ts b/src/hooks/useFetchTvl.ts
index c5a69fb3d..02976acd7 100644
--- a/src/hooks/useFetchTvl.ts
+++ b/src/hooks/useFetchTvl.ts
@@ -6,41 +6,59 @@ import {
useMulticall,
useMulticallContract,
useKeepAssetPoolContract,
+ useTStakingContract,
+ useKeepTokenStakingContract,
} from "../web3/hooks"
import { useETHData } from "./useETHData"
import { useToken } from "./useToken"
import { Token } from "../enums"
+import { toUsdBalance } from "../utils/getUsdBalance"
interface TVLRawData {
ecdsaTVL: string
tbtcTVL: string
keepCoveragePoolTVL: string
- // TODO: add PRE
+ keepStakingTVL: string
+ tStakingTVL: string
+ // TODO: add PRE and NU TVL
+}
+
+interface TVLData {
+ ecdsa: string
+ tbtc: string
+ keepCoveragePool: string
+ keepStaking: string
+ tStaking: string
+ total: string
}
const initialState = {
ecdsaTVL: "0",
tbtcTVL: "0",
keepCoveragePoolTVL: "0",
+ keepStakingTVL: "0",
+ tStakingTVL: "0",
}
-export const useFetchTvl = (): [
- {
- ecdsa: string
- tbtc: string
- keepCoveragePool: string
- total: string
- },
- () => Promise
-] => {
+export const useFetchTvl = (): [TVLData, () => Promise] => {
const [rawData, setRawData] = useState(initialState)
- const { ecdsaTVL, tbtcTVL, keepCoveragePoolTVL } = rawData
+ const {
+ ecdsaTVL,
+ tbtcTVL,
+ keepCoveragePoolTVL,
+ keepStakingTVL,
+ tStakingTVL,
+ } = rawData
+
const eth = useETHData()
const keep = useToken(Token.Keep)
const tbtc = useToken(Token.TBTC)
+ const t = useToken(Token.T)
const keepBonding = useKeepBondingContract()
const multicall = useMulticallContract()
const keepAssetPool = useKeepAssetPoolContract()
+ const tTokenStaking = useTStakingContract()
+ const keepTokenStaking = useKeepTokenStakingContract()
const fetchOnChainData = useMulticall([
{
@@ -53,19 +71,36 @@ export const useFetchTvl = (): [
method: "totalSupply",
},
{ contract: keepAssetPool!, method: "totalValue" },
+ {
+ contract: keep.contract!,
+ method: "balanceOf",
+ args: [keepTokenStaking?.address],
+ },
+ {
+ contract: t.contract!,
+ method: "balanceOf",
+ args: [tTokenStaking?.address],
+ },
])
const fetchTVLData = useCallback(async () => {
const chainData = await fetchOnChainData()
if (chainData.length === 0) return initialState
- const [ethInKeepBonding, tbtcTokenTotalSupply, coveragePoolTvl] =
- chainData.map((amount: string) => formatUnits(amount.toString()))
+ const [
+ ethInKeepBonding,
+ tbtcTokenTotalSupply,
+ coveragePoolTvl,
+ keepStaking,
+ tStaking,
+ ] = chainData.map((amount: string) => formatUnits(amount.toString()))
- const data = {
+ const data: TVLRawData = {
ecdsaTVL: ethInKeepBonding,
tbtcTVL: tbtcTokenTotalSupply,
keepCoveragePoolTVL: coveragePoolTvl,
+ keepStakingTVL: keepStaking,
+ tStakingTVL: tStaking,
}
setRawData(data)
@@ -73,31 +108,42 @@ export const useFetchTvl = (): [
}, [fetchOnChainData])
const data = useMemo(() => {
- const ecdsa = FixedNumber.fromString(ecdsaTVL).mulUnsafe(
- FixedNumber.fromString(eth.usdPrice.toString())
- )
+ const ecdsa = toUsdBalance(ecdsaTVL, eth.usdPrice)
- const tbtcUSD = FixedNumber.fromString(tbtcTVL).mulUnsafe(
- FixedNumber.fromString(tbtc.usdConversion.toString())
+ const tbtcUSD = toUsdBalance(tbtcTVL, tbtc.usdConversion)
+
+ const keepCoveragePool = toUsdBalance(
+ keepCoveragePoolTVL,
+ keep.usdConversion
)
- const keepCoveragePool = FixedNumber.fromString(
- keepCoveragePoolTVL
- ).mulUnsafe(FixedNumber.fromString(keep.usdConversion.toString()))
+ const keepStaking = toUsdBalance(keepStakingTVL, keep.usdConversion)
+
+ const tStaking = toUsdBalance(tStakingTVL, t.usdConversion)
return {
ecdsa: ecdsa.toString(),
tbtc: tbtcUSD.toString(),
keepCoveragePool: keepCoveragePool.toString(),
- total: ecdsa.addUnsafe(tbtcUSD).addUnsafe(keepCoveragePool).toString(),
- }
+ keepStaking: keepStaking.toString(),
+ tStaking: tStaking.toString(),
+ total: ecdsa
+ .addUnsafe(tbtcUSD)
+ .addUnsafe(keepCoveragePool)
+ .addUnsafe(keepStaking)
+ .addUnsafe(tStaking)
+ .toString(),
+ } as TVLData
}, [
ecdsaTVL,
keepCoveragePoolTVL,
tbtcTVL,
+ keepStakingTVL,
+ tStakingTVL,
eth.usdPrice,
keep.usdConversion,
tbtc.usdConversion,
+ t.usdConversion,
])
return [data, fetchTVLData]
diff --git a/src/hooks/useTokenBalance.ts b/src/hooks/useTokenBalance.ts
index ebb61bfce..d4a4efdef 100644
--- a/src/hooks/useTokenBalance.ts
+++ b/src/hooks/useTokenBalance.ts
@@ -1,19 +1,9 @@
import { useMemo } from "react"
import { Token } from "../enums/token"
-import { useTokenState } from "./useTokenState"
+import { useToken } from "./useToken"
export const useTokenBalance = (token: Token) => {
- const tokenMap = {
- [Token.T]: "t",
- [Token.Nu]: "nu",
- [Token.Keep]: "keep",
- [Token.TBTC]: "tbtc",
- }
-
- const tokenState = useTokenState()
-
- // @ts-ignore
- const _token = tokenState[tokenMap[token]]
+ const _token = useToken(token)
return useMemo(() => _token.balance, [_token.balance])
}
diff --git a/src/pages/Overview/Network/TotalValueLocked.tsx b/src/pages/Overview/Network/TotalValueLocked.tsx
index 8ac772521..8395d393c 100644
--- a/src/pages/Overview/Network/TotalValueLocked.tsx
+++ b/src/pages/Overview/Network/TotalValueLocked.tsx
@@ -3,23 +3,17 @@ import { Flex } from "@chakra-ui/react"
import CardTemplate from "./CardTemplate"
import { H1 } from "../../../components/Typography"
import { formatFiatCurrencyAmount } from "../../../utils/formatAmount"
-import { useWeb3React } from "@web3-react/core"
const TotalValueLocked: FC<{ totalValueLocked: number | string }> = ({
totalValueLocked,
}) => {
const tvl = formatFiatCurrencyAmount(totalValueLocked)
- const { account } = useWeb3React()
- /* TODO: This is a hack - we need a way to load on-chain data without a connected wallet */
return (
-
- {account ? tvl : "Please connect your wallet"}
+
+ {tvl}
diff --git a/src/utils/getUsdBalance.tsx b/src/utils/getUsdBalance.ts
similarity index 52%
rename from src/utils/getUsdBalance.tsx
rename to src/utils/getUsdBalance.ts
index c8b4a485b..e791828b3 100644
--- a/src/utils/getUsdBalance.tsx
+++ b/src/utils/getUsdBalance.ts
@@ -7,9 +7,16 @@ const getUsdBalance = (
usdConversion: number
): string => {
return formatFiatCurrencyAmount(
- FixedNumber.fromString(usdConversion.toString())
- .mulUnsafe(FixedNumber.fromString(formatUnits(balance)))
- .toString()
+ toUsdBalance(formatUnits(balance), usdConversion).toString()
+ )
+}
+
+export const toUsdBalance = (
+ balance: string | number,
+ usdConversion: number
+): FixedNumber => {
+ return FixedNumber.fromString(usdConversion.toString()).mulUnsafe(
+ FixedNumber.fromString(balance.toString())
)
}
diff --git a/src/web3/hooks/__tests__/useContract.test.ts b/src/web3/hooks/__tests__/useContract.test.ts
index e9d37d25f..41e202d44 100644
--- a/src/web3/hooks/__tests__/useContract.test.ts
+++ b/src/web3/hooks/__tests__/useContract.test.ts
@@ -1,22 +1,38 @@
import { renderHook } from "@testing-library/react-hooks"
import { useWeb3React } from "@web3-react/core"
+import { JsonRpcProvider } from "@ethersproject/providers"
import { useContract } from "../useContract"
import { getContract } from "../../../utils/getContract"
+import { getEnvVariable } from "../../../utils/getEnvVariable"
+import { EnvVariable } from "../../../enums"
jest.mock("../../../utils/getContract", () => ({
...(jest.requireActual("../../../utils/getContract") as {}),
getContract: jest.fn(() => {}),
}))
+jest.mock("../../../utils/getEnvVariable", () => ({
+ ...(jest.requireActual("../../../utils/getEnvVariable") as {}),
+ getEnvVariable: jest.fn(),
+}))
+
jest.mock("@web3-react/core", () => ({
...(jest.requireActual("@web3-react/core") as {}),
useWeb3React: jest.fn(),
}))
+jest.mock("@ethersproject/providers", () => ({
+ ...(jest.requireActual("@ethersproject/providers") as {}),
+ JsonRpcProvider: jest.fn(),
+}))
+
describe("Test the `useContract` hook", () => {
const address = "0x3aA3D0Bb15FAdDB154141c92DAaaA9022b2A346d"
const abi = ["function balanceOf(address owner) view returns (uint256)"]
const mockedLibrary = {}
+ const mockedJsonRpcProvider = {}
+ const mockedEthNodeUrl = "http://localhost:8545"
+ const mockedContract = {}
describe("when web3 react context is not active", () => {
beforeEach(() => {
@@ -24,6 +40,9 @@ describe("Test the `useContract` hook", () => {
chainId: null,
library: null,
})
+ // @ts-ignore
+ ;(JsonRpcProvider as jest.Mock).mockReturnValue(mockedJsonRpcProvider)
+ ;(getEnvVariable as jest.Mock).mockReturnValue(mockedEthNodeUrl)
})
test("should not create a contract instance if an address is not defined", () => {
@@ -38,20 +57,24 @@ describe("Test the `useContract` hook", () => {
expect(result.current).toBeNull()
})
- test("should not create a contract instance if web3 react provider is not active", () => {
+ test("should create a contract instance with a default provider if web3 react provider is not active", () => {
+ ;(getContract as jest.Mock).mockReturnValue(mockedContract)
+
const { result } = renderHook(() => useContract(address, abi))
- expect(result.current).toBeNull()
+ expect(getEnvVariable).toHaveBeenCalledWith(EnvVariable.ETH_HOSTNAME_HTTP)
+ expect(JsonRpcProvider).toHaveBeenCalledWith(mockedEthNodeUrl)
+ expect(result.current).toEqual(mockedContract)
})
})
describe("when web3 context provider is active", () => {
- const mockedContract = {}
const account = "0x086813525A7dC7dafFf015Cdf03896Fd276eab60"
beforeEach(() => {
;(useWeb3React as jest.Mock).mockReturnValue({
account,
+ active: true,
chainId: 1,
library: mockedLibrary,
})
diff --git a/src/web3/hooks/__tests__/useSendTransaction.test.ts b/src/web3/hooks/__tests__/useSendTransaction.test.ts
index 5108210d0..e77b5b221 100644
--- a/src/web3/hooks/__tests__/useSendTransaction.test.ts
+++ b/src/web3/hooks/__tests__/useSendTransaction.test.ts
@@ -46,6 +46,9 @@ describe("Test `useSendTransaction` hook", () => {
const userRejectedErrMsg =
"MetaMask Tx Signature: User denied transaction signature."
+ const mockedOnSuccessCallback = jest.fn()
+ const mockedOnErroCallback = jest.fn()
+
beforeEach(() => {
;(useWeb3React as jest.Mock).mockReturnValue({
chainId: 1,
@@ -84,6 +87,21 @@ describe("Test `useSendTransaction` hook", () => {
)
})
+ test("should proceed the transaction correctly and call custom on success callback", async () => {
+ mockedContract[methodName].mockResolvedValue(mockedTx)
+
+ const { result, waitForNextUpdate } = renderHook(() =>
+ useSendTransaction(mockedContract, methodName, mockedOnSuccessCallback)
+ )
+
+ expect(result.current.status).toEqual(TransactionStatus.Idle)
+
+ result.current.sendTransaction(from, value)
+ await waitForNextUpdate()
+
+ expect(mockedOnSuccessCallback).toHaveBeenCalledWith(mockedTx)
+ })
+
test("should do nothing if there is no signer", async () => {
;(useWeb3React as jest.Mock).mockReturnValue({
chainId: 1,
@@ -130,6 +148,30 @@ describe("Test `useSendTransaction` hook", () => {
expect(mockedOpenModalFn).not.toHaveBeenCalled()
})
+ test("should call a custom error callback", async () => {
+ const error = new Error()
+ mockedContract[methodName].mockRejectedValue(error)
+
+ const { result, waitForNextUpdate } = renderHook(() =>
+ useSendTransaction(
+ mockedContract,
+ methodName,
+ mockedOnSuccessCallback,
+ mockedOnErroCallback
+ )
+ )
+
+ expect(result.current.status).toEqual(TransactionStatus.Idle)
+
+ result.current.sendTransaction(from, value)
+ await waitForNextUpdate()
+ expect(mockedOnSuccessCallback).not.toHaveBeenCalled()
+ expect(mockedOnErroCallback).toHaveBeenCalledWith(error)
+ expect(mockedOpenModalFn).not.toHaveBeenCalledWith(
+ ModalType.TransactionFailed
+ )
+ })
+
test.each`
errorMsg | expectedStatus
${"Unexpected error"} | ${TransactionStatus.Failed}
@@ -156,7 +198,7 @@ describe("Test `useSendTransaction` hook", () => {
expect(result.current.status).toEqual(expectedStatus)
expect(mockedOpenModalFn).toHaveBeenCalledWith(
ModalType.TransactionFailed,
- { error, transactionHash: undefined }
+ { error, transactionHash: undefined, isExpandableError: true }
)
}
)
diff --git a/src/web3/hooks/__tests__/useSubscribeToContractEvent.test.ts b/src/web3/hooks/__tests__/useSubscribeToContractEvent.test.ts
index ab78a30ad..1e683f1b7 100644
--- a/src/web3/hooks/__tests__/useSubscribeToContractEvent.test.ts
+++ b/src/web3/hooks/__tests__/useSubscribeToContractEvent.test.ts
@@ -1,7 +1,13 @@
import { act, renderHook } from "@testing-library/react-hooks"
+import { useWeb3React } from "@web3-react/core"
import { useSubscribeToContractEvent } from "../useSubscribeToContractEvent"
import { EventEmitter } from "events"
+jest.mock("@web3-react/core", () => ({
+ ...(jest.requireActual("@web3-react/core") as {}),
+ useWeb3React: jest.fn(),
+}))
+
describe("Test `useSubscribeToContractEvent` hook", () => {
const eventName = "Transfer"
const from = "0x407C3329eA8f6BEFB984D97AE4Fa71945E43170b"
@@ -27,6 +33,10 @@ describe("Test `useSubscribeToContractEvent` hook", () => {
}
beforeEach(() => {
+ ;(useWeb3React as jest.Mock).mockReturnValue({
+ active: true,
+ })
+
// Clear listeners
contractEventEmitter.removeAllListeners()
providerEventEmitter.removeAllListeners()
@@ -59,6 +69,23 @@ describe("Test `useSubscribeToContractEvent` hook", () => {
expect(mockedContract.provider.off).not.toHaveBeenCalled()
})
+ test("should do nothing if a user is not connected to a wallet", () => {
+ ;(useWeb3React as jest.Mock).mockReturnValue({
+ active: false,
+ })
+
+ const { unmount } = renderHook(() =>
+ useSubscribeToContractEvent(mockedContract, eventName, mockedCallback)
+ )
+
+ expect(mockedCallback).not.toHaveBeenCalled()
+ expect(mockedContract.on).not.toHaveBeenCalled()
+ expect(mockedContract.provider.once).not.toHaveBeenCalled()
+ unmount()
+ expect(mockedContract.off).not.toHaveBeenCalled()
+ expect(mockedContract.provider.off).not.toHaveBeenCalled()
+ })
+
test("should off subscription correctly", () => {
const { unmount } = renderHook(() =>
useSubscribeToContractEvent(mockedContract, eventName, mockedCallback)
diff --git a/src/web3/hooks/__tests__/useSubscribeToERC20TransferEvent.test.ts b/src/web3/hooks/__tests__/useSubscribeToERC20TransferEvent.test.ts
index 21bb88b70..48daab228 100644
--- a/src/web3/hooks/__tests__/useSubscribeToERC20TransferEvent.test.ts
+++ b/src/web3/hooks/__tests__/useSubscribeToERC20TransferEvent.test.ts
@@ -6,7 +6,7 @@ import { EventEmitter } from "events"
import { Token } from "../../../enums"
import { useToken } from "../../../hooks/useToken"
import { useTokenBalance } from "../../../hooks/useTokenBalance"
-import { useReduxToken } from "../../../hooks/useReduxToken"
+import { useTokenState } from "../../../hooks/useTokenState"
jest.mock("@web3-react/core", () => ({
...(jest.requireActual("@web3-react/core") as {}),
@@ -21,8 +21,8 @@ jest.mock("../../../hooks/useTokenBalance", () => ({
useTokenBalance: jest.fn(),
}))
-jest.mock("../../../hooks/useReduxToken", () => ({
- useReduxToken: jest.fn(),
+jest.mock("../../../hooks/useTokenState", () => ({
+ useTokenState: jest.fn(),
}))
describe("Test `useSubscribeToERC20TransferEvent` hook", () => {
@@ -67,10 +67,10 @@ describe("Test `useSubscribeToERC20TransferEvent` hook", () => {
mockedContract.on.mockImplementation((eventName, callback) => {
contractEventEmitter.addListener(eventName, callback)
})
- ;(useWeb3React as jest.Mock).mockReturnValue({ account })
+ ;(useWeb3React as jest.Mock).mockReturnValue({ account, active: true })
;(useToken as jest.Mock).mockReturnValue({ contract: mockedContract })
;(useTokenBalance as jest.Mock).mockReturnValue(currentTokenBalance)
- ;(useReduxToken as jest.Mock).mockReturnValue({
+ ;(useTokenState as jest.Mock).mockReturnValue({
setTokenBalance: mockedSetTokenBalance,
})
})
diff --git a/src/web3/hooks/index.ts b/src/web3/hooks/index.ts
index 2ae98a97c..5ad9fac94 100644
--- a/src/web3/hooks/index.ts
+++ b/src/web3/hooks/index.ts
@@ -15,3 +15,4 @@ export * from "./useKeepBondingContract"
export * from "./useAssetPoolContract"
export * from "./useTBTCTokenContract"
export * from "./useTStakingContract"
+export * from "./useKeepTokenStakingContract"
diff --git a/src/web3/hooks/useContract.ts b/src/web3/hooks/useContract.ts
index b13cb58ee..2ce6015e9 100644
--- a/src/web3/hooks/useContract.ts
+++ b/src/web3/hooks/useContract.ts
@@ -1,24 +1,29 @@
import { useMemo } from "react"
-import { Contract } from "@ethersproject/contracts"
import { useWeb3React } from "@web3-react/core"
+import { Contract } from "@ethersproject/contracts"
+import { JsonRpcProvider } from "@ethersproject/providers"
+import { getEnvVariable } from "../../utils/getEnvVariable"
import { getContract } from "../../utils/getContract"
+import { EnvVariable } from "../../enums"
export function useContract(
address: string,
ABI: any,
withSignerIfPossible = true
): T | null {
- const { library, account, chainId } = useWeb3React()
+ const { library, account, chainId, active } = useWeb3React()
return useMemo(() => {
- if (!address || !ABI || !library || !chainId) {
+ if (!address || !ABI) {
return null
}
return getContract(
address,
ABI,
- library,
+ active
+ ? library
+ : new JsonRpcProvider(getEnvVariable(EnvVariable.ETH_HOSTNAME_HTTP)),
withSignerIfPossible && account ? account : undefined
)
}, [address, ABI, library, chainId, withSignerIfPossible, account]) as T
diff --git a/src/web3/hooks/useKeepTokenStakingContract.ts b/src/web3/hooks/useKeepTokenStakingContract.ts
new file mode 100644
index 000000000..0ddff5e16
--- /dev/null
+++ b/src/web3/hooks/useKeepTokenStakingContract.ts
@@ -0,0 +1,10 @@
+import KeepTokenStaking from "@keep-network/keep-core/artifacts/TokenStaking.json"
+import { useContract } from "./useContract"
+import { getContractAddressFromTruffleArtifact } from "../../utils/getContract"
+
+const KEEP_TOKEN_STAKING_ADDRESS =
+ getContractAddressFromTruffleArtifact(KeepTokenStaking)
+
+export const useKeepTokenStakingContract = () => {
+ return useContract(KEEP_TOKEN_STAKING_ADDRESS, KeepTokenStaking.abi)
+}
diff --git a/src/web3/hooks/useSubscribeToContractEvent.ts b/src/web3/hooks/useSubscribeToContractEvent.ts
index a3501945c..8a2fb57a6 100644
--- a/src/web3/hooks/useSubscribeToContractEvent.ts
+++ b/src/web3/hooks/useSubscribeToContractEvent.ts
@@ -1,5 +1,6 @@
import { useEffect, useRef } from "react"
import { Contract, EventFilter } from "@ethersproject/contracts"
+import { useWeb3React } from "@web3-react/core"
// TODO: types
export const useSubscribeToContractEvent = (
@@ -12,6 +13,7 @@ export const useSubscribeToContractEvent = (
// by `to` param we need to pass `[null, ]`.
indexedFilterParams: string[] = []
) => {
+ const { active } = useWeb3React()
const callbackRef = useRef<(args: any[]) => void>()
const indexedFilterParamsLength = indexedFilterParams.length
// An event can have up to 3 indexed params. We want to extract these values
@@ -29,7 +31,7 @@ export const useSubscribeToContractEvent = (
}, [callback])
useEffect(() => {
- if (!contract) {
+ if (!contract || !active) {
return
}